Exemplo n.º 1
0
 public bool ContainsBlock(HashDigest <SHA256> blockHash)
 {
     Log(nameof(ContainsBlock), blockHash);
     return(_store.ContainsBlock(blockHash));
 }
Exemplo n.º 2
0
 public abstract Block <T> GetBlock <T>(HashDigest <SHA256> blockHash)
     where T : IAction, new();
Exemplo n.º 3
0
 public abstract AddressStateMap GetBlockStates(
     HashDigest <SHA256> blockHash
     );
Exemplo n.º 4
0
        public StoreFixture()
        {
            StoreChainId = Guid.NewGuid();

            Address1 = new Address(new byte[]
            {
                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
            });
            Address2 = new Address(new byte[]
            {
                0x55, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xdd,
            });
            Address3 = new Address(new byte[]
            {
                0xa3, 0x4b, 0x0c, 0x91, 0xda, 0x58, 0xd4, 0x73, 0xd3, 0x70,
                0xc4, 0x5b, 0xf9, 0x6f, 0x6d, 0x98, 0xa5, 0x01, 0xd9, 0x22,
            });
            Address4 = new Address(new byte[]
            {
                0xbf, 0x78, 0x67, 0x29, 0xba, 0x04, 0x1b, 0xa7, 0x6f, 0xfb,
                0xa0, 0x6c, 0x8c, 0x4d, 0xc1, 0x24, 0xee, 0x3e, 0x8c, 0x8b,
            });
            Address5 = new Address(new byte[]
            {
                0x03, 0xf0, 0x42, 0x7f, 0x2e, 0x6c, 0x0f, 0x5f, 0xdb, 0xd3,
                0x77, 0x9d, 0xb2, 0x84, 0xd6, 0x1b, 0x04, 0x38, 0xdf, 0xb6,
            });
            TxId1 = new TxId(new byte[]
            {
                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x9c, 0xcc,
            });
            TxId2 = new TxId(new byte[]
            {
                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x9c, 0xdd,
            });
            TxId3 = new TxId(new byte[]
            {
                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x9c, 0xee,
            });
            Hash1 = new HashDigest <SHA256>(new byte[]
            {
                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x9c, 0xcc,
            });
            Hash2 = new HashDigest <SHA256>(new byte[]
            {
                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x9c, 0xdd,
            });
            Hash3 = new HashDigest <SHA256>(new byte[]
            {
                0x45, 0xa2, 0x21, 0x87, 0xe2, 0xd8, 0x85, 0x0b, 0xb3, 0x57,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x88, 0x69, 0x58, 0xbc, 0x3e, 0x85, 0x60, 0x92, 0x9c, 0xcc,
                0x9c, 0xee,
            });

            GenesisBlock = TestUtils.MineGenesis <DumbAction>();
            Block1       = TestUtils.MineNext(GenesisBlock);
            Block2       = TestUtils.MineNext(Block1);
            Block3       = TestUtils.MineNext(Block2);

            Transaction1 = MakeTransaction(new List <DumbAction>(), ImmutableHashSet <Address> .Empty);
            Transaction2 = MakeTransaction(new List <DumbAction>(), ImmutableHashSet <Address> .Empty);
            Transaction3 = MakeTransaction(new List <DumbAction>(), ImmutableHashSet <Address> .Empty);
        }
Exemplo n.º 5
0
 public abstract bool DeleteIndex(
     string @namespace,
     HashDigest <SHA256> hash
     );
Exemplo n.º 6
0
 public Tip(NetMQFrame[] frames)
 {
     TipIndex = frames[0].ConvertToInt64();
     TipHash  = frames[1].ConvertToHashDigest <SHA256>();
 }
 public GetBlock(NetMQFrame[] frames)
 {
     BlockHash = frames[0].ConvertToHashDigest <SHA256>();
 }
Exemplo n.º 8
0
        private UPath BlockPath(HashDigest <SHA256> blockHash)
        {
            string idHex = ByteUtil.Hex(blockHash.ByteArray);

            return(UPath.Root / idHex.Substring(0, 2) / idHex.Substring(2));
        }
