diff --git a/address.go b/address.go index 02eacc8a..7c652abf 100644 --- a/address.go +++ b/address.go @@ -91,7 +91,10 @@ func ScriptToAddress(script []byte) (ScriptType, string, error) { {ScriptStrange, scrNoAddr, 33, []pkbytes{{0, OP_DATA_32}}, false}, {ScriptStrange, scrNoAddr, 33, []pkbytes{{0, OP_HASH160}, {1, OP_DATA_20}, {22, OP_EQUAL}}, false}, } + return scriptToAddressTemplate(script, validformats) +} +func scriptToAddressTemplate(script []byte, validformats []pkformat) (ScriptType, string, error) { var format pkformat var success bool for _, format = range validformats { @@ -106,8 +109,8 @@ func ScriptToAddress(script []byte) (ScriptType, string, error) { success = true for _, pkbyte := range format.databytes { if pkbyte.off >= len(script) { - success = false - break + return ScriptUnknown, "Unknown", + StackErrInvalidAddrOffset } if script[pkbyte.off] != pkbyte.val { log.Tracef("off at byte %v %v %v", pkbyte.off, script[pkbyte.off], pkbyte.val) @@ -122,23 +125,22 @@ func ScriptToAddress(script []byte) (ScriptType, string, error) { } } - if success == false && len(script) > 1 { - // check for a few special case - if script[len(script)-1] == OP_CHECK_MULTISIG { - // Multisig ScriptPubKey - return ScriptStrange, "Unknown", nil - } - if script[0] == OP_0 && (len(script) <= 75 && byte(len(script)) == script[1]+2) { - // Multisig ScriptSig - return ScriptStrange, "Unknown", nil - } - if script[0] == OP_HASH160 && len(script) == 23 && script[22] == OP_EQUAL { - // Multisig ScriptSig - return ScriptStrange, "Unknown", nil - } - if script[0] == OP_DATA_36 && len(script) == 37 { - // Multisig ScriptSig - return ScriptStrange, "Unknown", nil + if success == false { + if len(script) > 1 { + // check for a few special case + if script[len(script)-1] == OP_CHECK_MULTISIG { + return ScriptStrange, "Unknown", nil + } + if script[0] == OP_0 && (len(script) <= 75 && byte(len(script)) == script[1]+2) { + return ScriptStrange, "Unknown", nil + } + if script[0] == OP_HASH160 && len(script) == 23 && script[22] == OP_EQUAL { + return ScriptStrange, "Unknown", nil + } + if script[0] == OP_DATA_36 && len(script) == 37 { + // Multisig ScriptSig + return ScriptStrange, "Unknown", nil + } } return ScriptUnknown, "Unknown", StackErrUnknownAddress @@ -175,7 +177,7 @@ func ScriptToAddress(script []byte) (ScriptType, string, error) { pubkey := script[1:34] abuf = calcHash160(pubkey) default: - log.Warnf("parsetype is %v", format.parsetype) + return ScriptUnknown, "Unknown", StackErrInvalidParseType } if abuf != nil { diff --git a/address_test.go b/address_test.go index d1f3f96a..a969dd60 100644 --- a/address_test.go +++ b/address_test.go @@ -170,6 +170,9 @@ var addressTests = []addressTest{ address: "Unknown", class: btcscript.ScriptStrange, }, + {script: []byte{}, + shouldFail: btcscript.StackErrUnknownAddress, + }, } func TestAddresses(t *testing.T) { diff --git a/internal_test.go b/internal_test.go index 239456df..9e282c66 100644 --- a/internal_test.go +++ b/internal_test.go @@ -4,6 +4,10 @@ package btcscript +import ( + "testing" +) + // this file is present to export some internal interfaces so that we can // test them reliably. @@ -49,3 +53,66 @@ func (s *Script) TstSetPC(script, off int) { s.scriptidx = script s.scriptoff = off } + +// Tests for internal error cases in ScriptToAddress. +// We pass bad format definitions to ScriptToAddrss to make sure the internal +// checks work correctly. This is located in internal_test.go and not address.go +// because of the ridiculous amount of internal types/constants that would +// otherwise need to be exported here. + +type pkformatTest struct { + name string + format pkformat + script []byte + ty ScriptType + err error +} + +var TstPkFormats = []pkformatTest{ + pkformatTest{ + name: "bad offset", + format: pkformat{ + addrtype: ScriptAddr, + parsetype: scrNoAddr, + length: 4, + databytes: []pkbytes{{0, OP_1}, {1, OP_2}, {2, + OP_3}, /* wrong - too long */ {9, OP_4}}, + allowmore: true, + }, + script: []byte{OP_1, OP_2, OP_3, OP_4}, + err: StackErrInvalidAddrOffset, + }, + pkformatTest{ + name: "Bad parsetype", + format: pkformat{ + addrtype: ScriptAddr, + parsetype: 8, // invalid type + length: 4, + databytes: []pkbytes{{0, OP_1}, {1, OP_2}, {2, + OP_3}, /* wrong - too long */ {3, OP_4}}, + allowmore: true, + }, + script: []byte{OP_1, OP_2, OP_3, OP_4}, + err: StackErrInvalidParseType, + }, +} + +func TestBadPkFormat(t *testing.T) { + for _, test := range TstPkFormats { + ty, addr, err := scriptToAddressTemplate(test.script, + []pkformat{test.format}) + if err != nil { + if err != test.err { + t.Errorf("%s got error \"%v\". Was expecrting "+ + "\"%v\"", test.name, err, test.err) + } + continue + } + if ty != test.ty { + t.Errorf("%s: unexpected type \"%s\". Wanted \"%s\" (addr %v)", + test.name, ty, test.ty, addr) + continue + } + } + +} diff --git a/script.go b/script.go index e3a7bfc9..11b64aa0 100644 --- a/script.go +++ b/script.go @@ -92,6 +92,14 @@ var StackErrEmptyStack = errors.New("Stack empty at end of execution") var StackErrP2SHNonPushOnly = errors.New("pay to script hash with non " + "pushonly input") +// StackErrInvalidParseType is an internal error returned from ScriptToAddress +// ony if the internal data tables are wrong. +var StackErrInvalidParseType = errors.New("internal error: invalid parsetype found") + +// StackErrInvalidAddrOffset is an internal error returned from ScriptToAddress +// ony if the internal data tables are wrong. +var StackErrInvalidAddrOffset = errors.New("internal error: invalid offset found") + // Bip16Activation is the timestamp where BIP0016 is valid to use in the // blockchain. To be used to determine if BIP0016 should be called for or not. // This timestamp corresponds to Sun Apr 1 00:00:00 UTC 2012. diff --git a/test_coverage.txt b/test_coverage.txt index 0b424aca..8e57caa9 100644 --- a/test_coverage.txt +++ b/test_coverage.txt @@ -1,61 +1,62 @@ +github.com/conformal/btcscript/address.go scriptToAddressTemplate 100.00% (58/58) github.com/conformal/btcscript/script.go Script.Step 100.00% (37/37) github.com/conformal/btcscript/script.go NewScript 100.00% (19/19) github.com/conformal/btcscript/stack.go asInt 100.00% (18/18) github.com/conformal/btcscript/script.go GetPreciseSigOpCount 100.00% (17/17) 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.print 100.00% (12/12) -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 opcodeIf 100.00% (11/11) +github.com/conformal/btcscript/opcode.go parsedOpcode.bytes 100.00% (12/12) +github.com/conformal/btcscript/opcode.go parsedOpcode.print 100.00% (12/12) github.com/conformal/btcscript/opcode.go opcodeNotIf 100.00% (11/11) -github.com/conformal/btcscript/opcode.go opcodeLessThanOrEqual 100.00% (10/10) +github.com/conformal/btcscript/opcode.go opcodeIf 100.00% (11/11) 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 opcodeBoolAnd 100.00% (10/10) -github.com/conformal/btcscript/opcode.go opcodeBoolOr 100.00% (10/10) -github.com/conformal/btcscript/stack.go Stack.Tuck 100.00% (10/10) github.com/conformal/btcscript/opcode.go opcodeNumEqual 100.00% (10/10) -github.com/conformal/btcscript/script.go getSigOpCount 100.00% (10/10) +github.com/conformal/btcscript/stack.go Stack.Tuck 100.00% (10/10) github.com/conformal/btcscript/opcode.go opcodeNumNotEqual 100.00% (10/10) github.com/conformal/btcscript/opcode.go opcodeLessThan 100.00% (10/10) github.com/conformal/btcscript/opcode.go opcodeGreaterThan 100.00% (10/10) -github.com/conformal/btcscript/stack.go Stack.RotN 100.00% (9/9) -github.com/conformal/btcscript/stack.go Stack.OverN 100.00% (9/9) +github.com/conformal/btcscript/script.go getSigOpCount 100.00% (10/10) +github.com/conformal/btcscript/opcode.go opcodeLessThanOrEqual 100.00% (10/10) +github.com/conformal/btcscript/opcode.go opcodeBoolOr 100.00% (10/10) +github.com/conformal/btcscript/opcode.go opcodeGreaterThanOrEqual 100.00% (10/10) +github.com/conformal/btcscript/opcode.go opcodeBoolAnd 100.00% (10/10) +github.com/conformal/btcscript/opcode.go opcodeMin 100.00% (10/10) 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.RotN 100.00% (9/9) +github.com/conformal/btcscript/stack.go Stack.OverN 100.00% (9/9) github.com/conformal/btcscript/opcode.go opcodeAdd 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 opcodeSub 100.00% (8/8) +github.com/conformal/btcscript/opcode.go opcodeRoll 100.00% (7/7) github.com/conformal/btcscript/stack.go Stack.DropN 100.00% (7/7) github.com/conformal/btcscript/opcode.go opcodePick 100.00% (7/7) -github.com/conformal/btcscript/opcode.go opcodeRoll 100.00% (7/7) -github.com/conformal/btcscript/opcode.go opcode0NotEqual 100.00% (7/7) github.com/conformal/btcscript/opcode.go opcodeNot 100.00% (7/7) +github.com/conformal/btcscript/opcode.go opcode0NotEqual 100.00% (7/7) +github.com/conformal/btcscript/opcode.go opcodeVerify 100.00% (6/6) +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 opcodeElse 100.00% (6/6) -github.com/conformal/btcscript/opcode.go opcodeVerify 100.00% (6/6) -github.com/conformal/btcscript/opcode.go opcodeFromAltStack 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeAbs 100.00% (5/5) github.com/conformal/btcscript/opcode.go opcode1Add 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeRipemd160 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeSha256 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeHash160 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeSize 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeHash256 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeToAltStack 100.00% (5/5) github.com/conformal/btcscript/stack.go Stack.PickN 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcode1Sub 100.00% (5/5) -github.com/conformal/btcscript/opcode.go opcodeNegate 100.00% (5/5) github.com/conformal/btcscript/stack.go Stack.RollN 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/script.go removeOpcodeByData 100.00% (5/5) -github.com/conformal/btcscript/script.go Script.validPC 100.00% (5/5) +github.com/conformal/btcscript/opcode.go opcode1Sub 100.00% (5/5) +github.com/conformal/btcscript/opcode.go opcodeNegate 100.00% (5/5) github.com/conformal/btcscript/script.go removeOpcode 100.00% (5/5) +github.com/conformal/btcscript/script.go Script.validPC 100.00% (5/5) +github.com/conformal/btcscript/opcode.go opcodeRipemd160 100.00% (5/5) +github.com/conformal/btcscript/opcode.go opcodeAbs 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 opcodeHash160 100.00% (5/5) +github.com/conformal/btcscript/opcode.go opcodeHash256 100.00% (5/5) +github.com/conformal/btcscript/opcode.go opcodeToAltStack 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) @@ -72,22 +73,22 @@ 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/script.go scriptUInt8 100.00% (3/3) -github.com/conformal/btcscript/script.go setStack 100.00% (3/3) -github.com/conformal/btcscript/stack.go fromBool 100.00% (3/3) -github.com/conformal/btcscript/script.go scriptUInt16 100.00% (3/3) -github.com/conformal/btcscript/script.go scriptUInt32 100.00% (3/3) github.com/conformal/btcscript/address.go ScriptType.String 100.00% (3/3) +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/script.go scriptUInt16 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.Depth 100.00% (2/2) github.com/conformal/btcscript/stack.go Stack.NipN 100.00% (2/2) github.com/conformal/btcscript/opcode.go calcHash 100.00% (2/2) -github.com/conformal/btcscript/opcode.go opcode1Negate 100.00% (2/2) github.com/conformal/btcscript/opcode.go opcodeDepth 100.00% (2/2) -github.com/conformal/btcscript/opcode.go opcodeCodeSeparator 100.00% (2/2) -github.com/conformal/btcscript/opcode.go opcodeN 100.00% (2/2) github.com/conformal/btcscript/opcode.go opcodePushData 100.00% (2/2) +github.com/conformal/btcscript/address.go ScriptToAddress 100.00% (2/2) +github.com/conformal/btcscript/opcode.go opcodeCodeSeparator 100.00% (2/2) github.com/conformal/btcscript/opcode.go opcodeFalse 100.00% (2/2) -github.com/conformal/btcscript/stack.go Stack.PushBool 100.00% (1/1) +github.com/conformal/btcscript/opcode.go opcodeN 100.00% (2/2) +github.com/conformal/btcscript/opcode.go opcode1Negate 100.00% (2/2) github.com/conformal/btcscript/script.go Script.subScript 100.00% (1/1) github.com/conformal/btcscript/opcode.go init 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcode2Over 100.00% (1/1) @@ -99,7 +100,7 @@ github.com/conformal/btcscript/script.go isScriptHash 100.00% (1/1) github.com/conformal/btcscript/opcode.go calcHash160 100.00% (1/1) github.com/conformal/btcscript/script.go Script.SetAltStack 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcode2Swap 100.00% (1/1) -github.com/conformal/btcscript/opcode.go opcodeRot 100.00% (1/1) +github.com/conformal/btcscript/opcode.go opcodeDisabled 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcode3Dup 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcode2Dup 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcode2Rot 100.00% (1/1) @@ -107,14 +108,14 @@ 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 opcode2Drop 100.00% (1/1) github.com/conformal/btcscript/stack.go Stack.PopByteArray 100.00% (1/1) +github.com/conformal/btcscript/opcode.go opcodeRot 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/script.go Script.GetStack 100.00% (1/1) github.com/conformal/btcscript/script.go Script.SetStack 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/script.go Script.disasm 100.00% (1/1) +github.com/conformal/btcscript/stack.go Stack.PushBool 100.00% (1/1) github.com/conformal/btcscript/log.go DisableLog 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) @@ -124,9 +125,9 @@ github.com/conformal/btcscript/opcode.go opcodeNip 100.00% (1/1) github.com/conformal/btcscript/log.go UseLogger 100.00% (1/1) github.com/conformal/btcscript/opcode.go opcodeOver 100.00% (1/1) github.com/conformal/btcscript/log.go init 100.00% (1/1) +github.com/conformal/btcscript/script.go Script.disasm 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/address.go ScriptToAddress 94.92% (56/59) github.com/conformal/btcscript/script.go parseScript 93.75% (30/32) github.com/conformal/btcscript/script.go typeOfScript 83.33% (5/6) github.com/conformal/btcscript/script.go Script.DisasmScript 80.00% (4/5) @@ -138,5 +139,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 -------------------------- 94.82% (878/926) +github.com/conformal/btcscript -------------------------- 95.15% (882/927)