Ejemplo n.º 1
0
        private bool CheckSigner(
            Transaction <NCAction> transaction,
            BlockChain <NCAction> blockChain
            )
        {
            try
            {
                // Check if it is a no-op transaction to prove it's made by the authorized miner.
                if (blockChain.GetState(AuthorizedMinersState.Address) is Dictionary rawAms &&
                    new AuthorizedMinersState(rawAms).Miners.Contains(transaction.Signer))
                {
                    // The authorization proof has to have no actions at all.
                    return(!transaction.Actions.Any());
                }

                if (transaction.Actions.Count == 1 &&
                    transaction.Actions.First().InnerAction is ActivateAccount aa)
                {
                    return(blockChain.GetState(aa.PendingAddress) is Dictionary rawPending &&
                           new PendingActivationState(rawPending).Verify(aa));
                }

                if (blockChain.GetState(ActivatedAccountsState.Address) is Dictionary asDict)
                {
                    IImmutableSet <Address> activatedAccounts =
                        new ActivatedAccountsState(asDict).Accounts;
                    return(!activatedAccounts.Any() ||
                           activatedAccounts.Contains(transaction.Signer));
                }
                else
                {
                    return(true);
                }
            }
            catch (InvalidSignatureException)
            {
                return(false);
            }
            catch (IncompleteBlockStatesException)
            {
                // It can be caused during `Swarm<T>.PreloadAsync()` because it doesn't fill its
                // state right away...
                // FIXME It should be removed after fix that Libplanet fills its state on IBD.
                // See also: https://github.com/planetarium/lib9c/pull/151#discussion_r506039478
                return(true);
            }
        }
Ejemplo n.º 2
0
        internal static TxPolicyViolationException ValidateNextBlockTxRaw(
            BlockChain <NCAction> blockChain,
            Transaction <NCAction> transaction,
            ImmutableHashSet <Address> allAuthorizedMiners)
        {
            // Avoid NRE when genesis block appended
            // Here, index is the index of a prospective block that transaction
            // will be included.
            long index = blockChain.Count > 0 ? blockChain.Tip.Index : 0;

            if (transaction.Actions.Count > 1)
            {
                return(new TxPolicyViolationException(
                           transaction.Id,
                           $"Transaction {transaction.Id} has too many actions: " +
                           $"{transaction.Actions.Count}"));
            }
            else if (IsObsolete(transaction, index))
            {
                return(new TxPolicyViolationException(
                           transaction.Id,
                           $"Transaction {transaction.Id} is obsolete."));
            }

            try
            {
                // Check if it is a no-op transaction to prove it's made by the authorized miner.
                if (IsAuthorizedMinerTransactionRaw(transaction, allAuthorizedMiners))
                {
                    // FIXME: This works under a strong assumption that any miner that was ever
                    // in a set of authorized miners can only create transactions without
                    // any actions.
                    return(transaction.Actions.Any()
                        ? new TxPolicyViolationException(
                               transaction.Id,
                               $"Transaction {transaction.Id} by an authorized miner should not " +
                               $"have any action: {transaction.Actions.Count}")
                        : null);
                }

                // Check ActivateAccount
                if (transaction.Actions.Count == 1 &&
                    transaction.Actions.First().InnerAction is IActivateAction aa)
                {
                    return(blockChain.GetState(aa.GetPendingAddress()) is Dictionary rawPending &&
                           new PendingActivationState(rawPending).Verify(aa.GetSignature())
                        ? null
                        : new TxPolicyViolationException(
                               transaction.Id,
                               $"Transaction {transaction.Id} has an invalid activate action."));
                }

                // Check admin
                if (IsAdminTransaction(blockChain, transaction))
                {
                    return(null);
                }

                switch (blockChain.GetState(transaction.Signer.Derive(ActivationKey.DeriveKey)))
                {
                case null:
                    // Fallback for pre-migration.
                    if (blockChain.GetState(ActivatedAccountsState.Address)
                        is Dictionary asDict)
                    {
                        IImmutableSet <Address> activatedAccounts =
                            new ActivatedAccountsState(asDict).Accounts;
                        return(!activatedAccounts.Any() ||
                               activatedAccounts.Contains(transaction.Signer)
                                ? null
                                : new TxPolicyViolationException(
                                   transaction.Id,
                                   $"Transaction {transaction.Id} is by a signer " +
                                   $"without account activation: {transaction.Signer}"));
                    }
                    return(null);

                case Bencodex.Types.Boolean _:
                    return(null);
                }

                return(null);
            }
            catch (InvalidSignatureException)
            {
                return(new TxPolicyViolationException(
                           transaction.Id,
                           $"Transaction {transaction.Id} has invalid signautre."));
            }
            catch (IncompleteBlockStatesException)
            {
                // It can be caused during `Swarm<T>.PreloadAsync()` because it doesn't fill its
                // state right away...
                // FIXME: It should be removed after fix that Libplanet fills its state on IBD.
                // See also: https://github.com/planetarium/lib9c/pull/151#discussion_r506039478
                return(null);
            }

            return(null);
        }