Ejemplo n.º 1
0
        public static Transaction <T> CreateUnsigned(
            long nonce,
            PublicKey publicKey,
            BlockHash?genesisHash,
            IEnumerable <T> actions,
            IImmutableSet <Address> updatedAddresses = null,
            DateTimeOffset?timestamp = null
            )
        {
            var signer = new Address(publicKey);

            if (ReferenceEquals(updatedAddresses, null))
            {
                updatedAddresses = ImmutableHashSet <Address> .Empty;
            }

            DateTimeOffset ts = timestamp ?? DateTimeOffset.UtcNow;

            ImmutableArray <T> actionsArray = actions.ToImmutableArray();

            if (!actionsArray.IsEmpty)
            {
                // FIXME: Although we are assuming all block hashes are SHA256 digest, we should
                // parametrize this in the future.
                BlockHash emptyBlockHash = BlockHash.FromHashDigest(default(HashDigest <SHA256>));

                var evalUpdatedAddresses = ActionEvaluator <T> .GetUpdatedAddresses(
                    new Transaction <T>(
                        nonce,
                        signer,
                        publicKey,
                        genesisHash,
                        updatedAddresses,
                        ts,
                        actionsArray));

                if (!updatedAddresses.IsSupersetOf(evalUpdatedAddresses))
                {
                    updatedAddresses = updatedAddresses.Union(evalUpdatedAddresses);
                }
            }

            return(new Transaction <T>(
                       nonce,
                       signer,
                       publicKey,
                       genesisHash,
                       updatedAddresses,
                       ts,
                       actionsArray));
        }
