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); } }
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); }