public void TestCreateCoinbaseAndSpend()
        {
            var keyPair = TransactionManager.CreateKeyPair();
            var privateKey = keyPair.Item1;
            var publicKey = keyPair.Item2;

            var coinbaseTx = TransactionManager.CreateCoinbaseTransaction(publicKey, Encoding.ASCII.GetBytes("coinbase text!"));

            var publicKeyScript = TransactionManager.CreatePublicKeyScript(publicKey);
            var privateKeyScript = TransactionManager.CreatePrivateKeyScript(coinbaseTx, 0, (byte)ScriptHashType.SIGHASH_ALL, privateKey, publicKey);

            var script = privateKeyScript.Concat(publicKeyScript);

            var scriptEngine = new ScriptEngine();
            Assert.IsTrue(scriptEngine.VerifyScript(0, 0, publicKeyScript.ToArray(), coinbaseTx, 0, script));
        }
示例#2
0
        public static byte[] CreatePrivateKeyScript(Transaction tx, int inputIndex, byte hashType, ECPrivateKeyParameters privateKey, ECPublicKeyParameters publicKey)
        {
            //TODO
            var scriptEngine = new ScriptEngine();

            var publicAddress = CreatePublicAddress(publicKey);
            var publicKeyScript = CreatePublicKeyScript(publicAddress);
            var txSignature = scriptEngine.TxSignature(publicKeyScript.ToImmutableArray(), tx, inputIndex, hashType);
            var txSignatureHash = Crypto.DoubleSHA256(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()));

            var privateKeyScript = new ScriptBuilder();
            privateKeyScript.WritePushData(sigEncoded);
            privateKeyScript.WritePushData(publicAddress);
            //Debug.WriteLine("Private Script: {0}".Format2(privateKeyScript.GetScript().ToHexDataString()));

            return privateKeyScript.GetScript();
        }
示例#3
0
        //TODO utxo needs to be as-at transaction, with regards to a transaction being fully spent and added back in in the same block
        public virtual void ValidateTransactionScripts(Block block, ImmutableDictionary<UInt256, UnspentTx> utxo, ImmutableDictionary<UInt256, ImmutableHashSet<int>> newTransactions)
        {
            if (BypassExecuteScript)
                return;

            // lookup all previous outputs
            var prevOutputMissing = false;
            var previousOutputs = new Dictionary<TxOutputKey, Tuple<Transaction, TxInput, int, TxOutput>>();
            for (var txIndex = 1; txIndex < block.Transactions.Length; txIndex++)
            {
                var tx = block.Transactions[txIndex];
                for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++)
                {
                    var input = tx.Inputs[inputIndex];

                    // find previous transaction
                    var prevTx = GetPreviousTransaction(block, txIndex, input.PreviousTxOutputKey, utxo, newTransactions);

                    // find previous transaction output
                    if (input.PreviousTxOutputKey.TxOutputIndex >= prevTx.Outputs.Length)
                        throw new ValidationException();
                    var prevOutput = prevTx.Outputs[input.PreviousTxOutputKey.TxOutputIndex.ToIntChecked()];

                    previousOutputs.Add(input.PreviousTxOutputKey, Tuple.Create(tx, input, inputIndex, prevOutput));
                }
            }

            if (prevOutputMissing)
            {
                throw new ValidationException();
            }

            var exceptions = new ConcurrentBag<Exception>();

            var scriptEngine = new ScriptEngine();

            Parallel.ForEach(previousOutputs.Values, (tuple, loopState) =>
            {
                try
                {
                    var tx = tuple.Item1;
                    var input = tuple.Item2;
                    var inputIndex = tuple.Item3;
                    var prevOutput = tuple.Item4;

                    // create the transaction script from the input and output
                    var script = input.ScriptSignature.AddRange(prevOutput.ScriptPublicKey);
                    if (!scriptEngine.VerifyScript(0 /*TODO blockHash*/, 0 /*TODO txIndex*/, prevOutput.ScriptPublicKey.ToArray(), tx, inputIndex, script.ToArray()))
                    {
                        exceptions.Add(new ValidationException());
                        loopState.Break();
                    }
                }
                catch (Exception e)
                {
                    exceptions.Add(e);
                    loopState.Break();
                }
            });

            if (exceptions.Count > 0)
                throw new AggregateException(exceptions.ToArray());
        }