Ejemplo n.º 2
0
        public void FromHashDigest()
        {
            byte[] b =
            {
                0x28, 0x31, 0xd4, 0xc2, 0x4a, 0xe5, 0xd1, 0x93, 0x1a, 0x16, 0xde,
                0x0a, 0x06, 0x6e, 0x23, 0x3e, 0x0e, 0xed, 0x1d, 0x3f, 0xdf, 0x6d,
                0x57, 0x2a, 0xd5, 0x8d, 0x1c, 0x37, 0x05, 0xc8, 0xcb, 0xfc,
            };
            var       expected = new BlockHash(b);
            BlockHash actual   = BlockHash.FromHashDigest(new HashDigest <SHA256>(b));

            Assert.Equal(expected, actual);

            Assert.Equal(
                new BlockHash(new byte[32]),
                BlockHash.FromHashDigest(default)
Ejemplo n.º 3
0
        /// <summary>
        /// A fa&#xe7;ade factory to create a new <see cref="Transaction{T}"/>.
        /// Unlike the <see cref="Transaction(long, Address, PublicKey, BlockHash?,
        /// IImmutableSet{Address}, DateTimeOffset, IEnumerable{T}, byte[])"/>
        /// constructor, it automatically fills the following values from:
        /// <list type="table">
        /// <listheader>
        /// <term>Property</term>
        /// <description>Parameter the filled value derived from</description>
        /// </listheader>
        /// <item>
        /// <term><see cref="Signer"/></term>
        /// <description><paramref name="privateKey"/></description>
        /// </item>
        /// <item>
        /// <term><see cref="PublicKey"/></term>
        /// <description><paramref name="privateKey"/></description>
        /// </item>
        /// <item>
        /// <term><see cref="UpdatedAddresses"/></term>
        /// <description><paramref name="actions"/> and
        /// <paramref name="updatedAddresses"/></description>
        /// </item>
        /// </list>
        /// <para>Note that the <paramref name="privateKey"/> in itself is not
        /// included in the created <see cref="Transaction{T}"/>.</para>
        /// </summary>
        /// <remarks>
        /// This factory method tries its best to fill the <see
        /// cref="UpdatedAddresses"/> property by actually evaluating
        /// the given <paramref name="actions"/> (we call it &#x201c;rehearsal
        /// mode&#x201d;), but remember that its result
        /// is approximated in some degree, because the result of
        /// <paramref name="actions"/> are not deterministic until
        /// the <see cref="Transaction{T}"/> belongs to a <see
        /// cref="Libplanet.Blocks.Block{T}"/>.
        /// <para>If an <see cref="IAction"/> depends on previous states or
        /// some randomness to determine what <see cref="Address"/> to update,
        /// the automatically filled <see cref="UpdatedAddresses"/> became
        /// mismatched from the <see cref="Address"/>es
        /// <paramref name="actions"/> actually update after
        /// a <see cref="Libplanet.Blocks.Block{T}"/> is mined.
        /// Although such case would be rare, a programmer could manually give
        /// the <paramref name="updatedAddresses"/> parameter
        /// the <see cref="Address"/>es they predict to be updated.</para>
        /// <para>If an <see cref="IAction"/> oversimplifies the assumption
        /// about the <see cref="Libplanet.Blocks.Block{T}"/> it belongs to,
        /// runtime exceptions could be thrown from this factory method.
        /// The best solution to that is not to oversimplify things,
        /// there is an option to check <see cref="IActionContext"/>'s
        /// <see cref="IActionContext.Rehearsal"/> is <c>true</c> and
        /// a conditional logic for the case.</para>
        /// </remarks>
        /// <param name="nonce">The number of previous
        /// <see cref="Transaction{T}"/>s committed by the <see cref="Signer"/>
        /// of this transaction.  This goes to the
        /// <see cref="Transaction{T}.Nonce"/> property.</param>
        /// <param name="privateKey">A <see cref="PrivateKey"/> of the account
        /// who creates and signs a new transaction.  This key is used to fill
        /// the <see cref="Signer"/>, <see cref="PublicKey"/>, and
        /// <see cref="Signature"/> properties, but this in itself is not
        /// included in the transaction.</param>
        /// <param name="genesisHash">A <see cref="HashDigest{SHA256}"/> value
        /// of the genesis which this <see cref="Transaction{T}"/> is made from.
        /// This can be <c>null</c> iff the transaction is contained
        /// in the genesis block.
        /// </param>
        /// <param name="actions">A list of <see cref="IAction"/>s.  This
        /// can be empty, but cannot be <c>null</c>.  This goes to
        /// the <see cref="Actions"/> property, and <see cref="IAction"/>s
        /// are evaluated before a <see cref="Transaction{T}"/> is created
        /// in order to fill the <see cref="UpdatedAddresses"/>.  See also
        /// <em>Remarks</em> section.</param>
        /// <param name="updatedAddresses"><see cref="Address"/>es whose
        /// states affected by <paramref name="actions"/>.
        /// These <see cref="Address"/>es are also included in
        /// the <see cref="UpdatedAddresses"/> property, besides
        /// <see cref="Address"/>es projected by evaluating
        /// <paramref name="actions"/>.  See also <em>Remarks</em> section.
        /// </param>
        /// <param name="timestamp">The time this <see cref="Transaction{T}"/>
        /// is created and signed.  This goes to the <see cref="Timestamp"/>
        /// property.  If <c>null</c> (which is default) is passed this will
        /// be the current time.</param>
        /// <returns>A created new <see cref="Transaction{T}"/> signed by
        /// the given <paramref name="privateKey"/>.</returns>
        /// <exception cref="ArgumentNullException">Thrown when <c>null</c>
        /// is passed to <paramref name="privateKey"/> or
        /// or <paramref name="actions"/>.
        /// </exception>
        public static Transaction <T> Create(
            long nonce,
            PrivateKey privateKey,
            BlockHash?genesisHash,
            IEnumerable <T> actions,
            IImmutableSet <Address> updatedAddresses = null,
            DateTimeOffset?timestamp = null
            )
        {
            if (ReferenceEquals(privateKey, null))
            {
                throw new ArgumentNullException(nameof(privateKey));
            }

            PublicKey publicKey = privateKey.PublicKey;
            var       signer    = new Address(publicKey);

            if (ReferenceEquals(updatedAddresses, null))
            {
                updatedAddresses = ImmutableHashSet <Address> .Empty;
            }

            DateTimeOffset ts = timestamp ?? DateTimeOffset.UtcNow;

            ImmutableArray <T> actionsArray = actions.ToImmutableArray();

            byte[] payload = new Transaction <T>(
                nonce,
                signer,
                publicKey,
                genesisHash,
                updatedAddresses,
                ts,
                actionsArray
                ).Serialize(false);

            if (!actionsArray.IsEmpty)
            {
                // FIXME: Although we are assuming all block hashes are SHA256 digest, we should
                // parametrize this in the future.
                BlockHash emptyBlockHash = BlockHash.FromHashDigest(default(HashDigest <SHA256>));

                IAccountStateDelta delta = new Transaction <T>(
                    nonce,
                    signer,
                    publicKey,
                    genesisHash,
                    updatedAddresses,
                    ts,
                    actionsArray
                    ).EvaluateActions(
                    emptyBlockHash,
                    0,
                    new AccountStateDeltaImpl(
                        _ => null,
                        (_, c) => new FungibleAssetValue(c),
                        signer
                        ),
                    signer,
                    rehearsal: true
                    );
                if (!updatedAddresses.IsSupersetOf(delta.UpdatedAddresses))
                {
                    updatedAddresses =
                        updatedAddresses.Union(delta.UpdatedAddresses);
                    payload = new Transaction <T>(
                        nonce,
                        signer,
                        publicKey,
                        genesisHash,
                        updatedAddresses,
                        ts,
                        actionsArray
                        ).Serialize(false);
                }
            }

            byte[] sig = privateKey.Sign(payload);
            return(new Transaction <T>(
                       nonce,
                       signer,
                       publicKey,
                       genesisHash,
                       updatedAddresses,
                       ts,
                       actionsArray,
                       sig
                       ));
        }
Ejemplo n.º 4
0
 public static BlockHash Hash(byte[] bytes) =>
 BlockHash.FromHashDigest(HashDigest <SHA256> .DeriveFrom(bytes));