Exemplo n.º 9
0
 public ITrie GetStateRoot(HashDigest <SHA256>?stateRootHash) => null;
Exemplo n.º 10
0
 public BlockDigest?GetBlockDigest(HashDigest <SHA256> blockHash)
 {
     Log(nameof(GetBlockDigest), blockHash);
     return(_store.GetBlockDigest(blockHash));
 }
Exemplo n.º 11
0
 /// <inheritdoc/>
 public override long AppendIndex(Guid chainId, HashDigest <SHA256> hash)
 {
     return(IndexCollection(chainId).Insert(new HashDoc {
         Hash = hash
     }) - 1);
 }
Exemplo n.º 12
0
 public long?GetBlockIndex(HashDigest <SHA256> blockHash)
 {
     Log(nameof(GetBlockIndex), blockHash);
     return(_store.GetBlockIndex(blockHash));
 }
Exemplo n.º 13
0
 public Block <T> GetBlock <T>(HashDigest <SHA256> blockHash)
     where T : IAction, new()
 {
     Log(nameof(GetBlock), blockHash);
     return(_store.GetBlock <T>(blockHash));
 }
Exemplo n.º 14
0
 public DateTimeOffset?GetBlockPerceivedTime(HashDigest <SHA256> blockHash)
 {
     Log(nameof(GetBlockPerceivedTime), blockHash);
     return(_store.GetBlockPerceivedTime(blockHash));
 }
 public void OnAfterDeserialize()
 {
     Value = HashDigest <T> .FromString(json);
 }
Exemplo n.º 16
0
        /// <summary>
        /// Generate a block with given <paramref name="transactions"/>.
        /// </summary>
        /// <param name="index">Index of the block.</param>
        /// <param name="difficulty">Difficulty to find the <see cref="Block{T}"/>
        /// <see cref="Nonce"/>.</param>
        /// <param name="previousTotalDifficulty">The total difficulty until the previous
        /// <see cref="Block{T}"/>.</param>
        /// <param name="miner">The <see cref="Address"/> of miner that mined the block.</param>
        /// <param name="previousHash">
        /// The <see cref="HashDigest{SHA256}"/> of previous block.
        /// </param>
        /// <param name="timestamp">The <see cref="DateTimeOffset"/> when mining started.</param>
        /// <param name="transactions"><see cref="Transaction{T}"/>s that are going to be included
        /// in the block.</param>
        /// <param name="cancellationToken">
        /// A cancellation token used to propagate notification that this
        /// operation should be canceled.</param>
        /// <returns>A <see cref="Block{T}"/> that mined.</returns>
        public static Block <T> Mine(
            long index,
            long difficulty,
            BigInteger previousTotalDifficulty,
            Address miner,
            HashDigest <SHA256>?previousHash,
            DateTimeOffset timestamp,
            IEnumerable <Transaction <T> > transactions,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            var txs = transactions.OrderBy(tx => tx.Id).ToImmutableArray();

            Block <T> MakeBlock(Nonce n) => new Block <T>(
                index,
                difficulty,
                previousTotalDifficulty + difficulty,
                n,
                miner,
                previousHash,
                timestamp,
                txs);

            // Poor man' way to optimize stamp...
            // FIXME: We need to rather reorganize the serialization layout.
            byte[] emptyNonce   = MakeBlock(new Nonce(new byte[0])).SerializeForHash();
            byte[] oneByteNonce = MakeBlock(new Nonce(new byte[1])).SerializeForHash();
            int    offset       = 0;

            while (offset < emptyNonce.Length && emptyNonce[offset].Equals(oneByteNonce[offset]))
            {
                offset++;
            }

            const int nonceLength = 2;  // In Bencodex, empty bytes are represented as "0:".

            byte[] stampPrefix = new byte[offset];
            Array.Copy(emptyNonce, stampPrefix, stampPrefix.Length);
            byte[] stampSuffix = new byte[emptyNonce.Length - offset - nonceLength];
            Array.Copy(emptyNonce, offset + nonceLength, stampSuffix, 0, stampSuffix.Length);

            Nonce nonce = Hashcash.Answer(
                n =>
            {
                int nLen       = n.ByteArray.Length;
                byte[] nLenStr = Encoding.ASCII.GetBytes(
                    nLen.ToString(CultureInfo.InvariantCulture));
                int totalLen =
                    stampPrefix.Length + nLenStr.Length + 1 + nLen + stampSuffix.Length;
                byte[] stamp = new byte[totalLen];
                Array.Copy(stampPrefix, stamp, stampPrefix.Length);
                int pos = stampPrefix.Length;
                Array.Copy(nLenStr, 0, stamp, pos, nLenStr.Length);
                pos       += nLenStr.Length;
                stamp[pos] = 0x3a;      // ':'
                pos++;
                n.ByteArray.CopyTo(stamp, pos);
                pos += nLen;
                Array.Copy(stampSuffix, 0, stamp, pos, stampSuffix.Length);
                return(stamp);
            },
                difficulty,
                cancellationToken
                );

            return(MakeBlock(nonce));
        }
