Example #1
0
        /// <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);
        }
Example #2
0
        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);
        }