Add HasCanonicalPushes

Closes #6.

ok @davecgh
This commit is contained in:
David Hill 2014-02-20 00:05:35 -05:00 committed by Dave Collins
parent b8dc1b66e5
commit 61d270957e
2 changed files with 60 additions and 0 deletions

View file

@ -308,6 +308,41 @@ func IsPushOnlyScript(script []byte) bool {
return isPushOnly(pops) return isPushOnly(pops)
} }
// HasCanonicalPushes returns whether or not the passed script only contains
// canonical data pushes. A canonical data push one where the fewest number of
// bytes possible to encode the size of the data being pushed is used. This
// includes using the small integer opcodes for single byte data that can be
// represented directly.
func HasCanonicalPushes(script []byte) bool {
pops, err := parseScript(script)
if err != nil {
return false
}
for _, pop := range pops {
opcode := pop.opcode.value
data := pop.data
dataLen := len(pop.data)
if opcode > OP_16 {
continue
}
if opcode < OP_PUSHDATA1 && opcode > OP_0 && (dataLen == 1 && data[0] <= 16) {
return false
}
if opcode == OP_PUSHDATA1 && dataLen < OP_PUSHDATA1 {
return false
}
if opcode == OP_PUSHDATA2 && dataLen <= 0xff {
return false
}
if opcode == OP_PUSHDATA4 && dataLen <= 0xffff {
return false
}
}
return true
}
// GetScriptClass returns the class of the script passed. If the script does not // GetScriptClass returns the class of the script passed. If the script does not
// parse then NonStandardTy will be returned. // parse then NonStandardTy will be returned.
func GetScriptClass(script []byte) ScriptClass { func GetScriptClass(script []byte) ScriptClass {

View file

@ -15,6 +15,31 @@ import (
"testing" "testing"
) )
func TestStandardPushes(t *testing.T) {
for i := 0; i < 1000; i++ {
builder := btcscript.NewScriptBuilder()
builder.PushInt64(int64(i))
if result := btcscript.IsPushOnlyScript(builder.Script()); !result {
t.Errorf("StandardPushesTests IsPushOnlyScript test #%d failed: %x\n", i, builder.Script())
}
if result := btcscript.HasCanonicalPushes(builder.Script()); !result {
t.Errorf("StandardPushesTests HasCanonicalPushes test #%d failed: %x\n", i, builder.Script())
continue
}
}
for i := 0; i < 1000; i++ {
builder := btcscript.NewScriptBuilder()
builder.PushData(bytes.Repeat([]byte{0x49}, i))
if result := btcscript.IsPushOnlyScript(builder.Script()); !result {
t.Errorf("StandardPushesTests IsPushOnlyScript test #%d failed: %x\n", i, builder.Script())
}
if result := btcscript.HasCanonicalPushes(builder.Script()); !result {
t.Errorf("StandardPushesTests HasCanonicalPushes test #%d failed: %x\n", i, builder.Script())
continue
}
}
}
type txTest struct { type txTest struct {
name string name string
tx *btcwire.MsgTx tx *btcwire.MsgTx