Exemplo n.º 17
0
 public Tip(long tipIndex, HashDigest <SHA256> tipHash)
 {
     TipIndex = tipIndex;
     TipHash  = tipHash;
 }
Exemplo n.º 18
0
        /// <summary>
        /// Creates a <see cref="Block{T}"/> instance by manually filling all field values.
        /// For a more automated way, see also <see cref="Mine"/> method.
        /// </summary>
        /// <param name="index">The height of the block to create.  Goes to the <see cref="Index"/>.
        /// </param>
        /// <param name="difficulty">The mining difficulty that <paramref name="nonce"/> has to
        /// satisfy.  Goes to the <see cref="Difficulty"/>.</param>
        /// <param name="totalDifficulty">The total mining difficulty until this block.
        /// See also <see cref="Difficulty"/>.</param>
        /// <param name="nonce">The nonce which satisfy the given <paramref name="difficulty"/> with
        /// any other field values.  Goes to the <see cref="Nonce"/>.</param>
        /// <param name="miner">An optional address refers to who mines this block.
        /// Goes to the <see cref="Miner"/>.</param>
        /// <param name="previousHash">The previous block's <see cref="Hash"/>.  If it's a genesis
        /// block (i.e., <paramref name="index"/> is 0) this should be <c>null</c>.
        /// Goes to the <see cref="PreviousHash"/>.</param>
        /// <param name="timestamp">The time this block is created.  Goes to
        /// the <see cref="Timestamp"/>.</param>
        /// <param name="transactions">The transactions to be mined together with this block.
        /// Transactions become sorted in an unpredicted-before-mined order and then go to
        /// the <see cref="Transactions"/> property.
        /// </param>
        /// <seealso cref="Mine"/>
        public Block(
            long index,
            long difficulty,
            BigInteger totalDifficulty,
            Nonce nonce,
            Address?miner,
            HashDigest <SHA256>?previousHash,
            DateTimeOffset timestamp,
            IEnumerable <Transaction <T> > transactions)
        {
            Index           = index;
            Difficulty      = difficulty;
            TotalDifficulty = totalDifficulty;
            Nonce           = nonce;
            Miner           = miner;
            PreviousHash    = previousHash;
            Timestamp       = timestamp;
            Transactions    = transactions.OrderBy(tx => tx.Id).ToArray();
            var codec = new Codec();

            TxHash = Transactions.Any()
                ? Hashcash.Hash(
                codec.Encode(
                    new Bencodex.Types.List(Transactions.Select(tx =>
                                                                (IValue)tx.ToBencodex(true)))))
                : (HashDigest <SHA256>?)null;

            // FIXME: This does not need to be computed every time?
            Hash = Hashcash.Hash(SerializeForHash());

            // As the order of transactions should be unpredictable until a block is mined,
            // the sorter key should be derived from both a block hash and a txid.
            var hashInteger = new BigInteger(Hash.ToByteArray());

            // If there are multiple transactions for the same signer these should be ordered by
            // their tx nonces.  So transactions of the same signer should have the same sort key.
            // The following logic "flattens" multiple tx ids having the same signer into a single
            // txid by applying XOR between them.
            IImmutableDictionary <Address, IImmutableSet <Transaction <T> > > signerTxs = Transactions
                                                                                          .GroupBy(tx => tx.Signer)
                                                                                          .ToImmutableDictionary(
                g => g.Key,
                g => (IImmutableSet <Transaction <T> >)g.ToImmutableHashSet()
                );
            IImmutableDictionary <Address, BigInteger> signerTxIds = signerTxs
                                                                     .ToImmutableDictionary(
                pair => pair.Key,
                pair => pair.Value
                .Select(tx => new BigInteger(tx.Id.ToByteArray()))
                .OrderBy(txid => txid)
                .Aggregate((a, b) => a ^ b)
                );

            // Order signers by values derivied from both block hash and their "flatten" txid:
            IImmutableList <Address> signers = signerTxIds
                                               .OrderBy(pair => pair.Value ^ hashInteger)
                                               .Select(pair => pair.Key)
                                               .ToImmutableArray();

            // Order transactions for each signer by their tx nonces:
            Transactions = signers
                           .SelectMany(signer => signerTxs[signer].OrderBy(tx => tx.Nonce))
                           .ToImmutableArray();
        }
 public GetBlock(HashDigest <SHA256> blockHash)
 {
     BlockHash = blockHash;
 }
