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