示例#4
0
        private void TestTransactionVerifySignature(byte[] expectedHashTypes, byte[][] expectedSignatures, byte[][] expectedSignatureHashes, byte[][] expectedX, byte[][] expectedY, byte[][] expectedR, byte[][] expectedS, Transaction tx, IDictionary<UInt256, Transaction> txLookup)
        {
            var scriptEngine = new ScriptEngine();

            for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++)
            {
                var input = tx.Inputs[inputIndex];
                var prevOutput = txLookup[input.PreviousTxOutputKey.TxHash].Outputs[input.PreviousTxOutputKey.TxOutputIndex.ToIntChecked()];

                var hashType = GetHashTypeFromScriptSig(input.ScriptSignature);
                var sig = GetSigFromScriptSig(input.ScriptSignature);
                var pubKey = GetPubKeyFromScripts(input.ScriptSignature, prevOutput.ScriptPublicKey);

                byte[] txSignature, txSignatureHash; BigInteger x, y, r, s;
                var result = scriptEngine.VerifySignature(prevOutput.ScriptPublicKey, tx, sig.ToArray(), pubKey.ToArray(), inputIndex, out hashType, out txSignature, out txSignatureHash, out x, out y, out r, out s);

                Debug.WriteLine(hashType);
                Debug.WriteLine(txSignature.ToHexDataString());
                Debug.WriteLine(txSignatureHash.ToHexNumberString());
                Debug.WriteLine(x.ToHexNumberString());
                Debug.WriteLine(y.ToHexNumberString());
                Debug.WriteLine(r.ToHexNumberString());
                Debug.WriteLine(s.ToHexNumberString());

                Assert.AreEqual(expectedHashTypes[inputIndex], hashType);
                CollectionAssert.AreEqual(expectedSignatures[inputIndex].ToList(), txSignature.ToList());
                CollectionAssert.AreEqual(expectedSignatureHashes[inputIndex].ToList(), txSignatureHash.ToList());
                CollectionAssert.AreEqual(expectedX[inputIndex], x.ToByteArrayUnsigned());
                CollectionAssert.AreEqual(expectedY[inputIndex], y.ToByteArrayUnsigned());
                CollectionAssert.AreEqual(expectedR[inputIndex], r.ToByteArrayUnsigned());
                CollectionAssert.AreEqual(expectedS[inputIndex], s.ToByteArrayUnsigned());
                Assert.IsTrue(result);
            }
        }
示例#5
0
        private void TestTransactionVerifyScript(Transaction tx, IDictionary<UInt256, Transaction> txLookup)
        {
            var scriptEngine = new ScriptEngine();

            for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++)
            {
                var input = tx.Inputs[inputIndex];
                var prevOutput = txLookup[input.PreviousTxOutputKey.TxHash].Outputs[input.PreviousTxOutputKey.TxOutputIndex.ToIntChecked()];

                var script = GetScriptFromInputPrevOutput(input, prevOutput);

                var result = scriptEngine.VerifyScript(0 /*blockIndex*/, -1 /*txIndex*/, prevOutput.ScriptPublicKey.ToArray(), tx, inputIndex, script.ToArray());

                Assert.IsTrue(result);
            }
        }
示例#6
0
        private void TestTransactionSignature(byte[][] expectedSignatures, Transaction tx, IDictionary<UInt256, Transaction> txLookup)
        {
            var scriptEngine = new ScriptEngine();
            for (var inputIndex = 0; inputIndex < tx.Inputs.Length; inputIndex++)
            {
                var input = tx.Inputs[inputIndex];
                var prevOutput = txLookup[input.PreviousTxOutputKey.TxHash].Outputs[input.PreviousTxOutputKey.TxOutputIndex.ToIntChecked()];

                var hashType = GetHashTypeFromScriptSig(input.ScriptSignature);

                var actual = scriptEngine.TxSignature(prevOutput.ScriptPublicKey, tx, inputIndex, hashType);
                CollectionAssert.AreEqual(expectedSignatures[inputIndex].ToList(), actual.ToList());
            }
        }