WIP: next hard fork #5

Draft
BrannonKing wants to merge 178 commits from WIP-HF-2022 into master
4 changed files with 49 additions and 49 deletions
Showing only changes of commit da9fdabbd5 - Show all commits

View file

@ -875,6 +875,7 @@ func (vm *Engine) SetAltStack(data [][]byte) {
// engine according to the description provided by each flag. // engine according to the description provided by each flag.
func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags, func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags,
sigCache *SigCache, hashCache *TxSigHashes, inputAmount int64) (*Engine, error) { sigCache *SigCache, hashCache *TxSigHashes, inputAmount int64) (*Engine, error) {
const scriptVersion = 0
// The provided transaction input index must refer to a valid input. // The provided transaction input index must refer to a valid input.
if txIdx < 0 || txIdx >= len(tx.TxIn) { if txIdx < 0 || txIdx >= len(tx.TxIn) {
@ -994,7 +995,9 @@ func NewEngine(scriptPubKey []byte, tx *wire.MsgTx, txIdx int, flags ScriptFlags
// data push of the witness program, otherwise we // data push of the witness program, otherwise we
// reintroduce malleability. // reintroduce malleability.
sigPops := vm.scripts[0] sigPops := vm.scripts[0]
if len(sigPops) == 1 && canonicalPush(sigPops[0]) && if len(sigPops) == 1 &&
isCanonicalPush(sigPops[0].opcode.value,
sigPops[0].data) &&
IsWitnessProgram(sigPops[0].data) { IsWitnessProgram(sigPops[0].data) {
witProgram = sigPops[0].data witProgram = sigPops[0].data

View file

@ -128,7 +128,7 @@ func IsWitnessProgram(script []byte) bool {
func isWitnessProgram(pops []parsedOpcode) bool { func isWitnessProgram(pops []parsedOpcode) bool {
return len(pops) == 2 && return len(pops) == 2 &&
isSmallInt(pops[0].opcode.value) && isSmallInt(pops[0].opcode.value) &&
canonicalPush(pops[1]) && isCanonicalPush(pops[1].opcode.value, pops[1].data) &&
(len(pops[1].data) >= 2 && len(pops[1].data) <= 40) (len(pops[1].data) >= 2 && len(pops[1].data) <= 40)
} }
@ -305,13 +305,16 @@ func removeOpcode(pkscript []parsedOpcode, opcode byte) []parsedOpcode {
return retScript return retScript
} }
// canonicalPush returns true if the object is either not a push instruction // isCanonicalPush returns true if the opcode is either not a push instruction
// or the push instruction contained wherein is matches the canonical form // or the data associated with the push instruction uses the smallest
// or using the smallest instruction to do the job. False otherwise. // instruction to do the job. False otherwise.
func canonicalPush(pop parsedOpcode) bool { //
opcode := pop.opcode.value // For example, it is possible to push a value of 1 to the stack as "OP_1",
data := pop.data // "OP_DATA_1 0x01", "OP_PUSHDATA1 0x01 0x01", and others, however, the first
dataLen := len(pop.data) // only takes a single byte, while the rest take more. Only the first is
// considered canonical.
func isCanonicalPush(opcode byte, data []byte) bool {
dataLen := len(data)
if opcode > OP_16 { if opcode > OP_16 {
return true return true
} }
@ -336,7 +339,9 @@ func canonicalPush(pop parsedOpcode) bool {
func removeOpcodeByData(pkscript []parsedOpcode, data []byte) []parsedOpcode { func removeOpcodeByData(pkscript []parsedOpcode, data []byte) []parsedOpcode {
retScript := make([]parsedOpcode, 0, len(pkscript)) retScript := make([]parsedOpcode, 0, len(pkscript))
for _, pop := range pkscript { for _, pop := range pkscript {
if !canonicalPush(pop) || !bytes.Contains(pop.data, data) { if !isCanonicalPush(pop.opcode.value, pop.data) ||
!bytes.Contains(pop.data, data) {
retScript = append(retScript, pop) retScript = append(retScript, pop)
} }
} }

View file

@ -3740,31 +3740,25 @@ func TestPushedData(t *testing.T) {
} }
} }
// TestHasCanonicalPush ensures the canonicalPush function works as expected. // TestHasCanonicalPush ensures the isCanonicalPush function works as expected.
func TestHasCanonicalPush(t *testing.T) { func TestHasCanonicalPush(t *testing.T) {
t.Parallel() t.Parallel()
const scriptVersion = 0
for i := 0; i < 65535; i++ { for i := 0; i < 65535; i++ {
script, err := NewScriptBuilder().AddInt64(int64(i)).Script() script, err := NewScriptBuilder().AddInt64(int64(i)).Script()
if err != nil { if err != nil {
t.Errorf("Script: test #%d unexpected error: %v\n", i, t.Errorf("Script: test #%d unexpected error: %v\n", i, err)
err)
continue continue
} }
if result := IsPushOnlyScript(script); !result { if !IsPushOnlyScript(script) {
t.Errorf("IsPushOnlyScript: test #%d failed: %x\n", i, t.Errorf("IsPushOnlyScript: test #%d failed: %x\n", i, script)
script)
continue continue
} }
pops, err := parseScript(script) tokenizer := MakeScriptTokenizer(scriptVersion, script)
if err != nil { for tokenizer.Next() {
t.Errorf("parseScript: #%d failed: %v", i, err) if !isCanonicalPush(tokenizer.Opcode(), tokenizer.Data()) {
continue t.Errorf("isCanonicalPush: test #%d failed: %x\n", i, script)
}
for _, pop := range pops {
if result := canonicalPush(pop); !result {
t.Errorf("canonicalPush: test #%d failed: %x\n",
i, script)
break break
} }
} }
@ -3774,21 +3768,17 @@ func TestHasCanonicalPush(t *testing.T) {
builder.AddData(bytes.Repeat([]byte{0x49}, i)) builder.AddData(bytes.Repeat([]byte{0x49}, i))
script, err := builder.Script() script, err := builder.Script()
if err != nil { if err != nil {
t.Errorf("StandardPushesTests test #%d unexpected error: %v\n", i, err) t.Errorf("Script: test #%d unexpected error: %v\n", i, err)
continue continue
} }
if result := IsPushOnlyScript(script); !result { if !IsPushOnlyScript(script) {
t.Errorf("StandardPushesTests IsPushOnlyScript test #%d failed: %x\n", i, script) t.Errorf("IsPushOnlyScript: test #%d failed: %x\n", i, script)
continue continue
} }
pops, err := parseScript(script) tokenizer := MakeScriptTokenizer(scriptVersion, script)
if err != nil { for tokenizer.Next() {
t.Errorf("StandardPushesTests #%d failed to TstParseScript: %v", i, err) if !isCanonicalPush(tokenizer.Opcode(), tokenizer.Data()) {
continue t.Errorf("isCanonicalPush: test #%d failed: %x\n", i, script)
}
for _, pop := range pops {
if result := canonicalPush(pop); !result {
t.Errorf("StandardPushesTests TstHasCanonicalPushes test #%d failed: %x\n", i, script)
break break
} }
} }
@ -4213,11 +4203,13 @@ func TestIsPayToWitnessPubKeyHash(t *testing.T) {
} }
} }
// TestHasCanonicalPushes ensures the canonicalPush function properly determines // TestHasCanonicalPushes ensures the isCanonicalPush function properly
// what is considered a canonical push for the purposes of removeOpcodeByData. // determines what is considered a canonical push for the purposes of
// removeOpcodeByData.
func TestHasCanonicalPushes(t *testing.T) { func TestHasCanonicalPushes(t *testing.T) {
t.Parallel() t.Parallel()
const scriptVersion = 0
tests := []struct { tests := []struct {
name string name string
script string script string
@ -4236,20 +4228,20 @@ func TestHasCanonicalPushes(t *testing.T) {
}, },
} }
for i, test := range tests { for _, test := range tests {
script := mustParseShortForm(test.script) script := mustParseShortForm(test.script)
pops, err := parseScript(script) if err := checkScriptParses(scriptVersion, script); err != nil {
if err != nil {
if test.expected { if test.expected {
t.Errorf("TstParseScript #%d failed: %v", i, err) t.Errorf("%q: script parse failed: %v", test.name, err)
} }
continue continue
} }
for _, pop := range pops { tokenizer := MakeScriptTokenizer(scriptVersion, script)
if canonicalPush(pop) != test.expected { for tokenizer.Next() {
t.Errorf("canonicalPush: #%d (%s) wrong result"+ result := isCanonicalPush(tokenizer.Opcode(), tokenizer.Data())
"\ngot: %v\nwant: %v", i, test.name, if result != test.expected {
true, test.expected) t.Errorf("%q: isCanonicalPush wrong result\ngot: %v\nwant: %v",
test.name, result, test.expected)
break break
} }
} }

View file

@ -953,7 +953,7 @@ func ExtractAtomicSwapDataPushes(version uint16, pkScript []byte) (*AtomicSwapDa
} }
isAtomicSwap := pops[0].opcode.value == OP_IF && isAtomicSwap := pops[0].opcode.value == OP_IF &&
pops[1].opcode.value == OP_SIZE && pops[1].opcode.value == OP_SIZE &&
canonicalPush(pops[2]) && isCanonicalPush(pops[2].opcode.value, pops[2].data) &&
pops[3].opcode.value == OP_EQUALVERIFY && pops[3].opcode.value == OP_EQUALVERIFY &&
pops[4].opcode.value == OP_SHA256 && pops[4].opcode.value == OP_SHA256 &&
pops[5].opcode.value == OP_DATA_32 && pops[5].opcode.value == OP_DATA_32 &&
@ -962,7 +962,7 @@ func ExtractAtomicSwapDataPushes(version uint16, pkScript []byte) (*AtomicSwapDa
pops[8].opcode.value == OP_HASH160 && pops[8].opcode.value == OP_HASH160 &&
pops[9].opcode.value == OP_DATA_20 && pops[9].opcode.value == OP_DATA_20 &&
pops[10].opcode.value == OP_ELSE && pops[10].opcode.value == OP_ELSE &&
canonicalPush(pops[11]) && isCanonicalPush(pops[11].opcode.value, pops[11].data) &&
pops[12].opcode.value == OP_CHECKLOCKTIMEVERIFY && pops[12].opcode.value == OP_CHECKLOCKTIMEVERIFY &&
pops[13].opcode.value == OP_DROP && pops[13].opcode.value == OP_DROP &&
pops[14].opcode.value == OP_DUP && pops[14].opcode.value == OP_DUP &&