public bool ContainsBlock(HashDigest <SHA256> blockHash) { Log(nameof(ContainsBlock), blockHash); return(_store.ContainsBlock(blockHash)); }
public abstract Block <T> GetBlock <T>(HashDigest <SHA256> blockHash) where T : IAction, new();
public abstract AddressStateMap GetBlockStates( HashDigest <SHA256> blockHash );
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); }
public abstract bool DeleteIndex( string @namespace, HashDigest <SHA256> hash );
public Tip(NetMQFrame[] frames) { TipIndex = frames[0].ConvertToInt64(); TipHash = frames[1].ConvertToHashDigest <SHA256>(); }
public GetBlock(NetMQFrame[] frames) { BlockHash = frames[0].ConvertToHashDigest <SHA256>(); }
private UPath BlockPath(HashDigest <SHA256> blockHash) { string idHex = ByteUtil.Hex(blockHash.ByteArray); return(UPath.Root / idHex.Substring(0, 2) / idHex.Substring(2)); }
public ITrie GetStateRoot(HashDigest <SHA256>?stateRootHash) => null;
public BlockDigest?GetBlockDigest(HashDigest <SHA256> blockHash) { Log(nameof(GetBlockDigest), blockHash); return(_store.GetBlockDigest(blockHash)); }
/// <inheritdoc/> public override long AppendIndex(Guid chainId, HashDigest <SHA256> hash) { return(IndexCollection(chainId).Insert(new HashDoc { Hash = hash }) - 1); }
public long?GetBlockIndex(HashDigest <SHA256> blockHash) { Log(nameof(GetBlockIndex), blockHash); return(_store.GetBlockIndex(blockHash)); }
public Block <T> GetBlock <T>(HashDigest <SHA256> blockHash) where T : IAction, new() { Log(nameof(GetBlock), blockHash); return(_store.GetBlock <T>(blockHash)); }
public DateTimeOffset?GetBlockPerceivedTime(HashDigest <SHA256> blockHash) { Log(nameof(GetBlockPerceivedTime), blockHash); return(_store.GetBlockPerceivedTime(blockHash)); }
public void OnAfterDeserialize() { Value = HashDigest <T> .FromString(json); }
/// <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)); }
public Tip(long tipIndex, HashDigest <SHA256> tipHash) { TipIndex = tipIndex; TipHash = tipHash; }
/// <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; }
public abstract void SetBlockStates( string @namespace, HashDigest <SHA256> blockHash, AddressStateMap states );
public abstract long AppendIndex(HashDigest <SHA256> hash);
public abstract Block <T> GetBlock <T>( string @namespace, HashDigest <SHA256> blockHash ) where T : IAction;
/// <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++; } } }
public abstract bool DeleteBlock( string @namespace, HashDigest <SHA256> blockHash );
public abstract long AppendIndex( string @namespace, HashDigest <SHA256> hash );
public abstract AddressStateMap GetBlockStates( string @namespace, HashDigest <SHA256> blockHash );
public abstract bool DeleteBlock(HashDigest <SHA256> blockHash);
public JsonConvertibleHashDigest(HashDigest <T> hashDigest) { Value = hashDigest; json = null; }
public abstract void SetBlockStates( HashDigest <SHA256> blockHash, AddressStateMap states );
public bool DeleteBlock(HashDigest <SHA256> blockHash) { Log(nameof(DeleteBlock), blockHash); return(_store.DeleteBlock(blockHash)); }