internal ActionEvaluation EvaluateBlockAction( Block <T> block, IReadOnlyList <ActionEvaluation> txActionEvaluations) { if (Policy.BlockAction is null) { var message = "To evaluate block action, Policy.BlockAction must not be null."; throw new InvalidOperationException(message); } IAccountStateDelta lastStates = null; if (!(txActionEvaluations is null) && txActionEvaluations.Count > 0) { lastStates = txActionEvaluations[txActionEvaluations.Count - 1].OutputStates; } Address miner = block.Miner.GetValueOrDefault(); if (lastStates is null) { lastStates = new AccountStateDeltaImpl( a => GetStates(new[] { a }, block.PreviousHash).GetValueOrDefault(a)); } return(ActionEvaluation.EvaluateActionsGradually( block.Hash, block.Index, null, lastStates, miner, miner, Array.Empty <byte>(), new[] { Policy.BlockAction }.ToImmutableList()).First()); }
IEnumerable <Tuple <Transaction <T>, ActionEvaluation> > EvaluateActionsPerTx( AccountStateGetter accountStateGetter = null, AccountBalanceGetter accountBalanceGetter = null ) { accountStateGetter ??= a => null; accountBalanceGetter ??= (a, c) => 0; IAccountStateDelta delta; foreach (Transaction <T> tx in Transactions) { delta = new AccountStateDeltaImpl( accountStateGetter, accountBalanceGetter, tx.Signer ); IEnumerable <ActionEvaluation> evaluations = tx.EvaluateActionsGradually( Hash, Index, delta, Miner.Value); foreach (var evaluation in evaluations) { yield return(Tuple.Create(tx, evaluation)); delta = evaluation.OutputStates; } accountStateGetter = delta.GetState; accountBalanceGetter = delta.GetBalance; } }
EvaluateActionsPerTx(AccountStateGetter accountStateGetter = null) { IAccountStateDelta delta = new AccountStateDeltaImpl( accountStateGetter ?? (a => null) ); foreach (Transaction <T> tx in Transactions) { IEnumerable <ActionEvaluation> evaluations = tx.EvaluateActionsGradually( Hash, Index, delta, Miner.Value); foreach (var evaluation in evaluations) { yield return(Tuple.Create(tx, evaluation)); delta = evaluation.OutputStates; } delta = new AccountStateDeltaImpl(delta.GetState); } }
public void CreateNullDelta() { IAccountStateDelta delta = new AccountStateDeltaImpl(GetState); Assert.Empty(delta.UpdatedAddresses); Assert.Equal("a", delta.GetState(_addr[0])); Assert.Equal("b", delta.GetState(_addr[1])); Assert.Null(delta.GetState(_addr[2])); }
internal ActionEvaluation EvaluateBlockAction( Block <T> block, IReadOnlyList <ActionEvaluation> txActionEvaluations, StateCompleterSet <T> stateCompleters ) { if (block == null) { throw new ArgumentNullException(nameof(block)); } if (_blockAction is null) { var message = "To evaluate block action, Policy.BlockAction must not be null."; throw new InvalidOperationException(message); } _logger.Debug( "Evaluating block action in block {blockIndex}: {block}", block?.Index, block); IAccountStateDelta?lastStates = null; if (!(txActionEvaluations is null) && txActionEvaluations.Count > 0) { lastStates = txActionEvaluations[txActionEvaluations.Count - 1].OutputStates; } Address miner = block !.Miner.GetValueOrDefault(); if (lastStates is null) { lastStates = new AccountStateDeltaImpl( a => _stateGetter(a, block.PreviousHash, stateCompleters.StateCompleter), (address, currency) => _balanceGetter( address, currency, block.PreviousHash, stateCompleters.FungibleAssetStateCompleter ), miner ); } return(ActionEvaluation.EvaluateActionsGradually( block.PreEvaluationHash, block.Index, null, lastStates, miner, miner, Array.Empty <byte>(), new[] { _blockAction }.ToImmutableList()).First()); }
public IEnumerable <IAccountStateDelta> EvaluateActions( AccountStateGetter accountStateGetter = null ) { IAccountStateDelta delta = new AccountStateDeltaImpl( accountStateGetter ?? (a => null) ); foreach (Transaction <T> tx in Transactions) { delta = tx.EvaluateActions( Hash, Index, delta, Miner.Value); yield return(delta); delta = new AccountStateDeltaImpl(delta.GetState); } }
/// <summary> /// Validates the integrity of the <see cref="Block{T}"/>. /// <para>It throws an <see cref="InvalidBlockException"/> or /// an <see cref="InvalidTxException"/> if there is any /// integrity error.</para> /// <para>Otherwise it returns an <see cref="IAccountStateDelta"/> /// which represents the final states and maintains the changes /// from the states of the previous <see cref="Block{T}"/>.</para> /// </summary> /// <param name="currentTime">The current time to validate /// time-wise conditions.</param> /// <param name="accountStateGetter">The getter of previous states. /// This affects the execution of <see cref="Transaction{T}.Actions"/>. /// </param> /// <returns>An <see cref="IAccountStateDelta"/> of the states /// right after all <see cref="Transaction{T}.Actions"/> of /// <see cref="Transactions"/>, which maintains the changes from /// the states of the previous <see cref="Block{T}"/>.</returns> /// <exception cref="InvalidBlockTimestampException">Thrown when /// the <see cref="Timestamp"/> is invalid, for example, it is the far /// future than the given <paramref name="currentTime"/>.</exception> /// <exception cref="InvalidBlockIndexException">Thrown when /// the <see cref="Index"/>is invalid, for example, it is a negative /// integer.</exception> /// <exception cref="InvalidBlockDifficultyException">Thrown when /// the <see cref="Difficulty"/> is not properly configured, /// for example, it is too easy.</exception> /// <exception cref="InvalidBlockPreviousHashException">Thrown when /// <see cref="PreviousHash"/> is invalid so that /// the <see cref="Block{T}"/>s are not continuous.</exception> /// <exception cref="InvalidBlockNonceException">Thrown when /// the <see cref="Nonce"/> does not satisfy its /// <see cref="Difficulty"/> level.</exception> /// <exception cref="InvalidTxSignatureException">Thrown when its /// <see cref="Transaction{T}.Signature"/> is invalid or not signed by /// the account who corresponds to its /// <see cref="Transaction{T}.PublicKey"/>.</exception> /// <exception cref="InvalidTxPublicKeyException">Thrown when its /// <see cref="Transaction{T}.Signer"/> is not derived from its /// <see cref="Transaction{T}.PublicKey"/>.</exception> /// <exception cref="InvalidTxUpdatedAddressesException">Thrown when /// any <see cref="IAction"/> of <see cref="Transactions"/> tries /// to update the states of <see cref="Address"/>es not included /// in <see cref="Transaction{T}.UpdatedAddresses"/>.</exception> public IAccountStateDelta Validate( DateTimeOffset currentTime, AccountStateGetter accountStateGetter ) { Validate(currentTime); IEnumerable <IAccountStateDelta> deltas = EvaluateActions(accountStateGetter); IAccountStateDelta result = new AccountStateDeltaImpl( accountStateGetter ); var txUpdatedAddressesPairs = Transactions.Zip( deltas, (tx, d) => (tx, d) ); foreach (var(tx, delta) in txUpdatedAddressesPairs) { IImmutableSet <Address> updatedAddresses = delta.UpdatedAddresses; if (!tx.UpdatedAddresses.IsSupersetOf(updatedAddresses)) { var msg = "Actions in the transaction try to update " + "the addresses not granted."; throw new InvalidTxUpdatedAddressesException( tx.Id, tx.UpdatedAddresses, updatedAddresses, msg ); } foreach (var pair in delta.GetUpdatedStates()) { result = result.SetState(pair.Key, pair.Value); } } return(result); }
public void GetSetState() { IAccountStateDelta init = new AccountStateDeltaImpl(GetState); IAccountStateDelta a = init.SetState(_addr[0], "A"); Assert.Equal("A", a.GetState(_addr[0])); Assert.Equal("a", init.GetState(_addr[0])); Assert.Equal("b", a.GetState(_addr[1])); Assert.Equal("b", init.GetState(_addr[1])); Assert.Null(a.GetState(_addr[2])); Assert.Null(init.GetState(_addr[2])); Assert.Equal( new[] { _addr[0] }.ToImmutableHashSet(), a.UpdatedAddresses ); Assert.Empty(init.UpdatedAddresses); IAccountStateDelta b = a.SetState(_addr[0], "z"); Assert.Equal("z", b.GetState(_addr[0])); Assert.Equal("A", a.GetState(_addr[0])); Assert.Equal("a", init.GetState(_addr[0])); Assert.Equal("b", b.GetState(_addr[1])); Assert.Equal("b", a.GetState(_addr[1])); Assert.Null(b.GetState(_addr[2])); Assert.Null(a.GetState(_addr[2])); Assert.Equal( new[] { _addr[0] }.ToImmutableHashSet(), a.UpdatedAddresses ); Assert.Empty(init.UpdatedAddresses); IAccountStateDelta c = b.SetState(_addr[0], "a"); Assert.Equal("a", c.GetState(_addr[0])); Assert.Equal("z", b.GetState(_addr[0])); Assert.Empty(c.UpdatedAddresses); Assert.Empty(init.UpdatedAddresses); }