diff --git a/opcode_test.go b/opcode_test.go index b3ce43d28..298292c51 100644 --- a/opcode_test.go +++ b/opcode_test.go @@ -542,6 +542,8 @@ type detailedTest struct { altafter [][]byte disassembly string disassemblyerr error + nSigOps int // should have same return as disassembly error + nPreciseSigOps int // should have same return as disassembly error } var detailedTests = []detailedTest{ @@ -2115,12 +2117,16 @@ var detailedTests = []detailedTest{ script: []byte{btcscript.OP_1, btcscript.OP_CHECKSIG}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "OP_1 OP_CHECKSIG", + nSigOps: 1, + nPreciseSigOps: 1, }, { name: "OP_CHECKSIG no arg", script: []byte{btcscript.OP_CHECKSIG}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "OP_CHECKSIG", + nSigOps: 1, + nPreciseSigOps: 1, }, { name: "OP_CHECKSIGVERIFY one arg", @@ -2128,18 +2134,24 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECKSIGVERIFY}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "OP_1 OP_CHECKSIGVERIFY", + nSigOps: 1, + nPreciseSigOps: 1, }, { name: "OP_CHECKSIGVERIFY no arg", script: []byte{btcscript.OP_CHECKSIGVERIFY}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "OP_CHECKSIGVERIFY", + nSigOps: 1, + nPreciseSigOps: 1, }, { name: "OP_CHECK_MULTISIG no args", script: []byte{btcscript.OP_CHECK_MULTISIG}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "OP_CHECK_MULTISIG", + nSigOps: 20, + nPreciseSigOps: 20, }, { name: "OP_CHECK_MULTISIG huge number", @@ -2148,6 +2160,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECK_MULTISIG}, expectedReturn: btcscript.StackErrNumberTooBig, disassembly: "010203040506070809 OP_CHECK_MULTISIG", + nSigOps: 20, + nPreciseSigOps: 20, }, { name: "OP_CHECK_MULTISIG too many keys", @@ -2155,6 +2169,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECK_MULTISIG}, expectedReturn: btcscript.StackErrTooManyPubkeys, disassembly: "15 OP_CHECK_MULTISIG", + nSigOps: 20, + nPreciseSigOps: 20, }, { name: "OP_CHECK_MULTISIG lying about pubkeys", @@ -2162,6 +2178,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECK_MULTISIG}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "OP_1 OP_CHECK_MULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, }, { // pubkey comes from blockchain @@ -2180,6 +2198,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECK_MULTISIG}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_1 OP_CHECK_MULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, }, { // pubkey comes from blockchain @@ -2200,6 +2220,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECK_MULTISIG}, expectedReturn: btcscript.StackErrNumberTooBig, disassembly: "010203040506070809 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_1 OP_CHECK_MULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, }, { name: "OP_CHECK_MULTISIG too few sigs", @@ -2217,6 +2239,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECK_MULTISIG}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "OP_1 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_1 OP_CHECK_MULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, }, { // pubkey and sig comes from blockchain, are unrelated @@ -2245,6 +2269,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECK_MULTISIG}, after: [][]byte{{0}}, disassembly: "OP_1 304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901 OP_1 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_1 OP_CHECK_MULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, }, { // invalid pubkey means that it fails to validate, not an @@ -2266,6 +2292,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECK_MULTISIG}, after: [][]byte{{0}}, disassembly: "OP_1 304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901 OP_1 OP_1 OP_1 OP_CHECK_MULTISIG", + nSigOps: 20, + nPreciseSigOps: 1, }, // XXX(oga) Test multisig when extra arg is missing. needs valid sig. // disabled opcodes @@ -2274,6 +2302,8 @@ var detailedTests = []detailedTest{ script: []byte{btcscript.OP_CHECKMULTISIGVERIFY}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 20, }, { name: "OP_CHECKMULTISIGVERIFY huge number", @@ -2282,6 +2312,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECKMULTISIGVERIFY}, expectedReturn: btcscript.StackErrNumberTooBig, disassembly: "010203040506070809 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 20, }, { name: "OP_CHECKMULTISIGVERIFY too many keys", @@ -2289,6 +2321,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECKMULTISIGVERIFY}, expectedReturn: btcscript.StackErrTooManyPubkeys, disassembly: "15 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 20, }, { name: "OP_CHECKMULTISIGVERIFY lying about pubkeys", @@ -2296,6 +2330,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECKMULTISIGVERIFY}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "OP_1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, }, { // pubkey comes from blockchain @@ -2314,6 +2350,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECKMULTISIGVERIFY}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, }, { name: "OP_CHECKMULTISIGVERIFY sigs huge no", @@ -2333,6 +2371,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECKMULTISIGVERIFY}, expectedReturn: btcscript.StackErrNumberTooBig, disassembly: "010203040506070809 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, }, { name: "OP_CHECKMULTISIGVERIFY too few sigs", @@ -2350,6 +2390,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECKMULTISIGVERIFY}, expectedReturn: btcscript.StackErrUnderflow, disassembly: "OP_1 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, }, { // pubkey and sig comes from blockchain, are unrelated @@ -2378,6 +2420,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECKMULTISIGVERIFY}, expectedReturn: btcscript.StackErrVerifyFailed, disassembly: "OP_1 304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901 OP_1 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, }, { // invalid pubkey means that it fails to validate, not an @@ -2399,6 +2443,8 @@ var detailedTests = []detailedTest{ btcscript.OP_CHECKMULTISIGVERIFY}, expectedReturn: btcscript.StackErrVerifyFailed, disassembly: "OP_1 304402204e45e16932b8af514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5fb8cd410220181522ec8eca07de4860a4acdd12909d831cc56cbbac4622082221a8768d1d0901 OP_1 OP_1 OP_1 OP_CHECKMULTISIGVERIFY", + nSigOps: 20, + nPreciseSigOps: 1, }, { // 201 operations + one push, should just fit limits @@ -3032,6 +3078,8 @@ var detailedTests = []detailedTest{ }, expectedReturn: btcscript.StackErrTooManyOperations, disassembly: "OP_1 OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_DUP OP_DROP OP_1 OP_1 OP_1 OP_1 OP_2 OP_CHECK_MULTISIG", + nSigOps: 20, + nPreciseSigOps: 2, }, { name: "OP_CAT disabled", @@ -3735,3 +3783,65 @@ func TestDisasmStrings(t *testing.T) { testDisasmString(t, &detailedTests[i]) } } + +// A basic test of GetSigOpCount for most opcodes, we do this by +// running the same test for every one of the detailed tests. Since +// disassembly errors are always parse errors, and so are +// sigops count errors we use the same error code. +// While this isn't as precise as using full transaction scripts, this gives +// us coverage over a wider range of opcodes. +func TestSigOps(t *testing.T) { + for _, test := range detailedTests { + count, err := btcscript.GetSigOpCount(test.script) + if err != nil { + if err != test.disassemblyerr { + t.Errorf("%s: unexpected error. exp \"%v\""+ + "got \"%v\"", test.name, + test.disassemblyerr, err) + } + continue + } + if test.disassemblyerr != nil { + t.Errorf("%s: no error when expected \"%v\"", + test.name, test.disassemblyerr) + continue + } + if count != test.nSigOps { + t.Errorf("%s: expected count of %d, got %d", test.name, + test.nSigOps, count) + + } + } +} + +// A basic test of GetPreciseSigOpCount for most opcodes, we do this by +// running the same test for every one of the detailed tests with a fake +// sigscript. Sicne disassembly errors are always parse errors, and so are +// sigops count errors we use the same error code. +// While this isn't as precise as using full transaction scripts, this gives +// us coverage over a wider range of opcodes. See script_test.go for tests +// using real transactions to provide a bit more coverage. +func TestPreciseSigOps(t *testing.T) { + for _, test := range detailedTests { + count, err := btcscript.GetPreciseSigOpCount( + []byte{btcscript.OP_1}, test.script, false) + if err != nil { + if err != test.disassemblyerr { + t.Errorf("%s: unexpected error. exp \"%v\""+ + "got \"%v\"", test.name, + test.disassemblyerr, err) + } + continue + } + if test.disassemblyerr != nil { + t.Errorf("%s: no error when expected \"%v\"", + test.name, test.disassemblyerr) + continue + } + if count != test.nPreciseSigOps { + t.Errorf("%s: expected count of %d, got %d", test.name, + test.nPreciseSigOps, count) + + } + } +} diff --git a/script.go b/script.go index 8a1bf6044..8fc9e3dc7 100644 --- a/script.go +++ b/script.go @@ -715,3 +715,87 @@ func (s *Script) GetAltStack() [][]byte { func (s *Script) SetAltStack(data [][]byte) { setStack(&s.astack, data) } + +// GetSigOpCount provides a quick count of the number of signature operations +// in a script. a CHECKSIG operations counts for 1, and a CHECK_MULTISIG for 20. +func GetSigOpCount(script [] byte) (int, error) { + pops, err := parseScript(script) + if err != nil { + return 0, err + } + + return getSigOpCount(pops, false), nil +} + +// GetPreciseSigOpCount returns the number of signature operations in +// scriptPubKey. If bip16 is true then scriptSig may be searched for the +// Pay-To-Script-Hash script in order to find the precise number of signature +// operations in the transaction. +func GetPreciseSigOpCount(scriptSig, scriptPubKey []byte, bip16 bool) (int, error) { + pops, err := parseScript(scriptPubKey) + if err != nil { + return 0, err + } + // non P2SH transactions just treated as normal. + if !(bip16 && isScriptHash(pops)) { + return getSigOpCount(pops, true), nil + } + + // Ok so this is P2SH, get the contained script and count it.. + + sigPops, err := parseScript(scriptSig) + if err != nil { + return 0, err + } + if !isPushOnly(sigPops) || len(sigPops) == 0 { + return 0, nil + } + + shScript := sigPops[len(sigPops) - 1].data + // Means that sigPops is jus OP_1 - OP_16, no sigops there. + if shScript == nil { + return 0, nil + } + + shPops, err := parseScript(shScript) + if err != nil { + return 0, err + } + + return getSigOpCount(shPops, true), nil +} + +// getSigOpCount is the implementation function for counting the number of +// signature operations in the script provided by pops. If precise mode is +// requested then we attempt to count the number of operations for a multisig +// op. Otherwise we use the maximum. +func getSigOpCount(pops []parsedOpcode, precise bool) int { + nSigs := 0 + for i, pop := range pops { + switch pop.opcode.value { + case OP_CHECKSIG: + fallthrough; + case OP_CHECKSIGVERIFY: + nSigs++ + case OP_CHECK_MULTISIG: + fallthrough; + case OP_CHECKMULTISIGVERIFY: + // If we are being precise then look for familiar + // patterns for multisig, for now all we recognise is + // OP_1 - OP_16 to signify the number of pubkeys. + // Otherwise, we use the max of 20. + if precise && i > 0 && + pops[i - 1].opcode.value >= OP_1 && + pops[i - 1].opcode.value <= OP_16 { + nSigs += int(pops[i-1].opcode.value - + (OP_1 - 1)) + } else { + nSigs += MaxPubKeysPerMultiSig + } + default: + // not a sigop. + } + } + + return nSigs +} diff --git a/script_test.go b/script_test.go index 8e887f8ef..45f1029f3 100644 --- a/script_test.go +++ b/script_test.go @@ -19,6 +19,7 @@ type txTest struct { bip16 bool err error shouldFail bool + nSigOps int } var txTests = []txTest{ @@ -121,6 +122,7 @@ var txTests = []txTest{ 0x12, 0xa3, btcscript.OP_CHECKSIG, }, idx: 0, + nSigOps: 1, }, // Previous test with the value of one output changed. txTest{ @@ -221,6 +223,7 @@ var txTests = []txTest{ }, idx: 0, err: btcscript.StackErrScriptFailed, + nSigOps: 1, }, txTest{ name: "CheckSig invalid signature", @@ -322,6 +325,7 @@ var txTests = []txTest{ }, idx: 0, shouldFail: true, + nSigOps: 1, }, txTest{ name: "CheckSig invalid pubkey", @@ -422,6 +426,7 @@ var txTests = []txTest{ }, idx: 0, shouldFail: true, + nSigOps: 1, }, // tx 599e47a8114fe098103663029548811d2651991b62397e057f0c863c2bc9f9ea // uses checksig with SigHashNone. @@ -523,6 +528,7 @@ var txTests = []txTest{ }, idx: 0, bip16: true, // after threshold + nSigOps: 1, }, // tx 51bf528ecf3c161e7c021224197dbe84f9a8564212f6207baa014c01a1668e1e // first instance of an AnyoneCanPay signature in the blockchain @@ -646,6 +652,7 @@ var txTests = []txTest{ }, idx: 0, bip16: true, // after threshold + nSigOps: 1, }, // tx 6d36bc17e947ce00bb6f12f8e7a56a1585c5a36188ffa2b05e10b4743273a74b // Uses OP_CODESEPARATOR and OP_CHECKMULTISIG @@ -768,6 +775,7 @@ var txTests = []txTest{ }, idx: 1, bip16: false, + nSigOps: 0, // multisig is in the pkScript! }, // same as previous but with one byte changed to make signature fail txTest{ @@ -890,6 +898,7 @@ var txTests = []txTest{ idx: 1, bip16: false, err: btcscript.StackErrScriptFailed, + nSigOps: 0, // multisig is in the pkScript! }, // tx e5779b9e78f9650debc2893fd9636d827b26b4ddfa6a8172fe8708c924f5c39d // First P2SH transaction in the blockchain @@ -948,6 +957,7 @@ var txTests = []txTest{ }, idx: 0, bip16: true, + nSigOps: 0, // no signature ops in the pushed script. }, } @@ -990,6 +1000,25 @@ func TestTX(t *testing.T) { } } +func TestGetPreciseSignOps(t *testing.T) { + for _, test := range txTests { + count, err := btcscript.GetPreciseSigOpCount( + test.tx.TxIn[test.idx].SignatureScript, test.pkScript, + test.bip16) + // all tx currently parse + if err != nil { + t.Errorf("%s: unexpected error. got \"%v\"", + test.name, err) + continue + } + if count != test.nSigOps { + t.Errorf("%s: expected count of %d, got %d", test.name, + test.nSigOps, count) + + } + } +} + type removeOpcodeTest struct { name string before []byte diff --git a/test_coverage.txt b/test_coverage.txt index 34e69f395..3d71e0510 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -2,56 +2,57 @@ github.com/conformal/btcscript/stack.go asInt 100.00% (18/18) github.com/conformal/btcscript/stack.go fromInt 100.00% (14/14) github.com/conformal/btcscript/opcode.go opcodeWithin 100.00% (13/13) -github.com/conformal/btcscript/opcode.go parsedOpcode.bytes 100.00% (12/12) -github.com/conformal/btcscript/stack.go Stack.nipN 100.00% (12/12) github.com/conformal/btcscript/opcode.go parsedOpcode.print 100.00% (12/12) +github.com/conformal/btcscript/stack.go Stack.nipN 100.00% (12/12) +github.com/conformal/btcscript/opcode.go parsedOpcode.bytes 100.00% (12/12) github.com/conformal/btcscript/opcode.go opcodeIf 100.00% (11/11) github.com/conformal/btcscript/opcode.go opcodeNotIf 100.00% (11/11) +github.com/conformal/btcscript/stack.go Stack.Tuck 100.00% (10/10) +github.com/conformal/btcscript/script.go getSigOpCount 100.00% (10/10) +github.com/conformal/btcscript/opcode.go opcodeMax 100.00% (10/10) +github.com/conformal/btcscript/opcode.go opcodeMin 100.00% (10/10) +github.com/conformal/btcscript/opcode.go opcodeGreaterThanOrEqual 100.00% (10/10) github.com/conformal/btcscript/opcode.go opcodeLessThanOrEqual 100.00% (10/10) github.com/conformal/btcscript/opcode.go opcodeGreaterThan 100.00% (10/10) github.com/conformal/btcscript/opcode.go opcodeLessThan 100.00% (10/10) github.com/conformal/btcscript/opcode.go opcodeNumNotEqual 100.00% (10/10) +github.com/conformal/btcscript/opcode.go opcodeNumEqual 100.00% (10/10) github.com/conformal/btcscript/opcode.go opcodeBoolOr 100.00% (10/10) github.com/conformal/btcscript/opcode.go opcodeBoolAnd 100.00% (10/10) -github.com/conformal/btcscript/opcode.go opcodeNumEqual 100.00% (10/10) -github.com/conformal/btcscript/opcode.go opcodeMax 100.00% (10/10) -github.com/conformal/btcscript/stack.go Stack.Tuck 100.00% (10/10) -github.com/conformal/btcscript/opcode.go opcodeMin 100.00% (10/10) -github.com/conformal/btcscript/opcode.go opcodeGreaterThanOrEqual 100.00% (10/10) github.com/conformal/btcscript/stack.go Stack.RotN 100.00% (9/9) -github.com/conformal/btcscript/script.go DisasmString 100.00% (9/9) github.com/conformal/btcscript/stack.go Stack.SwapN 100.00% (9/9) github.com/conformal/btcscript/stack.go Stack.OverN 100.00% (9/9) -github.com/conformal/btcscript/opcode.go opcodeEqual 100.00% (8/8) +github.com/conformal/btcscript/script.go DisasmString 100.00% (9/9) github.com/conformal/btcscript/opcode.go opcodeAdd 100.00% (8/8) github.com/conformal/btcscript/opcode.go opcodeSub 100.00% (8/8) +github.com/conformal/btcscript/opcode.go opcodeEqual 100.00% (8/8) github.com/conformal/btcscript/stack.go Stack.DupN 100.00% (8/8) -github.com/conformal/btcscript/opcode.go opcodePick 100.00% (7/7) -github.com/conformal/btcscript/opcode.go opcodeNot 100.00% (7/7) github.com/conformal/btcscript/stack.go Stack.DropN 100.00% (7/7) github.com/conformal/btcscript/opcode.go opcode0NotEqual 100.00% (7/7) github.com/conformal/btcscript/opcode.go opcodeRoll 100.00% (7/7) -github.com/conformal/btcscript/opcode.go opcodeElse 100.00% (6/6) -github.com/conformal/btcscript/opcode.go opcodeIfDup 100.00% (6/6) -github.com/conformal/btcscript/opcode.go parsedOpcode.conditional 100.00% (6/6) +github.com/conformal/btcscript/opcode.go opcodePick 100.00% (7/7) +github.com/conformal/btcscript/opcode.go opcodeNot 100.00% (7/7) github.com/conformal/btcscript/opcode.go opcodeVerify 100.00% (6/6) +github.com/conformal/btcscript/opcode.go opcodeIfDup 100.00% (6/6) +github.com/conformal/btcscript/opcode.go opcodeElse 100.00% (6/6) +github.com/conformal/btcscript/opcode.go parsedOpcode.conditional 100.00% (6/6) github.com/conformal/btcscript/opcode.go opcodeHash256 100.00% (5/5) github.com/conformal/btcscript/script.go removeOpcode 100.00% (5/5) -github.com/conformal/btcscript/script.go removeOpcodeByData 100.00% (5/5) -github.com/conformal/btcscript/stack.go Stack.PickN 100.00% (5/5) -github.com/conformal/btcscript/opcode.go parsedOpcode.exec 100.00% (5/5) -github.com/conformal/btcscript/stack.go Stack.RollN 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeToAltStack 100.00% (5/5) +github.com/conformal/btcscript/script.go Script.validPC 100.00% (5/5) +github.com/conformal/btcscript/opcode.go opcodeNegate 100.00% (5/5) +github.com/conformal/btcscript/opcode.go opcodeHash160 100.00% (5/5) github.com/conformal/btcscript/opcode.go opcodeFromAltStack 100.00% (5/5) github.com/conformal/btcscript/opcode.go opcodeSha256 100.00% (5/5) github.com/conformal/btcscript/opcode.go opcodeRipemd160 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeNegate 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeHash160 100.00% (5/5) github.com/conformal/btcscript/opcode.go opcodeAbs 100.00% (5/5) -github.com/conformal/btcscript/script.go Script.validPC 100.00% (5/5) +github.com/conformal/btcscript/opcode.go opcodeToAltStack 100.00% (5/5) +github.com/conformal/btcscript/opcode.go opcodeSize 100.00% (5/5) github.com/conformal/btcscript/opcode.go opcode1Add 100.00% (5/5) github.com/conformal/btcscript/opcode.go opcode1Sub 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeSize 100.00% (5/5) +github.com/conformal/btcscript/opcode.go parsedOpcode.exec 100.00% (5/5) +github.com/conformal/btcscript/stack.go Stack.PickN 100.00% (5/5) +github.com/conformal/btcscript/stack.go Stack.RollN 100.00% (5/5) +github.com/conformal/btcscript/script.go removeOpcodeByData 100.00% (5/5) github.com/conformal/btcscript/stack.go Stack.PeekBool 100.00% (4/4) github.com/conformal/btcscript/opcode.go opcodeEndif 100.00% (4/4) github.com/conformal/btcscript/opcode.go opcodeEqualVerify 100.00% (4/4) @@ -66,43 +67,47 @@ github.com/conformal/btcscript/script.go unparseScript 100.00% (4/4) github.com/conformal/btcscript/script.go Script.curPC 100.00% (4/4) github.com/conformal/btcscript/script.go Script.DisasmPC 100.00% (4/4) github.com/conformal/btcscript/script.go getStack 100.00% (4/4) +github.com/conformal/btcscript/script.go GetSigOpCount 100.00% (4/4) github.com/conformal/btcscript/stack.go fromBool 100.00% (3/3) +github.com/conformal/btcscript/script.go setStack 100.00% (3/3) github.com/conformal/btcscript/address.go ScriptType.String 100.00% (3/3) github.com/conformal/btcscript/script.go scriptUInt16 100.00% (3/3) -github.com/conformal/btcscript/script.go setStack 100.00% (3/3) github.com/conformal/btcscript/script.go scriptUInt8 100.00% (3/3) github.com/conformal/btcscript/script.go scriptUInt32 100.00% (3/3) -github.com/conformal/btcscript/stack.go Stack.NipN 100.00% (2/2) -github.com/conformal/btcscript/stack.go Stack.Depth 100.00% (2/2) -github.com/conformal/btcscript/opcode.go calcHash 100.00% (2/2) -github.com/conformal/btcscript/opcode.go opcodeDepth 100.00% (2/2) -github.com/conformal/btcscript/opcode.go opcodeN 100.00% (2/2) -github.com/conformal/btcscript/opcode.go opcodeCodeSeparator 100.00% (2/2) -github.com/conformal/btcscript/opcode.go opcode1Negate 100.00% (2/2) -github.com/conformal/btcscript/opcode.go opcodeFalse 100.00% (2/2) github.com/conformal/btcscript/opcode.go opcodePushData 100.00% (2/2) -github.com/conformal/btcscript/opcode.go opcodeNop 100.00% (1/1) -github.com/conformal/btcscript/opcode.go opcode3Dup 100.00% (1/1) +github.com/conformal/btcscript/opcode.go calcHash 100.00% (2/2) +github.com/conformal/btcscript/opcode.go opcodeCodeSeparator 100.00% (2/2) +github.com/conformal/btcscript/opcode.go opcodeDepth 100.00% (2/2) +github.com/conformal/btcscript/stack.go Stack.Depth 100.00% (2/2) +github.com/conformal/btcscript/opcode.go opcode1Negate 100.00% (2/2) +github.com/conformal/btcscript/stack.go Stack.NipN 100.00% (2/2) +github.com/conformal/btcscript/opcode.go opcodeN 100.00% (2/2) +github.com/conformal/btcscript/opcode.go opcodeFalse 100.00% (2/2) +github.com/conformal/btcscript/opcode.go init 100.00% (1/1) +github.com/conformal/btcscript/log.go newLogClosure 100.00% (1/1) +github.com/conformal/btcscript/stack.go Stack.PopByteArray 100.00% (1/1) github.com/conformal/btcscript/opcode.go calcHash160 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcode2Dup 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcode2Drop 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcodeReturn 100.00% (1/1) +github.com/conformal/btcscript/opcode.go opcodeNop 100.00% (1/1) +github.com/conformal/btcscript/opcode.go opcode3Dup 100.00% (1/1) github.com/conformal/btcscript/stack.go Stack.PushByteArray 100.00% (1/1) github.com/conformal/btcscript/stack.go Stack.PushInt 100.00% (1/1) -github.com/conformal/btcscript/opcode.go opcode2Over 100.00% (1/1) -github.com/conformal/btcscript/stack.go Stack.PopByteArray 100.00% (1/1) +github.com/conformal/btcscript/script.go Script.GetStack 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcodeInvalid 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcodeReserved 100.00% (1/1) -github.com/conformal/btcscript/opcode.go opcodeDisabled 100.00% (1/1) -github.com/conformal/btcscript/opcode.go init 100.00% (1/1) github.com/conformal/btcscript/script.go Script.SetStack 100.00% (1/1) +github.com/conformal/btcscript/opcode.go opcodeDisabled 100.00% (1/1) +github.com/conformal/btcscript/script.go Script.GetAltStack 100.00% (1/1) +github.com/conformal/btcscript/log.go UseLogger 100.00% (1/1) +github.com/conformal/btcscript/script.go Script.SetAltStack 100.00% (1/1) +github.com/conformal/btcscript/script.go isPubkey 100.00% (1/1) github.com/conformal/btcscript/script.go isPubkeyHash 100.00% (1/1) github.com/conformal/btcscript/script.go isScriptHash 100.00% (1/1) github.com/conformal/btcscript/log.go DisableLog 100.00% (1/1) -github.com/conformal/btcscript/script.go Script.GetAltStack 100.00% (1/1) -github.com/conformal/btcscript/log.go init 100.00% (1/1) -github.com/conformal/btcscript/script.go Script.SetAltStack 100.00% (1/1) github.com/conformal/btcscript/script.go Script.disasm 100.00% (1/1) +github.com/conformal/btcscript/log.go init 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcodeTuck 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcodeSwap 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcodeRot 100.00% (1/1) @@ -112,22 +117,20 @@ github.com/conformal/btcscript/opcode.go opcodeDup 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcodeDrop 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcode2Swap 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcode2Rot 100.00% (1/1) -github.com/conformal/btcscript/script.go Script.GetStack 100.00% (1/1) -github.com/conformal/btcscript/log.go newLogClosure 100.00% (1/1) -github.com/conformal/btcscript/script.go isPubkey 100.00% (1/1) +github.com/conformal/btcscript/opcode.go opcode2Over 100.00% (1/1) github.com/conformal/btcscript/stack.go Stack.PushBool 100.00% (1/1) github.com/conformal/btcscript/script.go Script.subScript 100.00% (1/1) -github.com/conformal/btcscript/log.go UseLogger 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcodeCheckMultiSig 98.21% (55/56) github.com/conformal/btcscript/opcode.go opcodeCheckSig 96.15% (25/26) -github.com/conformal/btcscript/script.go NewScript 95.24% (20/21) github.com/conformal/btcscript/address.go ScriptToAddress 94.92% (56/59) +github.com/conformal/btcscript/script.go NewScript 94.74% (18/19) github.com/conformal/btcscript/script.go parseScript 93.75% (30/32) github.com/conformal/btcscript/script.go Script.Step 91.89% (34/37) github.com/conformal/btcscript/script.go typeOfScript 83.33% (5/6) github.com/conformal/btcscript/script.go Script.DisasmScript 80.00% (4/5) -github.com/conformal/btcscript/script.go isPushOnly 75.00% (3/4) +github.com/conformal/btcscript/script.go GetPreciseSigOpCount 77.78% (14/18) github.com/conformal/btcscript/opcode.go opcodeCheckSigVerify 75.00% (3/4) +github.com/conformal/btcscript/script.go isPushOnly 75.00% (3/4) github.com/conformal/btcscript/script.go Script.calcScriptHash 71.43% (25/35) github.com/conformal/btcscript/script.go Script.CheckErrorCondition 71.43% (10/14) github.com/conformal/btcscript/script.go isMultiSig 61.54% (8/13) @@ -135,5 +138,5 @@ github.com/conformal/btcscript/opcode.go opcodeSha1 60.00% (3/5) github.com/conformal/btcscript/script.go Script.Execute 44.44% (8/18) github.com/conformal/btcscript/log.go SetLogWriter 0.00% (0/7) github.com/conformal/btcscript/log.go logClosure.String 0.00% (0/1) -github.com/conformal/btcscript -------------------------- 93.98% (843/897) +github.com/conformal/btcscript -------------------------- 93.74% (869/927)