public void test_IsStandard() { var coins = new TxOutRepository(); Transaction[] dummyTransactions = SetupDummyInputs(coins); Transaction t = new Transaction(); t.Inputs.Add(new TxIn()); t.Inputs[0].PrevOut.Hash = dummyTransactions[0].GetHash(); t.Inputs[0].PrevOut.N = 1; t.Inputs[0].ScriptSig = new Script(Op.GetPushOp(new byte[65])); t.Outputs.Add(new TxOut()); t.Outputs[0].Value = 90 * Money.CENT; Key key = new Key(true); var payToHash = new PayToPubkeyHashTemplate(); t.Outputs[0].ScriptPubKey = payToHash.GenerateScriptPubKey(key.PubKey.ID); Assert.True(StandardScripts.IsStandardTransaction(t)); t.Outputs[0].Value = 501; //dust Assert.True(!StandardScripts.IsStandardTransaction(t)); t.Outputs[0].Value = 601; // not dust Assert.True(StandardScripts.IsStandardTransaction(t)); t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_1; Assert.True(!StandardScripts.IsStandardTransaction(t)); // 40-byte TX_NULL_DATA (standard) t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN + ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); Assert.True(StandardScripts.IsStandardTransaction(t)); // 41-byte TX_NULL_DATA (non-standard) t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN + ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"); Assert.True(!StandardScripts.IsStandardTransaction(t)); // TX_NULL_DATA w/o PUSHDATA t.Outputs.Clear(); t.Outputs.Add(new TxOut()); t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN; Assert.True(StandardScripts.IsStandardTransaction(t)); // Only one TX_NULL_DATA permitted in all cases t.Outputs.Add(new TxOut()); t.Outputs.Add(new TxOut()); t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN + ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); t.Outputs[1].ScriptPubKey = new Script() + OpcodeType.OP_RETURN + ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); Assert.True(!StandardScripts.IsStandardTransaction(t)); t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN + ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); t.Outputs[1].ScriptPubKey = new Script() + OpcodeType.OP_RETURN; Assert.True(!StandardScripts.IsStandardTransaction(t)); t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN; t.Outputs[1].ScriptPubKey = new Script() + OpcodeType.OP_RETURN; Assert.True(!StandardScripts.IsStandardTransaction(t)); }
public void CanCompressScript2() { var payToHashTemplate = new PayToPubkeyHashTemplate(); var key = new Key(true); var script = payToHashTemplate.GenerateScriptPubKey(key.PubKey.ID); var compressed = script.ToCompressedRawScript(); Assert.Equal(21, compressed.Length); Assert.Equal(script.ToString(), new Script(compressed, true).ToString()); }
public void CanParseAndGeneratePayToPubKeyScript() { var payToPubHash = new PayToPubkeyHashTemplate(); var scriptPubKey = new Script("OP_DUP OP_HASH160 b72a6481ec2c2e65aa6bd9b42e213dce16fc6217 OP_EQUALVERIFY OP_CHECKSIG"); var pubKey = payToPubHash.ExtractScriptPubKeyParameters(scriptPubKey); Assert.Equal("b72a6481ec2c2e65aa6bd9b42e213dce16fc6217", pubKey.ToString()); var scriptSig = new Script("3044022064f45a382a15d3eb5e7fe72076eec4ef0f56fde1adfd710866e729b9e5f3383d02202720a895914c69ab49359087364f06d337a2138305fbc19e20d18da78415ea9301 0364bd4b02a752798342ed91c681a48793bb1c0853cbcd0b978c55e53485b8e27c"); var sigResult = payToPubHash.ExtractScriptSigParameters(scriptSig); Assert.Equal("3044022064f45a382a15d3eb5e7fe72076eec4ef0f56fde1adfd710866e729b9e5f3383d02202720a895914c69ab49359087364f06d337a2138305fbc19e20d18da78415ea9301", Encoders.Hex.EncodeData(sigResult.TransactionSignature.ToBytes())); Assert.Equal("0364bd4b02a752798342ed91c681a48793bb1c0853cbcd0b978c55e53485b8e27c", sigResult.PublicKey.ToString()); Assert.Equal(payToPubHash.GenerateScriptSig(sigResult.TransactionSignature, sigResult.PublicKey).ToString(), scriptSig.ToString()); Assert.Equal(payToPubHash.GenerateScriptPubKey(pubKey).ToString(), scriptPubKey.ToString()); }
public void CanCompressScript() { var payToHashTemplate = new PayToPubkeyHashTemplate(); var payToScriptTemplate = new PayToScriptHashTemplate(); var payToPubKeyTemplate = new PayToPubkeyTemplate(); var key = new Key(true); //Pay to pubkey hash (encoded as 21 bytes) var script = payToHashTemplate.GenerateScriptPubKey(key.PubKey.ID); AssertCompressed(script, 21); script = payToHashTemplate.GenerateScriptPubKey(key.PubKey.Decompress().ID); AssertCompressed(script, 21); //Pay to script hash (encoded as 21 bytes) script = payToScriptTemplate.GenerateScriptPubKey(script); AssertCompressed(script, 21); //Pay to pubkey starting with 0x02, 0x03 or 0x04 (encoded as 33 bytes) script = payToPubKeyTemplate.GenerateScriptPubKey(key.PubKey); script = AssertCompressed(script, 33); var readenKey = payToPubKeyTemplate.ExtractScriptPubKeyParameters(script); AssertEx.CollectionEquals(readenKey.ToBytes(), key.PubKey.ToBytes()); script = payToPubKeyTemplate.GenerateScriptPubKey(key.PubKey.Decompress()); script = AssertCompressed(script, 33); readenKey = payToPubKeyTemplate.ExtractScriptPubKeyParameters(script); AssertEx.CollectionEquals(readenKey.ToBytes(), key.PubKey.Decompress().ToBytes()); //Other scripts up to 121 bytes require 1 byte + script length. script = new Script(Enumerable.Range(0, 60).Select(_ => (Op)OpcodeType.OP_RETURN).ToArray()); AssertCompressed(script, 61); script = new Script(Enumerable.Range(0, 120).Select(_ => (Op)OpcodeType.OP_RETURN).ToArray()); AssertCompressed(script, 121); //Above that, scripts up to 16505 bytes require 2 bytes + script length. script = new Script(Enumerable.Range(0, 122).Select(_ => (Op)OpcodeType.OP_RETURN).ToArray()); AssertCompressed(script, 124); }
public async Task <Transaction> GetTransaction(string id) { var tx = await _client.GetRawTransactionAsync(id); if (tx == null) { return(null); } var transaction = new Transaction { Blockhash = tx.Blockhash, TransactionId = tx.Txid, Size = tx.Size, TransactionIn = new List <In>(), TransactionsOut = new List <Out>(), }; // this fails b/c no input validation // Debug.Assert(id == transaction.TransactionId); int index = 0; foreach (var rpcIn in tx.Vin) { var inp = new In { Index = index }; if (rpcIn.Coinbase == null) { string hexScript = rpcIn.ScriptSig.Hex; byte[] decodedScript = Encoders.Hex.DecodeData(hexScript); Script script = new Script(decodedScript); PayToPubkeyHashTemplate template = new PayToPubkeyHashTemplate(); PayToPubkeyHashScriptSigParameters param = template.ExtractScriptSigParameters(script); if (param != null) { PubKey pubKey = param.PublicKey; BitcoinPubKeyAddress address = pubKey.GetAddress(NetworkSpec.ObsidianMain()); inp.Address = address.ToString(); } else { inp.Address = "none"; } inp.TransactionId = rpcIn.Txid; inp.VOut = (int)rpcIn.Vout; inp.Sequence = rpcIn.Sequence; inp.ScriptSigHex = rpcIn.ScriptSig.Hex; } else { inp.Coinbase = rpcIn.Coinbase; inp.Sequence = rpcIn.Sequence; } transaction.TransactionIn.Add(inp); } if (transaction.TransactionIn[0].Coinbase != null) { //Debug.Assert(transaction.TransactionIn.Count == 1); transaction.IsCoinBase = true; } index = 0; foreach (var output in tx.Vout) { var @out = new Out { TransactionId = transaction.TransactionId, Value = output.Value, Quantity = output.N, AssetId = null, Index = index++ }; if (output.ScriptPubKey.Addresses != null) // Satoshi 14.2 { @out.Address = output.ScriptPubKey.Addresses.FirstOrDefault(); } else { string hexScript = output.ScriptPubKey.Hex; if (!string.IsNullOrEmpty(hexScript)) { byte[] decodedScript = Encoders.Hex.DecodeData(hexScript); Script script = new Script(decodedScript); var pubKey = PayToPubkeyTemplate.Instance.ExtractScriptPubKeyParameters(script); BitcoinPubKeyAddress address = pubKey.GetAddress(NetworkSpec.ObsidianMain()); @out.Address = address.ToString(); } else { @out.Address = "none"; } } transaction.TransactionsOut.Add(@out); } return(transaction); }
public void test_IsStandard() { var coins = new CoinsView(); Transaction[] dummyTransactions = SetupDummyInputs(coins); Transaction t = new Transaction(); t.Inputs.Add(new TxIn()); t.Inputs[0].PrevOut.Hash = dummyTransactions[0].GetHash(); t.Inputs[0].PrevOut.N = 1; t.Inputs[0].ScriptSig = new Script(Op.GetPushOp(new byte[65])); t.Outputs.Add(new TxOut()); t.Outputs[0].Value = 90 * Money.CENT; Key key = new Key(true); var payToHash = new PayToPubkeyHashTemplate(); t.Outputs[0].ScriptPubKey = payToHash.GenerateScriptPubKey(key.PubKey.ID); Assert.True(StandardScripts.IsStandardTransaction(t)); t.Outputs[0].Value = 501; //dust Assert.True(!StandardScripts.IsStandardTransaction(t)); t.Outputs[0].Value = 601; // not dust Assert.True(StandardScripts.IsStandardTransaction(t)); t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_1; Assert.True(!StandardScripts.IsStandardTransaction(t)); // 40-byte TX_NULL_DATA (standard) t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN + ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); Assert.True(StandardScripts.IsStandardTransaction(t)); // 41-byte TX_NULL_DATA (non-standard) t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN + ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef3800"); Assert.True(!StandardScripts.IsStandardTransaction(t)); // TX_NULL_DATA w/o PUSHDATA t.Outputs.Clear(); t.Outputs.Add(new TxOut()); t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN; Assert.True(StandardScripts.IsStandardTransaction(t)); // Only one TX_NULL_DATA permitted in all cases t.Outputs.Add(new TxOut()); t.Outputs.Add(new TxOut()); t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN + ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); t.Outputs[1].ScriptPubKey = new Script() + OpcodeType.OP_RETURN + ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); Assert.True(!StandardScripts.IsStandardTransaction(t)); t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN + ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38"); t.Outputs[1].ScriptPubKey = new Script() + OpcodeType.OP_RETURN; Assert.True(!StandardScripts.IsStandardTransaction(t)); t.Outputs[0].ScriptPubKey = new Script() + OpcodeType.OP_RETURN; t.Outputs[1].ScriptPubKey = new Script() + OpcodeType.OP_RETURN; Assert.True(!StandardScripts.IsStandardTransaction(t)); }