Exemplo n.º 20
0
 public abstract void SetBlockStates(
     string @namespace,
     HashDigest <SHA256> blockHash,
     AddressStateMap states
     );
Exemplo n.º 21
0
 public abstract long AppendIndex(HashDigest <SHA256> hash);
Exemplo n.º 22
0
 public abstract Block <T> GetBlock <T>(
     string @namespace,
     HashDigest <SHA256> blockHash
     )
     where T : IAction;
Exemplo n.º 23
0
        /// <summary>
        /// Executes the <paramref name="actions"/> step by step, and emits
        /// <see cref="ActionEvaluation"/> for each step.
        /// </summary>
        /// <param name="blockHash">The <see cref="Block{T}.Hash"/> of <see cref="Block{T}"/> that
        /// <paramref name="actions"/> belongs to.</param>
        /// <param name="blockIndex">The <see cref="Block{T}.Index"/> of <see cref="Block{T}"/> that
        /// <paramref name="actions"/> belongs to.</param>
        /// <param name="txid">The <see cref="Transaction{T}.Id"/> of <see cref="Transaction{T}"/>
        /// that <paramref name="actions"/> belongs to.  This can be <c>null</c> on rehearsal mode
        /// or if an action is a <see cref="IBlockPolicy{T}.BlockAction"/>.</param>
        /// <param name="previousStates">The states immediately before <paramref name="actions"/>
        /// being executed.  Note that its <see cref="IAccountStateDelta.UpdatedAddresses"/> are
        /// remained to the returned next states.</param>
        /// <param name="minerAddress">An address of block miner.</param>
        /// <param name="signer">Signer of the <paramref name="actions"/>.</param>
        /// <param name="signature"><see cref="Transaction{T}"/> signature used to generate random
        /// seeds.</param>
        /// <param name="actions">Actions to evaluate.</param>
        /// <param name="rehearsal">Pass <c>true</c> if it is intended
        /// to be dry-run (i.e., the returned result will be never used).
        /// The default value is <c>false</c>.</param>
        /// <returns>Enumerates <see cref="ActionEvaluation"/>s for each one in
        /// <paramref name="actions"/>.  The order is the same to the <paramref name="actions"/>.
        /// Note that each <see cref="IActionContext.Random"/> object
        /// has a unconsumed state.
        /// </returns>
        /// <exception cref="UnexpectedlyTerminatedActionException">
        /// Thrown when one of <paramref name="actions"/> throws some exception.
        /// The actual exception that an <see cref="IAction"/> threw
        /// is stored in its <see cref="Exception.InnerException"/> property.
        /// </exception>
        internal static IEnumerable <ActionEvaluation> EvaluateActionsGradually(
            HashDigest <SHA256> blockHash,
            long blockIndex,
            TxId?txid,
            IAccountStateDelta previousStates,
            Address minerAddress,
            Address signer,
            byte[] signature,
            IImmutableList <IAction> actions,
            bool rehearsal = false)
        {
            ActionContext CreateActionContext(
                IAccountStateDelta prevStates,
                int randomSeed
                ) =>
            new ActionContext(
                signer: signer,
                miner: minerAddress,
                blockIndex: blockIndex,
                previousStates: prevStates,
                randomSeed: randomSeed,
                rehearsal: rehearsal
                );

            byte[] hashedSignature;
            using (var hasher = SHA1.Create())
            {
                hashedSignature = hasher.ComputeHash(signature);
            }

            int seed =
                BitConverter.ToInt32(blockHash.ToByteArray(), 0) ^
                (signature.Any() ? BitConverter.ToInt32(hashedSignature, 0) : 0);

            IAccountStateDelta states = previousStates;

            foreach (IAction action in actions)
            {
                ActionContext context =
                    CreateActionContext(states, seed);
                IAccountStateDelta nextStates;
                try
                {
                    nextStates = action.Execute(context);
                }
                catch (Exception e)
                {
                    string msg;
                    if (!rehearsal)
                    {
                        msg = $"The action {action} (block #{blockIndex} {blockHash}, tx {txid}) " +
                              "threw an exception during execution.  See also this exception's " +
                              "InnerException property.";
                        throw new UnexpectedlyTerminatedActionException(
                                  blockHash, blockIndex, txid, action, msg, e
                                  );
                    }

                    msg =
                        $"The action {action} threw an exception during its " +
                        "rehearsal.  It is probably because the logic of the " +
                        $"action {action} is not enough generic so that it " +
                        "can cover every case including rehearsal mode.\n" +
                        "The IActionContext.Rehearsal property also might be " +
                        "useful to make the action can deal with the case of " +
                        "rehearsal mode.\n" +
                        "See also this exception's InnerException property.";
                    throw new UnexpectedlyTerminatedActionException(
                              null, null, null, action, msg, e
                              );
                }

                // As IActionContext.Random is stateful, we cannot reuse
                // the context which is once consumed by Execute().
                ActionContext equivalentContext =
                    CreateActionContext(states, seed);

                yield return(new ActionEvaluation(
                                 action,
                                 equivalentContext,
                                 nextStates
                                 ));

                states = nextStates;
                unchecked
                {
                    seed++;
                }
            }
        }
Exemplo n.º 24
0
 public abstract bool DeleteBlock(
     string @namespace,
     HashDigest <SHA256> blockHash
     );
Exemplo n.º 25
0
 public abstract long AppendIndex(
     string @namespace,
     HashDigest <SHA256> hash
     );
Exemplo n.º 26
0
 public abstract AddressStateMap GetBlockStates(
     string @namespace,
     HashDigest <SHA256> blockHash
     );
Exemplo n.º 27
0
 public abstract bool DeleteBlock(HashDigest <SHA256> blockHash);
 public JsonConvertibleHashDigest(HashDigest <T> hashDigest)
 {
     Value = hashDigest;
     json  = null;
 }
Exemplo n.º 29
0
 public abstract void SetBlockStates(
     HashDigest <SHA256> blockHash,
     AddressStateMap states
     );
Exemplo n.º 30
0
 public bool DeleteBlock(HashDigest <SHA256> blockHash)
 {
     Log(nameof(DeleteBlock), blockHash);
     return(_store.DeleteBlock(blockHash));
 }