github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/script/script_test.go (about)

     1  package script
     2  
     3  import (
     4  	//"os"
     5  	//"fmt"
     6  	"encoding/hex"
     7  	"encoding/json"
     8  	"errors"
     9  	"io/ioutil"
    10  	"strings"
    11  	"testing"
    12  
    13  	"github.com/piotrnar/gocoin/lib/btc"
    14  )
    15  
    16  type one_test_vector struct {
    17  	sigscr, pkscr []byte
    18  	flags         uint32
    19  	exp_res       bool
    20  	desc          string
    21  
    22  	witness [][]byte
    23  	value   uint64
    24  }
    25  
    26  func TestScritps(t *testing.T) {
    27  	var str interface{}
    28  	var vecs []*one_test_vector
    29  
    30  	DBG_ERR = false
    31  	dat, er := ioutil.ReadFile("../test/script_tests.json")
    32  	if er != nil {
    33  		t.Error(er.Error())
    34  		return
    35  	}
    36  	er = json.Unmarshal(dat, &str)
    37  	if er != nil {
    38  		t.Error(er.Error())
    39  		return
    40  	}
    41  
    42  	m := str.([]interface{})
    43  	for i := range m {
    44  		switch mm := m[i].(type) {
    45  		case []interface{}:
    46  			if len(mm) < 4 {
    47  				continue
    48  			}
    49  
    50  			var skip bool
    51  			var bfield int
    52  			var e error
    53  			var all_good bool
    54  
    55  			vec := new(one_test_vector)
    56  			for ii := range mm {
    57  				switch segwitdata := mm[ii].(type) {
    58  				case []interface{}:
    59  					for iii := range segwitdata {
    60  						switch segwitdata[iii].(type) {
    61  						case string:
    62  							var by []byte
    63  							s := segwitdata[iii].(string)
    64  							by, e = hex.DecodeString(s)
    65  							if e != nil {
    66  								t.Error("error parsing serwit script", s)
    67  								skip = true
    68  								break
    69  							}
    70  							vec.witness = append(vec.witness, by)
    71  
    72  						case float64:
    73  							vec.value = uint64(1e8 * segwitdata[iii].(float64))
    74  						}
    75  					}
    76  
    77  				case string:
    78  					s := mm[ii].(string)
    79  					if bfield == 0 {
    80  						vec.sigscr, e = btc.DecodeScript(s)
    81  						if e != nil {
    82  							t.Error("error parsing script", s)
    83  							skip = true
    84  							break
    85  						}
    86  					} else if bfield == 1 {
    87  						vec.pkscr, e = btc.DecodeScript(s)
    88  						if e != nil {
    89  							skip = true
    90  							break
    91  						}
    92  					} else if bfield == 2 {
    93  						vec.flags, e = decode_flags(s)
    94  						if e != nil {
    95  							println("error parsing flag", e.Error())
    96  							skip = true
    97  							break
    98  						}
    99  					} else if bfield == 3 {
   100  						vec.exp_res = s == "OK"
   101  						all_good = true
   102  					} else if bfield == 4 {
   103  						vec.desc = s
   104  						skip = true
   105  						break
   106  					}
   107  					bfield++
   108  
   109  				default:
   110  					panic("Unexpected test vector")
   111  				}
   112  				if skip {
   113  					break
   114  				}
   115  			}
   116  			if all_good {
   117  				vecs = append(vecs, vec)
   118  			}
   119  		}
   120  	}
   121  
   122  	tot := 0
   123  	for _, v := range vecs {
   124  		tot++
   125  
   126  		/*
   127  			if tot==114400 {
   128  				DBG_SCR = true
   129  				DBG_ERR = true
   130  			}*/
   131  
   132  		flags := v.flags
   133  		if (flags & VER_CLEANSTACK) != 0 {
   134  			flags |= VER_P2SH
   135  			flags |= VER_WITNESS
   136  		}
   137  
   138  		credit_tx := mk_credit_tx(v.pkscr, v.value)
   139  		spend_tx := mk_spend_tx(credit_tx, v.sigscr, v.witness)
   140  		spend_tx.Raw = spend_tx.SerializeNew()
   141  
   142  		if DBG_SCR {
   143  			println("desc:", v, tot, v.desc)
   144  			println("pkscr:", hex.EncodeToString(v.pkscr))
   145  			println("sigscr:", hex.EncodeToString(v.sigscr))
   146  			println("credit:", hex.EncodeToString(credit_tx.Serialize()))
   147  			println("spend:", hex.EncodeToString(spend_tx.Serialize()))
   148  			println("------------------------------ testing vector", tot, len(v.witness), v.value)
   149  		}
   150  		res := VerifyTxScript(v.pkscr, &SigChecker{Amount: v.value, Idx: 0, Tx: spend_tx}, flags)
   151  
   152  		if res != v.exp_res {
   153  			t.Error(tot, "TestScritps failed. Got:", res, "   exp:", v.exp_res, v.desc)
   154  			return
   155  		} else {
   156  			if DBG_SCR {
   157  				println(tot, "ok:", res, v.desc)
   158  			}
   159  		}
   160  
   161  		if tot == 114400 {
   162  			return
   163  		}
   164  	}
   165  }
   166  
   167  func decode_flags(s string) (fl uint32, e error) {
   168  	ss := strings.Split(s, ",")
   169  	for i := range ss {
   170  		switch ss[i] {
   171  		case "": // ignore
   172  		case "NONE": // ignore
   173  			break
   174  		case "P2SH":
   175  			fl |= VER_P2SH
   176  		case "STRICTENC":
   177  			fl |= VER_STRICTENC
   178  		case "DERSIG":
   179  			fl |= VER_DERSIG
   180  		case "LOW_S":
   181  			fl |= VER_LOW_S
   182  		case "NULLDUMMY":
   183  			fl |= VER_NULLDUMMY
   184  		case "SIGPUSHONLY":
   185  			fl |= VER_SIGPUSHONLY
   186  		case "MINIMALDATA":
   187  			fl |= VER_MINDATA
   188  		case "DISCOURAGE_UPGRADABLE_NOPS":
   189  			fl |= VER_BLOCK_OPS
   190  		case "CLEANSTACK":
   191  			fl |= VER_CLEANSTACK
   192  		case "CHECKLOCKTIMEVERIFY":
   193  			fl |= VER_CLTV
   194  		case "CHECKSEQUENCEVERIFY":
   195  			fl |= VER_CSV
   196  		case "WITNESS":
   197  			fl |= VER_WITNESS
   198  		case "DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM":
   199  			fl |= VER_WITNESS_PROG
   200  		case "MINIMALIF":
   201  			fl |= VER_MINIMALIF
   202  		case "NULLFAIL":
   203  			fl |= VER_NULLFAIL
   204  		case "WITNESS_PUBKEYTYPE":
   205  			fl |= VER_WITNESS_PUBKEY
   206  		case "CONST_SCRIPTCODE":
   207  			fl |= VER_CONST_SCRIPTCODE
   208  		case "TAPROOT":
   209  			fl |= VER_TAPROOT
   210  		default:
   211  			e = errors.New("Unsupported flag " + ss[i])
   212  			return
   213  		}
   214  	}
   215  	return
   216  }
   217  
   218  func mk_credit_tx(pk_scr []byte, value uint64) (input_tx *btc.Tx) {
   219  	// We build input_tx only to calculate it's hash for output_tx
   220  	input_tx = new(btc.Tx)
   221  	input_tx.Version = 1
   222  	input_tx.TxIn = []*btc.TxIn{{Input: btc.TxPrevOut{Vout: 0xffffffff},
   223  		ScriptSig: []byte{0, 0}, Sequence: 0xffffffff}}
   224  	input_tx.TxOut = []*btc.TxOut{{Pk_script: pk_scr, Value: value}}
   225  	// Lock_time = 0
   226  	input_tx.SetHash(input_tx.Serialize())
   227  	return
   228  }
   229  
   230  func mk_spend_tx(input_tx *btc.Tx, sig_scr []byte, witness [][]byte) (output_tx *btc.Tx) {
   231  	output_tx = new(btc.Tx)
   232  	output_tx.Version = 1
   233  	output_tx.TxIn = []*btc.TxIn{{Input: btc.TxPrevOut{Hash: btc.Sha2Sum(input_tx.Serialize()), Vout: 0},
   234  		ScriptSig: sig_scr, Sequence: 0xffffffff}}
   235  	output_tx.TxOut = []*btc.TxOut{{Value: input_tx.TxOut[0].Value}}
   236  	// Lock_time = 0
   237  
   238  	if len(witness) > 0 {
   239  		output_tx.SegWit = make([][][]byte, 1)
   240  		output_tx.SegWit[0] = witness
   241  		if DBG_SCR {
   242  			println("tx has", len(witness), "ws")
   243  			for xx := range witness {
   244  				println("", xx, hex.EncodeToString(witness[xx]))
   245  			}
   246  		}
   247  	}
   248  	output_tx.SetHash(output_tx.Serialize())
   249  	return
   250  }