Ejemplo n.º 1
0
        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
            }
        }
Ejemplo n.º 2
0
        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()));
        }
Ejemplo n.º 3
0
        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));
        }
Ejemplo n.º 4
0
        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);
        }
Ejemplo n.º 5
0
        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));
                }
            }
        }
Ejemplo n.º 6
0
        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());
            }
        }
Ejemplo n.º 7
0
        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))));
        }
Ejemplo n.º 8
0
        public static UInt256 CalculateTransactionHash(Transaction tx)
        {
            var sha256 = new SHA256Managed();

            return(new UInt256(sha256.ComputeDoubleHash(DataEncoder.EncodeTransaction(tx))));
        }
Ejemplo n.º 9
0
        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))));
        }
Ejemplo n.º 10
0
        public static UInt256 CalculateBlockHash(BlockHeader blockHeader)
        {
            var sha256 = new SHA256Managed();

            return(new UInt256(sha256.ComputeDoubleHash(DataEncoder.EncodeBlockHeader(blockHeader))));
        }
Ejemplo n.º 11
0
        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));
                        }
                    }
        }
Ejemplo n.º 12
0
        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);
        }
Ejemplo n.º 13
0
        public static UInt32 CalculatePayloadChecksum(byte[] payload)
        {
            var sha256 = new SHA256Managed();

            return(Bits.ToUInt32(sha256.ComputeDoubleHash(payload).Take(4).ToArray()));
        }