public bool VerifySignature(ImmutableArray <byte> scriptPubKey, Transaction tx, byte[] sig, byte[] pubKey, int inputIndex, out byte hashType, out byte[] txSignature, out byte[] txSignatureHash) { // get the 1-byte hashType off the end of sig hashType = sig[sig.Length - 1]; // get the DER encoded portion of sig, which is everything except the last byte (the last byte being hashType) var sigDER = sig.Take(sig.Length - 1).ToArray(); // get the simplified/signing version of the transaction txSignature = TxSignature(scriptPubKey, tx, inputIndex, hashType); // get the hash of the simplified/signing version of the transaction var sha256 = new SHA256Managed(); txSignatureHash = sha256.ComputeDoubleHash(txSignature); if (this.ignoreSignatures) { return(true); } else { #if SECP256K1_DLL // verify that signature is valid for pubKey and the simplified/signing transaction's hash return(Signatures.Verify(txSignatureHash, sigDER, pubKey) == Signatures.VerifyResult.Verified); #else return(true); #endif } }
public static UInt256 CalculateMerkleRoot(IImmutableList <UInt256> txHashes, out ImmutableList <ImmutableArray <byte> > merkleTree) { var sha256 = new SHA256Managed(); var workingMerkleTree = ImmutableList.CreateBuilder <ImmutableArray <byte> >(); var hashes = txHashes.Select(txHash => txHash.ToByteArray().ToImmutableArray()).ToList(); workingMerkleTree.AddRange(hashes); while (hashes.Count > 1) { workingMerkleTree.AddRange(hashes); // ensure row is even length if (hashes.Count % 2 != 0) { hashes.Add(hashes.Last()); } // pair up hashes in row ({1, 2, 3, 4} into {{1, 2}, {3, 4}}) and then hash the pairs // the result is the next row, which will be half the size of the current row hashes = Enumerable.Range(0, hashes.Count / 2) .Select(i => hashes[i * 2].AddRange(hashes[i * 2 + 1])) //.AsParallel().AsOrdered().WithExecutionMode(ParallelExecutionMode.ForceParallelism).WithDegreeOfParallelism(10) .Select(pair => sha256.ComputeDoubleHash(pair.ToArray()).ToImmutableArray()) .ToList(); } Debug.Assert(hashes.Count == 1); merkleTree = workingMerkleTree.ToImmutable(); return(new UInt256(hashes[0].ToArray())); }
public static MerkleTreeNode Pair(MerkleTreeNode left, MerkleTreeNode right) { if (left.Depth != right.Depth) { throw new InvalidOperationException(); } if (!left.pruned) { throw new ArgumentException("left"); } if (!right.pruned) { throw new ArgumentException("right"); } var expectedIndex = left.Index + (1 << left.Depth); if (right.Index != expectedIndex) { throw new InvalidOperationException(); } var pairHashBytes = new byte[64]; left.Hash.ToByteArray(pairHashBytes, 0); right.Hash.ToByteArray(pairHashBytes, 32); var sha256 = new SHA256Managed(); var pairHash = new UInt256(sha256.ComputeDoubleHash(pairHashBytes)); return(new MerkleTreeNode(left.Index, left.Depth + 1, pairHash, pruned: true)); }
public void TestUInt256Sha256() { var sha256 = new SHA256Managed(); var expected = sha256.ComputeDoubleHash(UInt256.Parse(TestData.HEX_STRING_64, NumberStyles.HexNumber).ToByteArray()); var actual = new UInt256(expected).ToByteArray(); CollectionAssert.AreEqual(expected, actual); }
private IEnumerable <BlockTx> ReadBlockTransactions(UInt256 blockHash, int blockId) { using (var handle = this.cursorCache.TakeItem()) { var cursor = handle.Item; using (var jetTx = cursor.jetSession.BeginTransaction()) { var sha256 = new SHA256Managed(); Api.JetSetCurrentIndex(cursor.jetSession, cursor.blocksTableId, "IX_BlockIdTxIndex"); Api.MakeKey(cursor.jetSession, cursor.blocksTableId, blockId, MakeKeyGrbit.NewKey); Api.MakeKey(cursor.jetSession, cursor.blocksTableId, -1, MakeKeyGrbit.None); if (!Api.TrySeek(cursor.jetSession, cursor.blocksTableId, SeekGrbit.SeekGE)) { yield break; } do { if (blockId != Api.RetrieveColumnAsInt32(cursor.jetSession, cursor.blocksTableId, cursor.blockIdColumnId).Value) { yield break; } var txIndex = Api.RetrieveColumnAsInt32(cursor.jetSession, cursor.blocksTableId, cursor.blockTxIndexColumnId).Value; var depth = Api.RetrieveColumnAsInt32(cursor.jetSession, cursor.blocksTableId, cursor.blockDepthColumnId).Value; var txHash = DbEncoder.DecodeUInt256(Api.RetrieveColumn(cursor.jetSession, cursor.blocksTableId, cursor.blockTxHashColumnId)); var txBytes = Api.RetrieveColumn(cursor.jetSession, cursor.blocksTableId, cursor.blockTxBytesColumnId); // determine if transaction is pruned by its depth var pruned = depth >= 0; depth = Math.Max(0, depth); Transaction tx; if (!pruned) { // verify transaction is not corrupt if (txHash != new UInt256(sha256.ComputeDoubleHash(txBytes))) { throw new MissingDataException(blockHash); } tx = DataEncoder.DecodeTransaction(txBytes); } else { tx = null; } var blockTx = new BlockTx(txIndex, depth, txHash, pruned, tx); yield return(blockTx); } while (Api.TryMoveNext(cursor.jetSession, cursor.blocksTableId)); } } }
public byte[] CreatePrivateKeyScript(Transaction tx, int inputIndex, byte hashType, ECPrivateKeyParameters privateKey, ECPublicKeyParameters publicKey) { //TODO var sha256 = new SHA256Managed(); var scriptEngine = new ScriptEngine(this.logger); var publicAddress = CreatePublicAddress(publicKey); var publicKeyScript = CreatePublicKeyScript(publicAddress); var txSignature = scriptEngine.TxSignature(publicKeyScript.ToImmutableArray(), tx, inputIndex, hashType); var txSignatureHash = sha256.ComputeDoubleHash(txSignature); //Debug.WriteLine("Signing Tx: {0}".Format2(txSignature.ToHexDataString())); //Debug.WriteLine("Signing Tx Hash: {0}".Format2(txSignatureHash.ToHexDataString())); var signer = new ECDsaSigner(); signer.Init(forSigning: true, parameters: privateKey); var signature = signer.GenerateSignature(txSignatureHash); var r = signature[0]; var s = signature[1]; byte[] sigEncoded; using (var stream = new MemoryStream()) { using (var asn1Stream = new Asn1OutputStream(stream)) { asn1Stream.WriteObject(new DerSequence(new DerInteger(r), new DerInteger(s))); } sigEncoded = stream.ToArray().Concat(hashType); } //Debug.WriteLine("Sig R: {0}".Format2(r.ToHexNumberStringUnsigned())); //Debug.WriteLine("Sig S: {0}".Format2(s.ToHexNumberStringUnsigned())); //Debug.WriteLine("Sig Encoded: {0}".Format2(sigEncoded.ToHexDataString())); using (var privateKeyScript = new ScriptBuilder()) { privateKeyScript.WritePushData(sigEncoded); privateKeyScript.WritePushData(publicAddress); //Debug.WriteLine("Private Script: {0}".Format2(privateKeyScript.GetScript().ToHexDataString())); return(privateKeyScript.GetScript()); } }
public static UInt256 CalculateTransactionHash(UInt32 Version, ImmutableArray <TxInput> Inputs, ImmutableArray <TxOutput> Outputs, UInt32 LockTime) { var sha256 = new SHA256Managed(); return(new UInt256(sha256.ComputeDoubleHash(DataEncoder.EncodeTransaction(Version, Inputs, Outputs, LockTime)))); }
public static UInt256 CalculateTransactionHash(Transaction tx) { var sha256 = new SHA256Managed(); return(new UInt256(sha256.ComputeDoubleHash(DataEncoder.EncodeTransaction(tx)))); }
public static UInt256 CalculateBlockHash(UInt32 Version, UInt256 PreviousBlock, UInt256 MerkleRoot, UInt32 Time, UInt32 Bits, UInt32 Nonce) { var sha256 = new SHA256Managed(); return(new UInt256(sha256.ComputeDoubleHash(DataEncoder.EncodeBlockHeader(Version, PreviousBlock, MerkleRoot, Time, Bits, Nonce)))); }
public static UInt256 CalculateBlockHash(BlockHeader blockHeader) { var sha256 = new SHA256Managed(); return(new UInt256(sha256.ComputeDoubleHash(DataEncoder.EncodeBlockHeader(blockHeader)))); }
private void TestRollback(ITestStorageProvider provider) { var logger = LogManager.CreateNullLogger(); var sha256 = new SHA256Managed(); var blockProvider = new MainnetBlockProvider(); var blocks = Enumerable.Range(0, 500).Select(x => blockProvider.GetBlock(x)).ToList(); var genesisBlock = blocks[0]; var genesisHeader = new ChainedHeader(genesisBlock.Header, height: 0, totalWork: 0); var genesisChain = Chain.CreateForGenesisBlock(genesisHeader); var rules = new MainnetRules(logger); using (var storageManager = provider.OpenStorageManager()) using (var coreStorage = new CoreStorage(storageManager, logger)) using (var chainStateBuilder = new ChainStateBuilder(logger, rules, coreStorage)) { // add blocks to storage coreStorage.AddGenesisBlock(ChainedHeader.CreateForGenesisBlock(blocks[0].Header)); foreach (var block in blocks) { coreStorage.TryAddBlock(block); } // calculate utxo forward and store its state at each step along the way var expectedUtxos = new List <List <UnspentTx> >(); for (var blockIndex = 0; blockIndex < blocks.Count; blockIndex++) { var block = blocks[blockIndex]; var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0); chainStateBuilder.AddBlock(chainedHeader, block.Transactions); using (var chainState = chainStateBuilder.ToImmutable()) { expectedUtxos.Add(chainState.ReadUnspentTransactions().ToList()); } } // verify the utxo state before rolling back //TODO verify the UTXO hash hard-coded here is correct var expectedUtxoHash = UInt256.Parse("609eb5882e0b71a707fb876c844fbfe6b4579e04eb27c7c0cefbb7478bac737b", NumberStyles.HexNumber); using (var utxoStream = new UtxoStream(logger, expectedUtxos.Last())) { var utxoHash = new UInt256(sha256.ComputeDoubleHash(utxoStream)); Assert.AreEqual(expectedUtxoHash, utxoHash); } expectedUtxos.RemoveAt(expectedUtxos.Count - 1); // roll utxo backwards and validate its state at each step along the way for (var blockIndex = blocks.Count - 1; blockIndex >= 1; blockIndex--) { var block = blocks[blockIndex]; var chainedHeader = new ChainedHeader(block.Header, blockIndex, 0); var blockTxes = block.Transactions.Select((tx, txIndex) => new BlockTx(txIndex, 0, tx.Hash, /*pruned:*/ false, tx)); chainStateBuilder.RollbackBlock(chainedHeader, blockTxes); var expectedUtxo = expectedUtxos.Last(); expectedUtxos.RemoveAt(expectedUtxos.Count - 1); List <UnspentTx> actualUtxo; using (var chainState = chainStateBuilder.ToImmutable()) { actualUtxo = chainState.ReadUnspentTransactions().ToList(); } CollectionAssert.AreEqual(expectedUtxo, actualUtxo, "UTXO differs at height: {0}".Format2(blockIndex)); } } }
public CoreDaemon(Logger logger, IKernel kernel, IBlockchainRules rules, BlockHeaderCache blockHeaderCache, ChainedHeaderCache chainedHeaderCache, BlockTxHashesCache blockTxHashesCache, TransactionCache transactionCache, BlockCache blockCache) { this.logger = logger; this.shutdownToken = new CancellationTokenSource(); this.kernel = kernel; this.rules = rules; this.blockHeaderCache = blockHeaderCache; this.chainedHeaderCache = chainedHeaderCache; this.blockTxHashesCache = blockTxHashesCache; this.transactionCache = transactionCache; this.blockCache = blockCache; // write genesis block out to storage this.blockHeaderCache[this.rules.GenesisBlock.Hash] = this.rules.GenesisBlock.Header; this.blockCache[this.rules.GenesisBlock.Hash] = this.rules.GenesisBlock; this.chainedHeaderCache[this.rules.GenesisChainedHeader.Hash] = this.rules.GenesisChainedHeader; // wire up cache events this.blockHeaderCache.OnAddition += OnBlockHeaderAddition; this.blockHeaderCache.OnModification += OnBlockHeaderModification; this.blockCache.OnAddition += OnBlockAddition; this.blockCache.OnModification += OnBlockModification; this.blockTxHashesCache.OnAddition += OnBlockTxHashesAddition; this.blockTxHashesCache.OnModification += OnBlockTxHashesModification; this.chainedHeaderCache.OnAddition += OnChainedHeaderAddition; this.chainedHeaderCache.OnModification += OnChainedHeaderModification; // create chain state builder this.chainStateBuilder = this.kernel.Get <ChainStateBuilder>( new ConstructorArgument("chain", Chain.CreateForGenesisBlock(this.rules.GenesisChainedHeader).ToBuilder()), new ConstructorArgument("parentUtxo", Utxo.CreateForGenesisBlock(this.rules.GenesisBlock.Hash))); this.chainStateLock = new ReaderWriterLockSlim(); // create workers this.chainingWorker = kernel.Get <ChainingWorker>( new ConstructorArgument("workerConfig", new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromSeconds(0), maxIdleTime: TimeSpan.FromSeconds(30)))); this.targetChainWorker = kernel.Get <TargetChainWorker>( new ConstructorArgument("workerConfig", new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.FromSeconds(0), maxIdleTime: TimeSpan.FromSeconds(30)))); this.chainStateWorker = kernel.Get <ChainStateWorker>( new ConstructorArgument("workerConfig", new WorkerConfig(initialNotify: true, minIdleTime: TimeSpan.Zero, maxIdleTime: TimeSpan.FromSeconds(5))), new ConstructorArgument("getTargetChain", (Func <Chain>)(() => this.targetChainWorker.TargetChain)), new ConstructorArgument("targetChainWorker", this.targetChainWorker), new ConstructorArgument("chainStateBuilder", this.chainStateBuilder)); this.targetChainWorker.OnTargetBlockChanged += () => { var handler = this.OnTargetBlockChanged; if (handler != null) { handler(this, EventArgs.Empty); } }; this.targetChainWorker.OnTargetChainChanged += () => { this.chainStateWorker.NotifyWork(); var handler = this.OnTargetChainChanged; if (handler != null) { handler(this, EventArgs.Empty); } }; this.chainStateWorker.OnChainStateChanged += () => { this.utxoScanWorker.NotifyWork(); //TODO once fully synced, this should save off the immutable snapshot immediately //TODO this will allow there to always be an active chain state once synced this.chainStateLock.DoWrite(() => this.chainState = null); var handler = this.OnChainStateChanged; if (handler != null) { handler(this, EventArgs.Empty); } }; this.gcWorker = new WorkerMethod("GC Worker", () => { this.logger.Info( string.Join("\n", new string('-', 80), "GC Memory: {0,10:#,##0.00} MB", "Process Memory: {1,10:#,##0.00} MB", new string('-', 80) ) .Format2 ( /*0*/ (float)GC.GetTotalMemory(false) / 1.MILLION(), /*1*/ (float)Process.GetCurrentProcess().PrivateMemorySize64 / 1.MILLION() )); }, initialNotify: true, minIdleTime: TimeSpan.FromSeconds(30), maxIdleTime: TimeSpan.FromSeconds(30), logger: this.logger); this.utxoScanWorker = new WorkerMethod("UTXO Scan Worker", () => { var chainStateLocal = this.GetChainState(); if (chainStateLocal == null) { return; } new MethodTimer().Time("Full UTXO Scan: {0:#,##0}".Format2(chainStateLocal.Utxo.OutputCount), () => { var sha256 = new SHA256Managed(); foreach (var output in chainStateLocal.Utxo.GetUnspentOutputs()) { if (new UInt256(sha256.ComputeDoubleHash(output.Value.ScriptPublicKey.ToArray())) == UInt256.Zero) { } } }); }, initialNotify: true, minIdleTime: TimeSpan.Zero, maxIdleTime: TimeSpan.MaxValue, logger: this.logger); }
public static UInt32 CalculatePayloadChecksum(byte[] payload) { var sha256 = new SHA256Managed(); return(Bits.ToUInt32(sha256.ComputeDoubleHash(payload).Take(4).ToArray())); }