diff --git a/.travis.yml b/.travis.yml index 3a51dd5..a27981d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,10 +1,23 @@ language: go -sudo: false - go: - - tip + - 1.14.x + +services: + - docker + +install: + # Get Nigiri-travis for testing + - mkdir -p tmp; cd tmp + - curl https://travis.nigiri.network | bash; cd .. + - docker-compose -f tmp/docker-compose.yml up -d + +env: + - API_URL=http://localhost:3001 script: - if [ -n "$(gofmt -l .)" ]; then echo "Go code is not formatted"; exit 1; fi - - go test -v ./... \ No newline at end of file + - go test -count=1 -race ./... -v + +after_script: + - docker-compose -f tmp/docker-compose.yml down && rm -rf tmp diff --git a/README.md b/README.md index 0a27cc6..0b8095b 100644 --- a/README.md +++ b/README.md @@ -7,25 +7,21 @@ [![Build Status](https://travis-ci.com/vulpemventures/go-elements.svg?branch=master)](https://travis-ci.com/vulpemventures/go-elements) [![Bitcoin Donate](https://badgen.net/badge/Bitcoin/Donate/F7931A?icon=bitcoin)](https://blockstream.info/address/3MdERN32qiMnQ68bSSee5CXQkrSGx1iStr) - - -Go support for confidential transactions on Elements-based blockchains - +Go support for confidential transactions on Elements-based blockchains **The package is currently being developed. DO NOT USE IT** - ## 🛣 Roadmap - [x] Chain parameters (prefixes, magic numbers, …) - [x] Pay to Public Key Hash - [x] Pay to Script Hash - [x] Pay to Witness Public Key Hash -- [ ] Pay to Witness Script Hash +- [x] Pay to Witness Script Hash - [x] Tx serialization / deserialization - - [ ] Use of confidential values instead of pure numbers + - [x] Use of confidential values instead of pure numbers - [x] Fix order of witness in transaction serialization - - [ ] Add confidential fields + - [x] Add confidential fields - [x] Serialization for (witness) signature - [x] [PSET / Bip174 for Elements](https://github.com/vulpemventures/go-elements/tree/master/pset) - [ ] CGO bindings for blech32 @@ -33,3 +29,27 @@ Go support for confidential transactions on Elements-based blockchains - [ ] Blinding outs/ Unblinding ins - [ ] Slip77 - [ ] Signing a confidential input (use 0 value amounts to produce the hash for the signature) + +## Development + +Clone repository: + +```sh +$ git clone https://github.com/vulpemventures/go-elements.git +``` + +Enter into the project folder and install dependencies: + +```sh +$ cd go-elements +$ go get -t -v ./... +``` + +For running tests it is required to have a running Nigiri locally, or at least a remote one reachable from the outside. +To run the tests it is mandatory to export an `API_URL` environment vriable pointing to the url of nigiri-chopsitcks. +Example having a local Nigiri running: + +``` +$ export API_URL=http://localhost:3001 +$ go test ./... -v +``` diff --git a/example.go b/example.go index adeb34d..c8d8cb6 100644 --- a/example.go +++ b/example.go @@ -2,6 +2,7 @@ package main import ( "encoding/hex" + "github.com/btcsuite/btcd/btcec" "github.com/vulpemventures/go-elements/network" "github.com/vulpemventures/go-elements/payment" @@ -22,7 +23,9 @@ func main() { _, publicKey := btcec.PrivKeyFromBytes(btcec.S256(), privateKeyBytes) pay := payment.FromPublicKey(publicKey, &network.Regtest) - println(pay.PubKeyHash()) - println(pay.WitnessPubKeyHash()) + legacyAddress := pay.PubKeyHash() + segwitAddress, _ := pay.WitnessPubKeyHash() + println(legacyAddress) + println(segwitAddress) } diff --git a/internal/bufferutil/bufferutil.go b/internal/bufferutil/bufferutil.go new file mode 100644 index 0000000..79119dc --- /dev/null +++ b/internal/bufferutil/bufferutil.go @@ -0,0 +1,13 @@ +package bufferutil + +// ReverseBytes returns the given byte slice with elems in reverse order. +func ReverseBytes(buf []byte) []byte { + if len(buf) < 1 { + return buf + } + for i := len(buf)/2 - 1; i >= 0; i-- { + j := len(buf) - 1 - i + buf[i], buf[j] = buf[j], buf[i] + } + return buf +} diff --git a/pset/pset_test.go b/pset/pset_test.go index 9b28b63..fb6b29e 100644 --- a/pset/pset_test.go +++ b/pset/pset_test.go @@ -5,10 +5,19 @@ import ( "encoding/binary" "encoding/hex" "encoding/json" + "errors" "io/ioutil" + "net/http" + "os" + "strings" "testing" + "time" + "github.com/btcsuite/btcd/btcec" "github.com/btcsuite/btcd/txscript" + "github.com/vulpemventures/go-elements/internal/bufferutil" + "github.com/vulpemventures/go-elements/network" + "github.com/vulpemventures/go-elements/payment" "github.com/vulpemventures/go-elements/transaction" ) @@ -82,7 +91,7 @@ func TestCreator(t *testing.T) { in := vIn.(map[string]interface{}) inHash, _ := hex.DecodeString(in["hash"].(string)) inIndex := uint32(in["index"].(float64)) - inHash = reverseBytes(inHash) + inHash = bufferutil.ReverseBytes(inHash) inputs = append(inputs, transaction.NewTxInput(inHash, inIndex)) } @@ -90,7 +99,7 @@ func TestCreator(t *testing.T) { for _, vOut := range v["outputs"].([]interface{}) { out := vOut.(map[string]interface{}) outAsset, _ := hex.DecodeString(out["asset"].(string)) - outAsset = append([]byte{0x01}, reverseBytes(outAsset)...) + outAsset = append([]byte{0x01}, bufferutil.ReverseBytes(outAsset)...) outValue, _ := toConfidentialValue(int(out["value"].(float64))) outScript, _ := hex.DecodeString(out["script"].(string)) outputs = append(outputs, transaction.NewTxOutput(outAsset, outValue, outScript)) @@ -146,7 +155,7 @@ func TestUpdater(t *testing.T) { } else { wu := in["witnessUtxo"].(map[string]interface{}) asset, _ := hex.DecodeString(wu["asset"].(string)) - asset = append([]byte{0x01}, reverseBytes(asset)...) + asset = append([]byte{0x01}, bufferutil.ReverseBytes(asset)...) script, _ := hex.DecodeString(wu["script"].(string)) value, _ := toConfidentialValue(int(wu["value"].(float64))) utxo := transaction.NewTxOutput(asset, value, script) @@ -291,11 +300,222 @@ func TestExtractor(t *testing.T) { } } +func TestFromCreateToBroadcast(t *testing.T) { + /** + * This test attempts to broadcast a transaction composed by 1 input and 3 + * outputs. The input of the transaction will be a native segwit input, thus + * locked by a p2wpkh script, while the outputs will be a legacy p2sh for the + * receiver and a segwit p2wpkh for the change. + * The 3rd output is for the fees, that in Elements side chains are explicits. + * + * This is intended to test that all methods provided let one to manage a + * partial transaction from its creatation to the extraction of the final + * tranasction so that it can be correctly broadcasted to the network and + * included in the blockchain. + */ + + // Generate sender random key pair. + privkey, err := btcec.NewPrivateKey(btcec.S256()) + if err != nil { + t.Fatal(err) + } + pubkey := privkey.PubKey() + p2wpkh := payment.FromPublicKey(pubkey, &network.Regtest) + address, _ := p2wpkh.WitnessPubKeyHash() + + // Fund sender address. + _, err = faucet(address) + if err != nil { + t.Fatal(err) + } + + // Retrieve sender utxos. + utxos, err := unspents(address) + if err != nil { + t.Fatal(err) + } + + // The transaction will have 1 input and 3 outputs. + txInputHash, _ := hex.DecodeString(utxos[0]["txid"].(string)) + txInputHash = bufferutil.ReverseBytes(txInputHash) + txInputIndex := uint32(utxos[0]["vout"].(float64)) + txInput := transaction.NewTxInput(txInputHash, txInputIndex) + + lbtc, _ := hex.DecodeString("5ac9f65c0efcc4775e0baec4ec03abdde22473cd3cf33c0419ca290e0751b225") + lbtc = append([]byte{0x01}, bufferutil.ReverseBytes(lbtc)...) + receiverValue, _ := toConfidentialValue(60000000) + receiverScript, _ := hex.DecodeString("76a91439397080b51ef22c59bd7469afacffbeec0da12e88ac") + receiverOutput := transaction.NewTxOutput(lbtc, receiverValue, receiverScript) + + changeScript := p2wpkh.Script + changeValue, _ := toConfidentialValue(39999500) + changeOutput := transaction.NewTxOutput(lbtc, changeValue, changeScript) + + feeScript := []byte{} + feeValue, _ := toConfidentialValue(500) + feeOutput := transaction.NewTxOutput(lbtc, feeValue, feeScript) + + // Create a new pset. + inputs := []*transaction.TxInput{txInput} + outputs := []*transaction.TxOutput{receiverOutput, changeOutput, feeOutput} + p, err := New(inputs, outputs, 2, 0) + if err != nil { + t.Fatal(err) + } + + // Add sighash type and witness utxo to the partial input. + updater, err := NewUpdater(p) + if err != nil { + t.Fatal(err) + } + + updater.AddInSighashType(txscript.SigHashAll, 0) + if err != nil { + t.Fatal(err) + } + witValue, _ := toConfidentialValue(int(utxos[0]["value"].(float64))) + witnessUtxo := transaction.NewTxOutput(lbtc, witValue, p2wpkh.Script) + updater.AddInWitnessUtxo(witnessUtxo, 0) + + // The signing of the input is done by retrieving the proper hash of the serialization + // of the transaction (the BIP-0143 segwit version in this case) directly from the pset's + // UnsignedTx. + // NOTE: to correctly sign an utxo locked by a p2wpkh script, we must use the legacy pubkey script + // when serializing the transaction. + legacyScript := append(append([]byte{0x76, 0xa9, 0x14}, p2wpkh.Hash...), []byte{0x88, 0xac}...) + witHash := updater.Upsbt.UnsignedTx.HashForWitnessV0(0, legacyScript, witValue, txscript.SigHashAll) + sig, err := privkey.Sign(witHash[:]) + if err != nil { + t.Fatal(err) + } + sigWithHashType := append(sig.Serialize(), byte(txscript.SigHashAll)) + if err != nil { + t.Fatal(err) + } + + // Update the pset adding the input signature script and the pubkey. + _, err = updater.Sign(0, sigWithHashType, pubkey.SerializeCompressed(), nil, nil) + if err != nil { + t.Fatal(err) + } + + // Finalize the partial transaction. + p = updater.Upsbt + err = FinalizeAll(p) + if err != nil { + t.Fatal(err) + } + + // Extract the final signed transaction from the Pset wrapper. + finalTx, err := Extract(p) + if err != nil { + t.Fatal(err) + } + + // Serialize the transaction and try to broadcast. + txHex, err := finalTx.ToHex() + if err != nil { + t.Fatal(err) + } + txid, err := broadcast(txHex) + if err != nil { + t.Fatal(err) + } + + if len(txid) <= 0 { + t.Fatal("Expected transaction to be broadcasted") + } +} + func toConfidentialValue(val int) ([]byte, error) { unconfPrefix := byte(1) b := bytes.NewBuffer([]byte{}) if err := transaction.BinarySerializer.PutUint64(b, binary.LittleEndian, uint64(val)); err != nil { return nil, err } - return append([]byte{unconfPrefix}, reverseBytes(b.Bytes())...), nil + return append([]byte{unconfPrefix}, bufferutil.ReverseBytes(b.Bytes())...), nil +} + +func faucet(address string) (string, error) { + baseUrl, ok := os.LookupEnv("API_URL") + if !ok { + return "", errors.New("API_URL environment variable is not set") + } + url := baseUrl + "/faucet" + payload := map[string]string{"address": address} + body, _ := json.Marshal(payload) + resp, err := http.Post(url, "appliation/json", bytes.NewBuffer(body)) + if err != nil { + return "", err + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + respBody := map[string]string{} + err = json.Unmarshal(data, &respBody) + if err != nil { + return "", err + } + + return respBody["txId"], nil +} + +func unspents(address string) ([]map[string]interface{}, error) { + getUtxos := func(address string) ([]interface{}, error) { + baseUrl, ok := os.LookupEnv("API_URL") + if !ok { + return nil, errors.New("API_URL environment variable is not set") + } + url := baseUrl + "/address/" + address + "/utxo" + resp, err := http.Get(url) + if err != nil { + return nil, err + } + data, err := ioutil.ReadAll(resp.Body) + if err != nil { + return nil, err + } + var respBody interface{} + err = json.Unmarshal(data, &respBody) + if err != nil { + return nil, err + } + + return respBody.([]interface{}), nil + } + + utxos := []map[string]interface{}{} + for len(utxos) <= 0 { + time.Sleep(1 * time.Second) + u, err := getUtxos(address) + if err != nil { + return nil, err + } + for _, unspent := range u { + utxo := unspent.(map[string]interface{}) + utxos = append(utxos, utxo) + } + } + + return utxos, nil +} + +func broadcast(txHex string) (string, error) { + baseUrl, ok := os.LookupEnv("API_URL") + if !ok { + return "", errors.New("API_URL environment variable is not set") + } + + url := baseUrl + "/tx" + resp, err := http.Post(url, "text/plain", strings.NewReader(txHex)) + if err != nil { + return "", err + } + txid, err := ioutil.ReadAll(resp.Body) + if err != nil { + return "", err + } + + return string(txid), nil } diff --git a/pset/utils.go b/pset/utils.go index 92bb314..6f0e83b 100644 --- a/pset/utils.go +++ b/pset/utils.go @@ -371,19 +371,3 @@ func validateSignature(sig []byte) bool { func checkValid(ps psbt.PartialSig) bool { return validatePubkey(ps.PubKey) && validateSignature(ps.Signature) } - -// reverseBytes returns the given byte slice with elems in reverse order. -func reverseBytes(buf []byte) []byte { - if len(buf) < 1 { - return buf - } - j := len(buf) - 1 - tmp := byte(0) - for i := 0; i < len(buf)/2; i++ { - tmp = buf[i] - buf[i] = buf[j] - buf[j] = tmp - j-- - } - return buf -} diff --git a/transaction/data/tx_valid.json b/transaction/data/tx_valid.json new file mode 100644 index 0000000..b008925 --- /dev/null +++ b/transaction/data/tx_valid.json @@ -0,0 +1,137 @@ +{ + "txRoundTrip": [ + "010000000001f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b4830450221008732a460737d956fd94d49a31890b2908f7ed7025a9c1d0f25e43290f1841716022004fa7d608a291d44ebbbebbadaac18f943031e7de39ef3bf9920998c43e60c0401210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000186a0001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000", + "010000000002f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b483045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff2fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe0100000083483045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c78012102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee517a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687000000800201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000000c350001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000249f00017a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc768700000000", + "01000000000ee7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0000000008c493046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff7bfc005f3880a606027c7cd7dd02a0f6a6572eeb84a91aa158311be13695a7ea010000008b483045022100e2e61c40f26e2510b76dc72ea2f568ec514fce185c719e18bca9caaef2b20e9e02207f1100fc79eb0584e970c7f18fb226f178951d481767b4092d50d13c50ccba8b014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0e0f8e6bf951fbb84d7d8ef833a1cbf5bb046ea7251973ac6e7661c755386ee3010000008a473044022048f1611e403710f248f7caf479965a6a5f63cdfbd9a714fef4ec1b68331ade1d022074919e79376c363d4575b2fc21513d5949471703efebd4c5ca2885e810eb1fa4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b000000008b483045022100886c07cad489dfcf4b364af561835d5cf985f07adf8bd1d5bd6ddea82b0ce6b2022045bdcbcc2b5fc55191bb997039cf59ff70e8515c56b62f293a9add770ba26738014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b010000008a4730440220535d49b819fdf294d27d82aff2865ed4e18580f0ca9796d793f611cb43a44f47022019584d5e300c415f642e37ba2a814a1e1106b4a9b91dc2a30fb57ceafe041181014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffd3051677216ea53baa2e6d7f6a75434ac338438c59f314801c8496d1e6d1bf6d010000008b483045022100bf612b0fa46f49e70ab318ca3458d1ed5f59727aa782f7fac5503f54d9b43a590220358d7ed0e3cee63a5a7e972d9fad41f825d95de2fd0c5560382468610848d489014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff1e751ccc4e7d973201e9174ec78ece050ef2fadd6a108f40f76a9fa314979c31010000008b483045022006e263d5f73e05c48a603e3bd236e8314e5420721d5e9020114b93e8c9220e1102210099d3dead22f4a792123347a238c87e67b55b28a94a0bb7793144cc7ad94a0168014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff25c4cf2c61743b3f4252d921d937cca942cf32e4f3fa4a544d0b26f014337084010000008a47304402207d6e87588be47bf2d97eaf427bdd992e9d6b306255711328aee38533366a88b50220623099595ae442cb77eaddb3f91753a4fc9df56fde69cfec584c7f97e05533c8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffecd93c87eb43c48481e6694904305349bdea94b01104579fa9f02bff66c89663010000008a473044022020f59498aee0cf82cb113768ef3cb721000346d381ff439adb4d405f791252510220448de723aa59412266fabbc689ec25dc94b1688c27a614982047513a80173514014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa1fdc0a79ff98d5b6154176e321c22f4f8450dbd950bd013ad31135f5604411e010000008b48304502210088167867f87327f9c0db0444267ff0b6a026eedd629d8f16fe44a34c18e706bf0220675c8baebf89930e2d6e4463adefc50922653af99375242e38f5ee677418738a014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffb89e8249c3573b58bf1ec7433185452dd57ab8e1daab01c3cc6ddc8b66ad3de8000000008b4830450220073d50ac5ec8388d5b3906921f9368c31ad078c8e1fb72f26d36b533f35ee327022100c398b23e6692e11dca8a1b64aae2ff70c6a781ed5ee99181b56a2f583a967cd4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff45ee07e182084454dacfad1e61b04ffdf9c7b01003060a6c841a01f4fff8a5a0010000008b483045022100991d1bf60c41358f08b20e53718a24e05ac0608915df4f6305a5b47cb61e5da7022003f14fc1cc5b737e2c3279a4f9be1852b49dbb3d9d6cc4c8af6a666f600dced8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff4cba12549f1d70f8e60aea8b546c8357f7c099e7c7d9d8691d6ee16e7dfa3170010000008c493046022100f14e2b0ef8a8e206db350413d204bc0a5cd779e556b1191c2d30b5ec023cde6f022100b90b2d2bf256c98a88f7c3a653b93cec7d25bb6a517db9087d11dbd189e8851c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa4b3aed39eb2a1dc6eae4609d9909724e211c153927c230d02bd33add3026959010000008b483045022100a8cebb4f1c58f5ba1af91cb8bd4a2ed4e684e9605f5a9dc8b432ed00922d289d0220251145d2d56f06d936fd0c51fa884b4a6a5fafd0c3318f72fb05a5c9aa372195014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000323d540001976a914167c3e1f10cc3b691c73afbdb211e156e3e3f25c88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000002e4615001976a914290f7d617b75993e770e5606335fa0999a28d71388ac00000000", + "020000000101a5c44e1434a1f9b90652ff5a7fe35ab4ed349db0d73d428b63585dc87178dabb00000000171600143e5913dd0fdf12a0d4dd68007a55d734ef938dc1fdffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a9140a5996dceab48274e3f915eb4db2c90ea26922ac88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914963f9bef50bf71a46a0a674b6f16f6d8ae2f61a5870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a01000000000000163000007900000000000247304402202fc73aad6932e25b3cb2a7da3213189bcdb4dbacceb5687ff713751d85e66f570220232951e9e820b3cdabb5c827ef9499e98aa90cd9275ea223f6f40549a940e596012103cbc1315ebc3d91dde32682be3c763260004cf60840908e72a50f4e59dfe7175700000000000000" + ], + "txHash": [ + { + "txHex": "010000000001f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b4830450221008732a460737d956fd94d49a31890b2908f7ed7025a9c1d0f25e43290f1841716022004fa7d608a291d44ebbbebbadaac18f943031e7de39ef3bf9920998c43e60c0401210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000186a0001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000", + "expectedTxHash": "ed16cef815497ce650be77b4a476787f2293565483c7b9c3fb403d0694c8af4f", + "expectedTxWitnessHash": "4fafc894063d40fbc3b9c783545693227f7876a4b477be50e67c4915f8ce16ed" + }, + { + "txHex": "010000000002f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b483045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff2fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe0100000083483045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c78012102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee517a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687000000800201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000000c350001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000249f00017a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc768700000000", + "expectedTxHash": "705918b21434dfb738ce4e261942e96dc22f4868d6973ecb2c6191ef467c2e5d", + "expectedTxWitnessHash": "5d2e7c46ef91612ccb3e97d668482fc26de94219264ece38b7df3414b2185970" + }, + { + "txHex": "01000000000ee7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0000000008c493046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff7bfc005f3880a606027c7cd7dd02a0f6a6572eeb84a91aa158311be13695a7ea010000008b483045022100e2e61c40f26e2510b76dc72ea2f568ec514fce185c719e18bca9caaef2b20e9e02207f1100fc79eb0584e970c7f18fb226f178951d481767b4092d50d13c50ccba8b014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0e0f8e6bf951fbb84d7d8ef833a1cbf5bb046ea7251973ac6e7661c755386ee3010000008a473044022048f1611e403710f248f7caf479965a6a5f63cdfbd9a714fef4ec1b68331ade1d022074919e79376c363d4575b2fc21513d5949471703efebd4c5ca2885e810eb1fa4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b000000008b483045022100886c07cad489dfcf4b364af561835d5cf985f07adf8bd1d5bd6ddea82b0ce6b2022045bdcbcc2b5fc55191bb997039cf59ff70e8515c56b62f293a9add770ba26738014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b010000008a4730440220535d49b819fdf294d27d82aff2865ed4e18580f0ca9796d793f611cb43a44f47022019584d5e300c415f642e37ba2a814a1e1106b4a9b91dc2a30fb57ceafe041181014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffd3051677216ea53baa2e6d7f6a75434ac338438c59f314801c8496d1e6d1bf6d010000008b483045022100bf612b0fa46f49e70ab318ca3458d1ed5f59727aa782f7fac5503f54d9b43a590220358d7ed0e3cee63a5a7e972d9fad41f825d95de2fd0c5560382468610848d489014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff1e751ccc4e7d973201e9174ec78ece050ef2fadd6a108f40f76a9fa314979c31010000008b483045022006e263d5f73e05c48a603e3bd236e8314e5420721d5e9020114b93e8c9220e1102210099d3dead22f4a792123347a238c87e67b55b28a94a0bb7793144cc7ad94a0168014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff25c4cf2c61743b3f4252d921d937cca942cf32e4f3fa4a544d0b26f014337084010000008a47304402207d6e87588be47bf2d97eaf427bdd992e9d6b306255711328aee38533366a88b50220623099595ae442cb77eaddb3f91753a4fc9df56fde69cfec584c7f97e05533c8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffecd93c87eb43c48481e6694904305349bdea94b01104579fa9f02bff66c89663010000008a473044022020f59498aee0cf82cb113768ef3cb721000346d381ff439adb4d405f791252510220448de723aa59412266fabbc689ec25dc94b1688c27a614982047513a80173514014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa1fdc0a79ff98d5b6154176e321c22f4f8450dbd950bd013ad31135f5604411e010000008b48304502210088167867f87327f9c0db0444267ff0b6a026eedd629d8f16fe44a34c18e706bf0220675c8baebf89930e2d6e4463adefc50922653af99375242e38f5ee677418738a014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffb89e8249c3573b58bf1ec7433185452dd57ab8e1daab01c3cc6ddc8b66ad3de8000000008b4830450220073d50ac5ec8388d5b3906921f9368c31ad078c8e1fb72f26d36b533f35ee327022100c398b23e6692e11dca8a1b64aae2ff70c6a781ed5ee99181b56a2f583a967cd4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff45ee07e182084454dacfad1e61b04ffdf9c7b01003060a6c841a01f4fff8a5a0010000008b483045022100991d1bf60c41358f08b20e53718a24e05ac0608915df4f6305a5b47cb61e5da7022003f14fc1cc5b737e2c3279a4f9be1852b49dbb3d9d6cc4c8af6a666f600dced8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff4cba12549f1d70f8e60aea8b546c8357f7c099e7c7d9d8691d6ee16e7dfa3170010000008c493046022100f14e2b0ef8a8e206db350413d204bc0a5cd779e556b1191c2d30b5ec023cde6f022100b90b2d2bf256c98a88f7c3a653b93cec7d25bb6a517db9087d11dbd189e8851c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa4b3aed39eb2a1dc6eae4609d9909724e211c153927c230d02bd33add3026959010000008b483045022100a8cebb4f1c58f5ba1af91cb8bd4a2ed4e684e9605f5a9dc8b432ed00922d289d0220251145d2d56f06d936fd0c51fa884b4a6a5fafd0c3318f72fb05a5c9aa372195014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000323d540001976a914167c3e1f10cc3b691c73afbdb211e156e3e3f25c88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000002e4615001976a914290f7d617b75993e770e5606335fa0999a28d71388ac00000000", + "expectedTxHash": "1a7fb5098a7ea5ce45e8849804ddc8ffc0a6778e9e4ccbd47a0945b1499c7e31", + "expectedTxWitnessHash": "317e9c49b145097ad4cb4c9e8e77a6c0ffc8dd049884e845cea57e8a09b57f1a" + }, + { + "txHex": "020000000101a5c44e1434a1f9b90652ff5a7fe35ab4ed349db0d73d428b63585dc87178dabb00000000171600143e5913dd0fdf12a0d4dd68007a55d734ef938dc1fdffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a9140a5996dceab48274e3f915eb4db2c90ea26922ac88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914963f9bef50bf71a46a0a674b6f16f6d8ae2f61a5870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a01000000000000163000007900000000000247304402202fc73aad6932e25b3cb2a7da3213189bcdb4dbacceb5687ff713751d85e66f570220232951e9e820b3cdabb5c827ef9499e98aa90cd9275ea223f6f40549a940e596012103cbc1315ebc3d91dde32682be3c763260004cf60840908e72a50f4e59dfe7175700000000000000", + "expectedTxHash": "4c4419a815a143c1a54c62609c059c34f31afe0c0a21b0dab8c9048a8a3ae41f", + "expectedTxWitnessHash": "1fe43a8a8a04c9b8dab0210a0cfe1af3349c059c60624ca5c143a115a819444c" + } + ], + "txSize": [ + { + "txHex": "010000000001f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b4830450221008732a460737d956fd94d49a31890b2908f7ed7025a9c1d0f25e43290f1841716022004fa7d608a291d44ebbbebbadaac18f943031e7de39ef3bf9920998c43e60c0401210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000186a0001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000", + "expectedWeight": 912, + "expectedVsize": 228 + }, + { + "txHex": "010000000002f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b483045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff2fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe0100000083483045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c78012102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee517a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687000000800201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000000c350001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000249f00017a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc768700000000", + "expectedWeight": 1868, + "expectedVsize": 467 + }, + { + "txHex": "01000000000ee7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0000000008c493046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff7bfc005f3880a606027c7cd7dd02a0f6a6572eeb84a91aa158311be13695a7ea010000008b483045022100e2e61c40f26e2510b76dc72ea2f568ec514fce185c719e18bca9caaef2b20e9e02207f1100fc79eb0584e970c7f18fb226f178951d481767b4092d50d13c50ccba8b014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0e0f8e6bf951fbb84d7d8ef833a1cbf5bb046ea7251973ac6e7661c755386ee3010000008a473044022048f1611e403710f248f7caf479965a6a5f63cdfbd9a714fef4ec1b68331ade1d022074919e79376c363d4575b2fc21513d5949471703efebd4c5ca2885e810eb1fa4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b000000008b483045022100886c07cad489dfcf4b364af561835d5cf985f07adf8bd1d5bd6ddea82b0ce6b2022045bdcbcc2b5fc55191bb997039cf59ff70e8515c56b62f293a9add770ba26738014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b010000008a4730440220535d49b819fdf294d27d82aff2865ed4e18580f0ca9796d793f611cb43a44f47022019584d5e300c415f642e37ba2a814a1e1106b4a9b91dc2a30fb57ceafe041181014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffd3051677216ea53baa2e6d7f6a75434ac338438c59f314801c8496d1e6d1bf6d010000008b483045022100bf612b0fa46f49e70ab318ca3458d1ed5f59727aa782f7fac5503f54d9b43a590220358d7ed0e3cee63a5a7e972d9fad41f825d95de2fd0c5560382468610848d489014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff1e751ccc4e7d973201e9174ec78ece050ef2fadd6a108f40f76a9fa314979c31010000008b483045022006e263d5f73e05c48a603e3bd236e8314e5420721d5e9020114b93e8c9220e1102210099d3dead22f4a792123347a238c87e67b55b28a94a0bb7793144cc7ad94a0168014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff25c4cf2c61743b3f4252d921d937cca942cf32e4f3fa4a544d0b26f014337084010000008a47304402207d6e87588be47bf2d97eaf427bdd992e9d6b306255711328aee38533366a88b50220623099595ae442cb77eaddb3f91753a4fc9df56fde69cfec584c7f97e05533c8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffecd93c87eb43c48481e6694904305349bdea94b01104579fa9f02bff66c89663010000008a473044022020f59498aee0cf82cb113768ef3cb721000346d381ff439adb4d405f791252510220448de723aa59412266fabbc689ec25dc94b1688c27a614982047513a80173514014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa1fdc0a79ff98d5b6154176e321c22f4f8450dbd950bd013ad31135f5604411e010000008b48304502210088167867f87327f9c0db0444267ff0b6a026eedd629d8f16fe44a34c18e706bf0220675c8baebf89930e2d6e4463adefc50922653af99375242e38f5ee677418738a014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffb89e8249c3573b58bf1ec7433185452dd57ab8e1daab01c3cc6ddc8b66ad3de8000000008b4830450220073d50ac5ec8388d5b3906921f9368c31ad078c8e1fb72f26d36b533f35ee327022100c398b23e6692e11dca8a1b64aae2ff70c6a781ed5ee99181b56a2f583a967cd4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff45ee07e182084454dacfad1e61b04ffdf9c7b01003060a6c841a01f4fff8a5a0010000008b483045022100991d1bf60c41358f08b20e53718a24e05ac0608915df4f6305a5b47cb61e5da7022003f14fc1cc5b737e2c3279a4f9be1852b49dbb3d9d6cc4c8af6a666f600dced8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff4cba12549f1d70f8e60aea8b546c8357f7c099e7c7d9d8691d6ee16e7dfa3170010000008c493046022100f14e2b0ef8a8e206db350413d204bc0a5cd779e556b1191c2d30b5ec023cde6f022100b90b2d2bf256c98a88f7c3a653b93cec7d25bb6a517db9087d11dbd189e8851c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa4b3aed39eb2a1dc6eae4609d9909724e211c153927c230d02bd33add3026959010000008b483045022100a8cebb4f1c58f5ba1af91cb8bd4a2ed4e684e9605f5a9dc8b432ed00922d289d0220251145d2d56f06d936fd0c51fa884b4a6a5fafd0c3318f72fb05a5c9aa372195014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000323d540001976a914167c3e1f10cc3b691c73afbdb211e156e3e3f25c88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000002e4615001976a914290f7d617b75993e770e5606335fa0999a28d71388ac00000000", + "expectedWeight": 10668, + "expectedVsize": 2667 + }, + { + "txHex": "020000000101a5c44e1434a1f9b90652ff5a7fe35ab4ed349db0d73d428b63585dc87178dabb00000000171600143e5913dd0fdf12a0d4dd68007a55d734ef938dc1fdffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a9140a5996dceab48274e3f915eb4db2c90ea26922ac88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914963f9bef50bf71a46a0a674b6f16f6d8ae2f61a5870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a01000000000000163000007900000000000247304402202fc73aad6932e25b3cb2a7da3213189bcdb4dbacceb5687ff713751d85e66f570220232951e9e820b3cdabb5c827ef9499e98aa90cd9275ea223f6f40549a940e596012103cbc1315ebc3d91dde32682be3c763260004cf60840908e72a50f4e59dfe7175700000000000000", + "expectedWeight": 1136, + "expectedVsize": 284 + } + ], + "txCopy": [ + "010000000001f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b4830450221008732a460737d956fd94d49a31890b2908f7ed7025a9c1d0f25e43290f1841716022004fa7d608a291d44ebbbebbadaac18f943031e7de39ef3bf9920998c43e60c0401210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000186a0001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000", + "010000000002f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b483045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff2fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe0100000083483045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c78012102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee517a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687000000800201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000000c350001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000249f00017a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc768700000000", + "01000000000ee7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0000000008c493046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff7bfc005f3880a606027c7cd7dd02a0f6a6572eeb84a91aa158311be13695a7ea010000008b483045022100e2e61c40f26e2510b76dc72ea2f568ec514fce185c719e18bca9caaef2b20e9e02207f1100fc79eb0584e970c7f18fb226f178951d481767b4092d50d13c50ccba8b014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0e0f8e6bf951fbb84d7d8ef833a1cbf5bb046ea7251973ac6e7661c755386ee3010000008a473044022048f1611e403710f248f7caf479965a6a5f63cdfbd9a714fef4ec1b68331ade1d022074919e79376c363d4575b2fc21513d5949471703efebd4c5ca2885e810eb1fa4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b000000008b483045022100886c07cad489dfcf4b364af561835d5cf985f07adf8bd1d5bd6ddea82b0ce6b2022045bdcbcc2b5fc55191bb997039cf59ff70e8515c56b62f293a9add770ba26738014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b010000008a4730440220535d49b819fdf294d27d82aff2865ed4e18580f0ca9796d793f611cb43a44f47022019584d5e300c415f642e37ba2a814a1e1106b4a9b91dc2a30fb57ceafe041181014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffd3051677216ea53baa2e6d7f6a75434ac338438c59f314801c8496d1e6d1bf6d010000008b483045022100bf612b0fa46f49e70ab318ca3458d1ed5f59727aa782f7fac5503f54d9b43a590220358d7ed0e3cee63a5a7e972d9fad41f825d95de2fd0c5560382468610848d489014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff1e751ccc4e7d973201e9174ec78ece050ef2fadd6a108f40f76a9fa314979c31010000008b483045022006e263d5f73e05c48a603e3bd236e8314e5420721d5e9020114b93e8c9220e1102210099d3dead22f4a792123347a238c87e67b55b28a94a0bb7793144cc7ad94a0168014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff25c4cf2c61743b3f4252d921d937cca942cf32e4f3fa4a544d0b26f014337084010000008a47304402207d6e87588be47bf2d97eaf427bdd992e9d6b306255711328aee38533366a88b50220623099595ae442cb77eaddb3f91753a4fc9df56fde69cfec584c7f97e05533c8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffecd93c87eb43c48481e6694904305349bdea94b01104579fa9f02bff66c89663010000008a473044022020f59498aee0cf82cb113768ef3cb721000346d381ff439adb4d405f791252510220448de723aa59412266fabbc689ec25dc94b1688c27a614982047513a80173514014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa1fdc0a79ff98d5b6154176e321c22f4f8450dbd950bd013ad31135f5604411e010000008b48304502210088167867f87327f9c0db0444267ff0b6a026eedd629d8f16fe44a34c18e706bf0220675c8baebf89930e2d6e4463adefc50922653af99375242e38f5ee677418738a014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffb89e8249c3573b58bf1ec7433185452dd57ab8e1daab01c3cc6ddc8b66ad3de8000000008b4830450220073d50ac5ec8388d5b3906921f9368c31ad078c8e1fb72f26d36b533f35ee327022100c398b23e6692e11dca8a1b64aae2ff70c6a781ed5ee99181b56a2f583a967cd4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff45ee07e182084454dacfad1e61b04ffdf9c7b01003060a6c841a01f4fff8a5a0010000008b483045022100991d1bf60c41358f08b20e53718a24e05ac0608915df4f6305a5b47cb61e5da7022003f14fc1cc5b737e2c3279a4f9be1852b49dbb3d9d6cc4c8af6a666f600dced8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff4cba12549f1d70f8e60aea8b546c8357f7c099e7c7d9d8691d6ee16e7dfa3170010000008c493046022100f14e2b0ef8a8e206db350413d204bc0a5cd779e556b1191c2d30b5ec023cde6f022100b90b2d2bf256c98a88f7c3a653b93cec7d25bb6a517db9087d11dbd189e8851c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa4b3aed39eb2a1dc6eae4609d9909724e211c153927c230d02bd33add3026959010000008b483045022100a8cebb4f1c58f5ba1af91cb8bd4a2ed4e684e9605f5a9dc8b432ed00922d289d0220251145d2d56f06d936fd0c51fa884b4a6a5fafd0c3318f72fb05a5c9aa372195014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000323d540001976a914167c3e1f10cc3b691c73afbdb211e156e3e3f25c88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000002e4615001976a914290f7d617b75993e770e5606335fa0999a28d71388ac00000000", + "020000000101a5c44e1434a1f9b90652ff5a7fe35ab4ed349db0d73d428b63585dc87178dabb00000000171600143e5913dd0fdf12a0d4dd68007a55d734ef938dc1fdffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a9140a5996dceab48274e3f915eb4db2c90ea26922ac88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914963f9bef50bf71a46a0a674b6f16f6d8ae2f61a5870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a01000000000000163000007900000000000247304402202fc73aad6932e25b3cb2a7da3213189bcdb4dbacceb5687ff713751d85e66f570220232951e9e820b3cdabb5c827ef9499e98aa90cd9275ea223f6f40549a940e596012103cbc1315ebc3d91dde32682be3c763260004cf60840908e72a50f4e59dfe7175700000000000000" + ], + "txHashForSignature": [ + { + "txHex": "01000000000200000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000003e8000000000000", + "inIndex": 2, + "script": "00", + "hashType": 0, + "expectedHash": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "txHex": "01000000000200000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000003e8000000000000", + "inIndex": 2, + "script": "00", + "hashType": 3, + "expectedHash": "0000000000000000000000000000000000000000000000000000000000000001" + }, + { + "txHex": "01000000000200000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000003e8000000000000", + "inIndex": 0, + "script": "0053", + "hashType": 0, + "expectedHash": "8f2713d29adbc1668229b6f35a9452d19f0020c7f65366ca9cb72c4a212d353a" + }, + { + "txHex": "01000000000200000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000003e8000000000000", + "inIndex": 0, + "script": "0053", + "hashType": 0, + "expectedHash": "8f2713d29adbc1668229b6f35a9452d19f0020c7f65366ca9cb72c4a212d353a" + }, + { + "txHex": "01000000000200000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000003e8000000000000", + "inIndex": 0, + "script": "0054", + "hashType": 0, + "expectedHash": "59124a8ebe87e608e53d6278e78c9a5d547db52529d4df67a909e8a48ff61dc1" + } + ], + "txHashForWitnessV0": [ + { + "txHex": "0200000001019f8006baffecf6f67a614b957dea2926e5c3a664dcc76107904e81c51e81d8b4010000001716001477eed0492f963c8b63c5dba38df46c067c4c470effffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a914c82f73abe9d97ebced99c3c95633ec10fc7676de88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914be03ace8797d9ca591ce47111fe94a328308b1d0870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000000001630000000000000000002473044022057daca2f62f2d227c98f00d3feb31d010477b9d463d4dd9959b3dfe5ad91fbae022007732d08427cd70c998a70d9b6accf360ef6a758a642f888b409c516a474908f01210318a9d75c7ab17fc69119ed20c0e2d36eb6a54d54a590e98355ed914c7f81242f00000000000000", + "inIndex": 0, + "script": "76a91477eed0492f963c8b63c5dba38df46c067c4c470e88ac", + "expectedHash": "30a66fb46bdd8a823e48b000d792d2383aa4b6a7d467a5531d37fe418411b4ff", + "hashType": 1, + "amount": 200000000 + }, + { + "txHex": "0200000001019f8006baffecf6f67a614b957dea2926e5c3a664dcc76107904e81c51e81d8b4010000001716001477eed0492f963c8b63c5dba38df46c067c4c470effffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a914c82f73abe9d97ebced99c3c95633ec10fc7676de88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914be03ace8797d9ca591ce47111fe94a328308b1d0870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000000001630000000000000000002473044022057daca2f62f2d227c98f00d3feb31d010477b9d463d4dd9959b3dfe5ad91fbae022007732d08427cd70c998a70d9b6accf360ef6a758a642f888b409c516a474908f01210318a9d75c7ab17fc69119ed20c0e2d36eb6a54d54a590e98355ed914c7f81242f0000000000000140", + "inIndex": 0, + "script": "76a91477eed0492f963c8b63c5dba38df46c067c4c470e88ac", + "expectedHash": "53f8e203b55bdb2270ebd7070119b79581e4beca047baf15f93edad72689c8ef", + "hashType": 2, + "amount": 200000000 + }, + { + "txHex": "0200000001019f8006baffecf6f67a614b957dea2926e5c3a664dcc76107904e81c51e81d8b4010000001716001477eed0492f963c8b63c5dba38df46c067c4c470effffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a914c82f73abe9d97ebced99c3c95633ec10fc7676de88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914be03ace8797d9ca591ce47111fe94a328308b1d0870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000000001630000000000000000002473044022057daca2f62f2d227c98f00d3feb31d010477b9d463d4dd9959b3dfe5ad91fbae022007732d08427cd70c998a70d9b6accf360ef6a758a642f888b409c516a474908f01210318a9d75c7ab17fc69119ed20c0e2d36eb6a54d54a590e98355ed914c7f81242f00000000000000", + "inIndex": 0, + "script": "76a91477eed0492f963c8b63c5dba38df46c067c4c470e88ac", + "expectedHash": "6fbc34a6ec37506a3babf478a522aa72f7d3acd49e277ddc9f94f3c3b99aca74", + "hashType": 3, + "amount": 200000000 + }, + { + "txHex": "0200000001019f8006baffecf6f67a614b957dea2926e5c3a664dcc76107904e81c51e81d8b4010000001716001477eed0492f963c8b63c5dba38df46c067c4c470effffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a914c82f73abe9d97ebced99c3c95633ec10fc7676de88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914be03ace8797d9ca591ce47111fe94a328308b1d0870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000000001630000000000000000002473044022057daca2f62f2d227c98f00d3feb31d010477b9d463d4dd9959b3dfe5ad91fbae022007732d08427cd70c998a70d9b6accf360ef6a758a642f888b409c516a474908f01210318a9d75c7ab17fc69119ed20c0e2d36eb6a54d54a590e98355ed914c7f81242f00000000000000", + "inIndex": 0, + "script": "76a91477eed0492f963c8b63c5dba38df46c067c4c470e88ac", + "expectedHash": "8148a515ffacfaec9ed59cfcd19ef99d78d3ae83cecead9f35eab36d5c0f8e15", + "hashType": 129, + "amount": 200000000 + }, + { + "txHex": "0200000001019f8006baffecf6f67a614b957dea2926e5c3a664dcc76107904e81c51e81d8b4010000001716001477eed0492f963c8b63c5dba38df46c067c4c470effffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a914c82f73abe9d97ebced99c3c95633ec10fc7676de88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914be03ace8797d9ca591ce47111fe94a328308b1d0870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000000001630000000000000000002473044022057daca2f62f2d227c98f00d3feb31d010477b9d463d4dd9959b3dfe5ad91fbae022007732d08427cd70c998a70d9b6accf360ef6a758a642f888b409c516a474908f01210318a9d75c7ab17fc69119ed20c0e2d36eb6a54d54a590e98355ed914c7f81242f00000000000000", + "inIndex": 0, + "script": "76a91477eed0492f963c8b63c5dba38df46c067c4c470e88ac", + "expectedHash": "a2150946ba3eb129f2e14b730bc240d084830064fe9563746bc9da9c170302ed", + "hashType": 130, + "amount": 200000000 + } + ] +} diff --git a/transaction/transaction.go b/transaction/transaction.go index 8d823df..4abf9f7 100644 --- a/transaction/transaction.go +++ b/transaction/transaction.go @@ -5,6 +5,7 @@ import ( "encoding/hex" "github.com/btcsuite/btcd/chaincfg/chainhash" + "github.com/btcsuite/btcd/txscript" ) const ( @@ -20,6 +21,22 @@ const ( defaultTxInOutAlloc = 15 ) +var ( + One = [32]byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, + } + Zero = [32]byte{ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + } + MaxConfidentialValue = []byte{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + } +) + //TxIssuance defines the type for Issuance field in TxInput type TxIssuance struct { AssetBlindingNonce []byte @@ -447,6 +464,145 @@ func (tx *Transaction) Serialize() ([]byte, error) { return tx.serialize(nil, true, false, false) } +// HashForSignature returns the double sha256 hash of the serialization +// of the transaction in order to then produce a signature from it. +// The transaction is serialized in a different way depending on the +// hashType provided. +func (tx *Transaction) HashForSignature( + inIndex int, + prevoutScript []byte, + hashType txscript.SigHashType) ([32]byte, error) { + if inIndex >= len(tx.Inputs) { + return One, nil + } + + txCopy := tx.Copy() + + // SIGHASH_NONE: ignore all outputs (wildcard payee) + if (hashType & 0x1f) == txscript.SigHashNone { + txCopy.Outputs = []*TxOutput{} + for i := range txCopy.Inputs { + if i != inIndex { + txCopy.Inputs[i].Sequence = 0 + } + } + } else { + // SIGHASH_SINGLE: ignore all outputs, except at the same index + if (hashType & 0x1f) == txscript.SigHashSingle { + if inIndex >= len(tx.Outputs) { + return One, nil + } + + outs := txCopy.Outputs[:inIndex+1] + txCopy.Outputs = outs + + for i := 0; i < inIndex; i++ { + txCopy.Outputs[i].Asset = Zero[:] + txCopy.Outputs[i].Nonce = Zero[:] + txCopy.Outputs[i].Value = MaxConfidentialValue + txCopy.Outputs[i].Script = []byte{} + } + + for i := range txCopy.Inputs { + if i != inIndex { + txCopy.Inputs[i].Sequence = 0 + } + } + } + } + + // SIGHASH_ANYONECANPAY: ignore inputs entirely + if (hashType & txscript.SigHashAnyOneCanPay) == 1 { + input := TxInput{ + Hash: txCopy.Inputs[inIndex].Hash, + Index: txCopy.Inputs[inIndex].Index, + Sequence: txCopy.Inputs[inIndex].Sequence, + Script: prevoutScript, + IsPegin: txCopy.Inputs[inIndex].IsPegin, + Witness: txCopy.Inputs[inIndex].Witness, + PeginWitness: txCopy.Inputs[inIndex].PeginWitness, + Issuance: txCopy.Inputs[inIndex].Issuance, + IssuanceRangeProof: txCopy.Inputs[inIndex].IssuanceRangeProof, + InflationRangeProof: txCopy.Inputs[inIndex].InflationRangeProof, + } + txCopy.Inputs = []*TxInput{&input} + } else { + // SIGHASH_ALL: only ignore input scripts + for i := range txCopy.Inputs { + script := []byte{} + if i == inIndex { + script = prevoutScript + } + txCopy.Inputs[i].Script = script + } + } + + buf, err := txCopy.serialize(nil, false, true, true) + if err != nil { + return [32]byte{}, err + } + buf = append(buf, []byte{0x00, 0x00, 0x00, byte(hashType)}...) + return chainhash.DoubleHashH(buf), nil +} + +// HashForWitnessV0 returns the double sha256 hash of the serialization +// of the transaction following the BIP-0143 specification. This hash should +// then be used to produce a witness signatures for the given inIndex input. +func (tx *Transaction) HashForWitnessV0(inIndex int, prevoutScript []byte, value []byte, hashType txscript.SigHashType) [32]byte { + hashInputs := Zero + hashSequences := Zero + hashIssuances := Zero + hashOutputs := Zero + + // Inputs + if (hashType & txscript.SigHashAnyOneCanPay) == 0 { + hashInputs = calcTxInputsHash(tx.Inputs) + } + // Sequences + if (hashType&txscript.SigHashAnyOneCanPay) == 0 && + (hashType&0x1f) != txscript.SigHashSingle && + (hashType&0x1f) != txscript.SigHashNone { + hashSequences = calcTxSequencesHash(tx.Inputs) + } + // Issuances + if (hashType & txscript.SigHashAnyOneCanPay) == 0 { + hashIssuances = calcTxIssuancesHash(tx.Inputs) + } + // Outputs + if (hashType&0x1f) != txscript.SigHashSingle && + (hashType&0x1f) != txscript.SigHashNone { + hashOutputs = calcTxOutputsHash(tx.Outputs) + } else { + if (hashType&0x1f) == txscript.SigHashSingle && inIndex < len(tx.Outputs) { + hashOutputs = calcTxOutputsHash([]*TxOutput{tx.Outputs[inIndex]}) + } + } + + s, _ := NewSerializer(nil) + input := tx.Inputs[inIndex] + + s.WriteUint32(uint32(tx.Version)) + s.WriteSlice(hashInputs[:]) + s.WriteSlice(hashSequences[:]) + s.WriteSlice(hashIssuances[:]) + s.WriteSlice(input.Hash[:]) + s.WriteUint32(input.Index) + s.WriteVarSlice(prevoutScript) + s.WriteSlice(value) + s.WriteUint32(input.Sequence) + if input.Issuance != nil { + s.WriteSlice(input.Issuance.AssetBlindingNonce) + s.WriteSlice(input.Issuance.AssetEntropy) + s.WriteSlice(input.Issuance.AssetAmount) + s.WriteSlice(input.Issuance.TokenAmount) + } + s.WriteSlice(hashOutputs[:]) + s.WriteUint32(tx.Locktime) + s.WriteUint32(uint32(hashType)) + + return chainhash.DoubleHashH(s.Bytes()) +} + // ToHex returns the serializarion of the transaction in hex enncoding format. func (tx *Transaction) ToHex() (string, error) { bytes, err := tx.Serialize() @@ -573,3 +729,46 @@ func (tx *Transaction) serialize(buf *bytes.Buffer, allowWitness, zeroFlag, forS return s.Bytes(), nil } + +func calcTxInputsHash(ins []*TxInput) [32]byte { + s, _ := NewSerializer(nil) + for _, in := range ins { + s.WriteSlice(in.Hash) + s.WriteUint32(in.Index) + } + return chainhash.DoubleHashH(s.Bytes()) +} + +func calcTxSequencesHash(ins []*TxInput) [32]byte { + s, _ := NewSerializer(nil) + for _, in := range ins { + s.WriteUint32(in.Sequence) + } + return chainhash.DoubleHashH(s.Bytes()) +} + +func calcTxIssuancesHash(ins []*TxInput) [32]byte { + s, _ := NewSerializer(nil) + for _, in := range ins { + if in.Issuance != nil { + s.WriteSlice(in.Issuance.AssetBlindingNonce) + s.WriteSlice(in.Issuance.AssetEntropy) + s.WriteSlice(in.Issuance.AssetAmount) + s.WriteSlice(in.Issuance.TokenAmount) + } else { + s.WriteSlice([]byte{0x00}) + } + } + return chainhash.DoubleHashH(s.Bytes()) +} + +func calcTxOutputsHash(outs []*TxOutput) [32]byte { + s, _ := NewSerializer(nil) + for _, out := range outs { + s.WriteSlice(out.Asset) + s.WriteSlice(out.Value) + s.WriteSlice(out.Nonce) + s.WriteVarSlice(out.Script) + } + return chainhash.DoubleHashH(s.Bytes()) +} diff --git a/transaction/transaction_test.go b/transaction/transaction_test.go index 54388fd..cfcc57c 100644 --- a/transaction/transaction_test.go +++ b/transaction/transaction_test.go @@ -1,34 +1,28 @@ package transaction import ( + "bytes" + "encoding/binary" "encoding/hex" + "encoding/json" + "io/ioutil" "reflect" "testing" -) -func TestTransaction(t *testing.T) { - t.Run("RoundTrip", testRoundTrip) - t.Run("AddInput", testAddInput) - t.Run("AddOutput", testAddOutput) - t.Run("TxHashAndWitnessHash", testCopy) - t.Run("WeightAndVirtualSize", testSize) - t.Run("Copy", testCopy) -} + "github.com/btcsuite/btcd/txscript" + "github.com/vulpemventures/go-elements/internal/bufferutil" +) -func testRoundTrip(t *testing.T) { - tests := struct { - hex []string - }{ - []string{ - "010000000001f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b4830450221008732a460737d956fd94d49a31890b2908f7ed7025a9c1d0f25e43290f1841716022004fa7d608a291d44ebbbebbadaac18f943031e7de39ef3bf9920998c43e60c0401210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000186a0001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000", - "010000000002f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b483045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff2fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe0100000083483045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c78012102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee517a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687000000800201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000000c350001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000249f00017a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc768700000000", - "01000000000ee7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0000000008c493046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff7bfc005f3880a606027c7cd7dd02a0f6a6572eeb84a91aa158311be13695a7ea010000008b483045022100e2e61c40f26e2510b76dc72ea2f568ec514fce185c719e18bca9caaef2b20e9e02207f1100fc79eb0584e970c7f18fb226f178951d481767b4092d50d13c50ccba8b014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0e0f8e6bf951fbb84d7d8ef833a1cbf5bb046ea7251973ac6e7661c755386ee3010000008a473044022048f1611e403710f248f7caf479965a6a5f63cdfbd9a714fef4ec1b68331ade1d022074919e79376c363d4575b2fc21513d5949471703efebd4c5ca2885e810eb1fa4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b000000008b483045022100886c07cad489dfcf4b364af561835d5cf985f07adf8bd1d5bd6ddea82b0ce6b2022045bdcbcc2b5fc55191bb997039cf59ff70e8515c56b62f293a9add770ba26738014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b010000008a4730440220535d49b819fdf294d27d82aff2865ed4e18580f0ca9796d793f611cb43a44f47022019584d5e300c415f642e37ba2a814a1e1106b4a9b91dc2a30fb57ceafe041181014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffd3051677216ea53baa2e6d7f6a75434ac338438c59f314801c8496d1e6d1bf6d010000008b483045022100bf612b0fa46f49e70ab318ca3458d1ed5f59727aa782f7fac5503f54d9b43a590220358d7ed0e3cee63a5a7e972d9fad41f825d95de2fd0c5560382468610848d489014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff1e751ccc4e7d973201e9174ec78ece050ef2fadd6a108f40f76a9fa314979c31010000008b483045022006e263d5f73e05c48a603e3bd236e8314e5420721d5e9020114b93e8c9220e1102210099d3dead22f4a792123347a238c87e67b55b28a94a0bb7793144cc7ad94a0168014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff25c4cf2c61743b3f4252d921d937cca942cf32e4f3fa4a544d0b26f014337084010000008a47304402207d6e87588be47bf2d97eaf427bdd992e9d6b306255711328aee38533366a88b50220623099595ae442cb77eaddb3f91753a4fc9df56fde69cfec584c7f97e05533c8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffecd93c87eb43c48481e6694904305349bdea94b01104579fa9f02bff66c89663010000008a473044022020f59498aee0cf82cb113768ef3cb721000346d381ff439adb4d405f791252510220448de723aa59412266fabbc689ec25dc94b1688c27a614982047513a80173514014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa1fdc0a79ff98d5b6154176e321c22f4f8450dbd950bd013ad31135f5604411e010000008b48304502210088167867f87327f9c0db0444267ff0b6a026eedd629d8f16fe44a34c18e706bf0220675c8baebf89930e2d6e4463adefc50922653af99375242e38f5ee677418738a014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffb89e8249c3573b58bf1ec7433185452dd57ab8e1daab01c3cc6ddc8b66ad3de8000000008b4830450220073d50ac5ec8388d5b3906921f9368c31ad078c8e1fb72f26d36b533f35ee327022100c398b23e6692e11dca8a1b64aae2ff70c6a781ed5ee99181b56a2f583a967cd4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff45ee07e182084454dacfad1e61b04ffdf9c7b01003060a6c841a01f4fff8a5a0010000008b483045022100991d1bf60c41358f08b20e53718a24e05ac0608915df4f6305a5b47cb61e5da7022003f14fc1cc5b737e2c3279a4f9be1852b49dbb3d9d6cc4c8af6a666f600dced8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff4cba12549f1d70f8e60aea8b546c8357f7c099e7c7d9d8691d6ee16e7dfa3170010000008c493046022100f14e2b0ef8a8e206db350413d204bc0a5cd779e556b1191c2d30b5ec023cde6f022100b90b2d2bf256c98a88f7c3a653b93cec7d25bb6a517db9087d11dbd189e8851c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa4b3aed39eb2a1dc6eae4609d9909724e211c153927c230d02bd33add3026959010000008b483045022100a8cebb4f1c58f5ba1af91cb8bd4a2ed4e684e9605f5a9dc8b432ed00922d289d0220251145d2d56f06d936fd0c51fa884b4a6a5fafd0c3318f72fb05a5c9aa372195014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000323d540001976a914167c3e1f10cc3b691c73afbdb211e156e3e3f25c88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000002e4615001976a914290f7d617b75993e770e5606335fa0999a28d71388ac00000000", - "020000000101a5c44e1434a1f9b90652ff5a7fe35ab4ed349db0d73d428b63585dc87178dabb00000000171600143e5913dd0fdf12a0d4dd68007a55d734ef938dc1fdffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a9140a5996dceab48274e3f915eb4db2c90ea26922ac88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914963f9bef50bf71a46a0a674b6f16f6d8ae2f61a5870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a01000000000000163000007900000000000247304402202fc73aad6932e25b3cb2a7da3213189bcdb4dbacceb5687ff713751d85e66f570220232951e9e820b3cdabb5c827ef9499e98aa90cd9275ea223f6f40549a940e596012103cbc1315ebc3d91dde32682be3c763260004cf60840908e72a50f4e59dfe7175700000000000000", - }, +func TestRoundTrip(t *testing.T) { + file, err := ioutil.ReadFile("data/tx_valid.json") + if err != nil { + t.Fatal(err) } + var tests map[string]interface{} + json.Unmarshal(file, &tests) - for _, str := range tests.hex { - tx, err := NewTxFromHex(str) + for _, str := range tests["txRoundTrip"].([]interface{}) { + tx, err := NewTxFromHex(str.(string)) if err != nil { t.Fatal(err) } @@ -42,7 +36,7 @@ func testRoundTrip(t *testing.T) { } } -func testAddInput(t *testing.T) { +func TestAddInput(t *testing.T) { hashStr := "ffffffff00ffff000000000000000000000000000000000000000000101010ff" index := uint32(0) @@ -63,7 +57,7 @@ func testAddInput(t *testing.T) { } } -func testAddOutput(t *testing.T) { +func TestAddOutput(t *testing.T) { assetStr := "01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d" value := []byte{0x00} script := []byte{} @@ -84,90 +78,68 @@ func testAddOutput(t *testing.T) { } } -func testTxHash(t *testing.T) { - tests := struct { - hex []string - hash []string - witnessHash []string - }{ - []string{ - "010000000001f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b4830450221008732a460737d956fd94d49a31890b2908f7ed7025a9c1d0f25e43290f1841716022004fa7d608a291d44ebbbebbadaac18f943031e7de39ef3bf9920998c43e60c0401210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000186a0001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000", - "010000000002f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b483045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff2fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe0100000083483045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c78012102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee517a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687000000800201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000000c350001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000249f00017a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc768700000000", - "01000000000ee7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0000000008c493046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff7bfc005f3880a606027c7cd7dd02a0f6a6572eeb84a91aa158311be13695a7ea010000008b483045022100e2e61c40f26e2510b76dc72ea2f568ec514fce185c719e18bca9caaef2b20e9e02207f1100fc79eb0584e970c7f18fb226f178951d481767b4092d50d13c50ccba8b014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0e0f8e6bf951fbb84d7d8ef833a1cbf5bb046ea7251973ac6e7661c755386ee3010000008a473044022048f1611e403710f248f7caf479965a6a5f63cdfbd9a714fef4ec1b68331ade1d022074919e79376c363d4575b2fc21513d5949471703efebd4c5ca2885e810eb1fa4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b000000008b483045022100886c07cad489dfcf4b364af561835d5cf985f07adf8bd1d5bd6ddea82b0ce6b2022045bdcbcc2b5fc55191bb997039cf59ff70e8515c56b62f293a9add770ba26738014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b010000008a4730440220535d49b819fdf294d27d82aff2865ed4e18580f0ca9796d793f611cb43a44f47022019584d5e300c415f642e37ba2a814a1e1106b4a9b91dc2a30fb57ceafe041181014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffd3051677216ea53baa2e6d7f6a75434ac338438c59f314801c8496d1e6d1bf6d010000008b483045022100bf612b0fa46f49e70ab318ca3458d1ed5f59727aa782f7fac5503f54d9b43a590220358d7ed0e3cee63a5a7e972d9fad41f825d95de2fd0c5560382468610848d489014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff1e751ccc4e7d973201e9174ec78ece050ef2fadd6a108f40f76a9fa314979c31010000008b483045022006e263d5f73e05c48a603e3bd236e8314e5420721d5e9020114b93e8c9220e1102210099d3dead22f4a792123347a238c87e67b55b28a94a0bb7793144cc7ad94a0168014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff25c4cf2c61743b3f4252d921d937cca942cf32e4f3fa4a544d0b26f014337084010000008a47304402207d6e87588be47bf2d97eaf427bdd992e9d6b306255711328aee38533366a88b50220623099595ae442cb77eaddb3f91753a4fc9df56fde69cfec584c7f97e05533c8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffecd93c87eb43c48481e6694904305349bdea94b01104579fa9f02bff66c89663010000008a473044022020f59498aee0cf82cb113768ef3cb721000346d381ff439adb4d405f791252510220448de723aa59412266fabbc689ec25dc94b1688c27a614982047513a80173514014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa1fdc0a79ff98d5b6154176e321c22f4f8450dbd950bd013ad31135f5604411e010000008b48304502210088167867f87327f9c0db0444267ff0b6a026eedd629d8f16fe44a34c18e706bf0220675c8baebf89930e2d6e4463adefc50922653af99375242e38f5ee677418738a014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffb89e8249c3573b58bf1ec7433185452dd57ab8e1daab01c3cc6ddc8b66ad3de8000000008b4830450220073d50ac5ec8388d5b3906921f9368c31ad078c8e1fb72f26d36b533f35ee327022100c398b23e6692e11dca8a1b64aae2ff70c6a781ed5ee99181b56a2f583a967cd4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff45ee07e182084454dacfad1e61b04ffdf9c7b01003060a6c841a01f4fff8a5a0010000008b483045022100991d1bf60c41358f08b20e53718a24e05ac0608915df4f6305a5b47cb61e5da7022003f14fc1cc5b737e2c3279a4f9be1852b49dbb3d9d6cc4c8af6a666f600dced8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff4cba12549f1d70f8e60aea8b546c8357f7c099e7c7d9d8691d6ee16e7dfa3170010000008c493046022100f14e2b0ef8a8e206db350413d204bc0a5cd779e556b1191c2d30b5ec023cde6f022100b90b2d2bf256c98a88f7c3a653b93cec7d25bb6a517db9087d11dbd189e8851c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa4b3aed39eb2a1dc6eae4609d9909724e211c153927c230d02bd33add3026959010000008b483045022100a8cebb4f1c58f5ba1af91cb8bd4a2ed4e684e9605f5a9dc8b432ed00922d289d0220251145d2d56f06d936fd0c51fa884b4a6a5fafd0c3318f72fb05a5c9aa372195014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000323d540001976a914167c3e1f10cc3b691c73afbdb211e156e3e3f25c88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000002e4615001976a914290f7d617b75993e770e5606335fa0999a28d71388ac00000000", - "020000000101a5c44e1434a1f9b90652ff5a7fe35ab4ed349db0d73d428b63585dc87178dabb00000000171600143e5913dd0fdf12a0d4dd68007a55d734ef938dc1fdffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a9140a5996dceab48274e3f915eb4db2c90ea26922ac88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914963f9bef50bf71a46a0a674b6f16f6d8ae2f61a5870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a01000000000000163000007900000000000247304402202fc73aad6932e25b3cb2a7da3213189bcdb4dbacceb5687ff713751d85e66f570220232951e9e820b3cdabb5c827ef9499e98aa90cd9275ea223f6f40549a940e596012103cbc1315ebc3d91dde32682be3c763260004cf60840908e72a50f4e59dfe7175700000000000000", - }, - []string{ - "ed16cef815497ce650be77b4a476787f2293565483c7b9c3fb403d0694c8af4f", - "705918b21434dfb738ce4e261942e96dc22f4868d6973ecb2c6191ef467c2e5d", - "1a7fb5098a7ea5ce45e8849804ddc8ffc0a6778e9e4ccbd47a0945b1499c7e31", - "4c4419a815a143c1a54c62609c059c34f31afe0c0a21b0dab8c9048a8a3ae41f", - }, - []string{ - "4fafc894063d40fbc3b9c783545693227f7876a4b477be50e67c4915f8ce16ed", - "5d2e7c46ef91612ccb3e97d668482fc26de94219264ece38b7df3414b2185970", - "317e9c49b145097ad4cb4c9e8e77a6c0ffc8dd049884e845cea57e8a09b57f1a", - "1fe43a8a8a04c9b8dab0210a0cfe1af3349c059c60624ca5c143a115a819444c", - }, - } - - for i, str := range tests.hex { - tx, err := NewTxFromHex(str) +func TestTxHash(t *testing.T) { + file, err := ioutil.ReadFile("data/tx_valid.json") + if err != nil { + t.Fatal(err) + } + var tests map[string]interface{} + json.Unmarshal(file, &tests) + + for _, v := range tests["txHash"].([]interface{}) { + testVector := v.(map[string]interface{}) + tx, err := NewTxFromHex(testVector["txHex"].(string)) if err != nil { t.Fatal(err) } - if tx.TxHash().String() != tests.hash[i] { - t.Fatalf("Got: %s, expected: %s", tx.TxHash().String(), tests.hash[i]) + + expectedTxHash := testVector["expectedTxHash"].(string) + expectedTxWitnessHash := testVector["expectedTxWitnessHash"].(string) + if tx.TxHash().String() != expectedTxHash { + t.Fatalf("Got: %s, expected: %s", tx.TxHash().String(), expectedTxHash) } - if tx.WitnessHash().String() == tests.witnessHash[i] { - t.Fatalf("Got: %s, expected: %s", tx.WitnessHash().String(), tests.witnessHash[i]) + if tx.WitnessHash().String() == expectedTxWitnessHash { + t.Fatalf("Got: %s, expected: %s", tx.WitnessHash().String(), expectedTxWitnessHash) } } } -func testSize(t *testing.T) { - tests := struct { - hex []string - weight []int - vsize []int - }{ - []string{ - "010000000001f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b4830450221008732a460737d956fd94d49a31890b2908f7ed7025a9c1d0f25e43290f1841716022004fa7d608a291d44ebbbebbadaac18f943031e7de39ef3bf9920998c43e60c0401210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000186a0001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000", - "010000000002f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b483045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff2fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe0100000083483045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c78012102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee517a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687000000800201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000000c350001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000249f00017a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc768700000000", - "01000000000ee7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0000000008c493046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff7bfc005f3880a606027c7cd7dd02a0f6a6572eeb84a91aa158311be13695a7ea010000008b483045022100e2e61c40f26e2510b76dc72ea2f568ec514fce185c719e18bca9caaef2b20e9e02207f1100fc79eb0584e970c7f18fb226f178951d481767b4092d50d13c50ccba8b014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0e0f8e6bf951fbb84d7d8ef833a1cbf5bb046ea7251973ac6e7661c755386ee3010000008a473044022048f1611e403710f248f7caf479965a6a5f63cdfbd9a714fef4ec1b68331ade1d022074919e79376c363d4575b2fc21513d5949471703efebd4c5ca2885e810eb1fa4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b000000008b483045022100886c07cad489dfcf4b364af561835d5cf985f07adf8bd1d5bd6ddea82b0ce6b2022045bdcbcc2b5fc55191bb997039cf59ff70e8515c56b62f293a9add770ba26738014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b010000008a4730440220535d49b819fdf294d27d82aff2865ed4e18580f0ca9796d793f611cb43a44f47022019584d5e300c415f642e37ba2a814a1e1106b4a9b91dc2a30fb57ceafe041181014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffd3051677216ea53baa2e6d7f6a75434ac338438c59f314801c8496d1e6d1bf6d010000008b483045022100bf612b0fa46f49e70ab318ca3458d1ed5f59727aa782f7fac5503f54d9b43a590220358d7ed0e3cee63a5a7e972d9fad41f825d95de2fd0c5560382468610848d489014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff1e751ccc4e7d973201e9174ec78ece050ef2fadd6a108f40f76a9fa314979c31010000008b483045022006e263d5f73e05c48a603e3bd236e8314e5420721d5e9020114b93e8c9220e1102210099d3dead22f4a792123347a238c87e67b55b28a94a0bb7793144cc7ad94a0168014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff25c4cf2c61743b3f4252d921d937cca942cf32e4f3fa4a544d0b26f014337084010000008a47304402207d6e87588be47bf2d97eaf427bdd992e9d6b306255711328aee38533366a88b50220623099595ae442cb77eaddb3f91753a4fc9df56fde69cfec584c7f97e05533c8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffecd93c87eb43c48481e6694904305349bdea94b01104579fa9f02bff66c89663010000008a473044022020f59498aee0cf82cb113768ef3cb721000346d381ff439adb4d405f791252510220448de723aa59412266fabbc689ec25dc94b1688c27a614982047513a80173514014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa1fdc0a79ff98d5b6154176e321c22f4f8450dbd950bd013ad31135f5604411e010000008b48304502210088167867f87327f9c0db0444267ff0b6a026eedd629d8f16fe44a34c18e706bf0220675c8baebf89930e2d6e4463adefc50922653af99375242e38f5ee677418738a014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffb89e8249c3573b58bf1ec7433185452dd57ab8e1daab01c3cc6ddc8b66ad3de8000000008b4830450220073d50ac5ec8388d5b3906921f9368c31ad078c8e1fb72f26d36b533f35ee327022100c398b23e6692e11dca8a1b64aae2ff70c6a781ed5ee99181b56a2f583a967cd4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff45ee07e182084454dacfad1e61b04ffdf9c7b01003060a6c841a01f4fff8a5a0010000008b483045022100991d1bf60c41358f08b20e53718a24e05ac0608915df4f6305a5b47cb61e5da7022003f14fc1cc5b737e2c3279a4f9be1852b49dbb3d9d6cc4c8af6a666f600dced8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff4cba12549f1d70f8e60aea8b546c8357f7c099e7c7d9d8691d6ee16e7dfa3170010000008c493046022100f14e2b0ef8a8e206db350413d204bc0a5cd779e556b1191c2d30b5ec023cde6f022100b90b2d2bf256c98a88f7c3a653b93cec7d25bb6a517db9087d11dbd189e8851c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa4b3aed39eb2a1dc6eae4609d9909724e211c153927c230d02bd33add3026959010000008b483045022100a8cebb4f1c58f5ba1af91cb8bd4a2ed4e684e9605f5a9dc8b432ed00922d289d0220251145d2d56f06d936fd0c51fa884b4a6a5fafd0c3318f72fb05a5c9aa372195014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000323d540001976a914167c3e1f10cc3b691c73afbdb211e156e3e3f25c88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000002e4615001976a914290f7d617b75993e770e5606335fa0999a28d71388ac00000000", - "020000000101a5c44e1434a1f9b90652ff5a7fe35ab4ed349db0d73d428b63585dc87178dabb00000000171600143e5913dd0fdf12a0d4dd68007a55d734ef938dc1fdffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a9140a5996dceab48274e3f915eb4db2c90ea26922ac88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914963f9bef50bf71a46a0a674b6f16f6d8ae2f61a5870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a01000000000000163000007900000000000247304402202fc73aad6932e25b3cb2a7da3213189bcdb4dbacceb5687ff713751d85e66f570220232951e9e820b3cdabb5c827ef9499e98aa90cd9275ea223f6f40549a940e596012103cbc1315ebc3d91dde32682be3c763260004cf60840908e72a50f4e59dfe7175700000000000000", - }, - []int{912, 1868, 10668, 1136}, - []int{228, 467, 2667, 284}, - } - - for i, str := range tests.hex { - tx, err := NewTxFromHex(str) +func TestSize(t *testing.T) { + file, err := ioutil.ReadFile("data/tx_valid.json") + if err != nil { + t.Fatal(err) + } + var tests map[string]interface{} + json.Unmarshal(file, &tests) + + for _, v := range tests["txSize"].([]interface{}) { + testVector := v.(map[string]interface{}) + tx, err := NewTxFromHex(testVector["txHex"].(string)) if err != nil { t.Fatal(err) } - if res := tx.Weight(); res != tests.weight[i] { - t.Fatalf("Got: %d, expected: %d", res, tests.weight[i]) + + expectedWeight := int(testVector["expectedWeight"].(float64)) + expectedVsize := int(testVector["expectedVsize"].(float64)) + if res := tx.Weight(); res != expectedWeight { + t.Fatalf("Got: %d, expected: %d", res, expectedWeight) } - if res := tx.VirtualSize(); res != tests.vsize[i] { - t.Fatalf("Got: %d, expected: %d", res, tests.vsize[i]) + if res := tx.VirtualSize(); res != expectedVsize { + t.Fatalf("Got: %d, expected: %d", res, expectedVsize) } } } -func testCopy(t *testing.T) { - tests := struct { - hex []string - }{ - []string{ - "010000000001f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b4830450221008732a460737d956fd94d49a31890b2908f7ed7025a9c1d0f25e43290f1841716022004fa7d608a291d44ebbbebbadaac18f943031e7de39ef3bf9920998c43e60c0401210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798ffffffff0101e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000186a0001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac00000000", - "010000000002f1fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe000000006b483045022100e661badd8d2cf1af27eb3b82e61b5d3f5d5512084591796ae31487f5b82df948022006df3c2a2cac79f68e4b179f4bbb8185a0bb3c4a2486d4405c59b2ba07a74c2101210279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798fffffffff2fefefefefefefefefefefefefefefefefefefefefefefefefefefefefefefe0100000083483045022100be54a46a44fb7e6bf4ebf348061d0dace7ddcbb92d4147ce181cf4789c7061f0022068ccab2a89a47fc29bb5074bca99ae846ab446eecf3c3aaeb238a13838783c78012102c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee517a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc7687000000800201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000000c350001976a914c42e7ef92fdb603af844d064faad95db9bcdfd3d88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000000249f00017a9147ccb85f0ab2d599bc17246c98babd5a20b1cdc768700000000", - "01000000000ee7b73e229790c1e79a02f0c871813b3cf26a4156c5b8d942e88b38fe8d3f43a0000000008c493046022100fd3d8fef44fb0962ba3f07bee1d4cafb84e60e38e6c7d9274504b3638a8d2f520221009fce009044e615b6883d4bf62e04c48f9fe236e19d644b082b2f0ae5c98e045c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff7bfc005f3880a606027c7cd7dd02a0f6a6572eeb84a91aa158311be13695a7ea010000008b483045022100e2e61c40f26e2510b76dc72ea2f568ec514fce185c719e18bca9caaef2b20e9e02207f1100fc79eb0584e970c7f18fb226f178951d481767b4092d50d13c50ccba8b014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0e0f8e6bf951fbb84d7d8ef833a1cbf5bb046ea7251973ac6e7661c755386ee3010000008a473044022048f1611e403710f248f7caf479965a6a5f63cdfbd9a714fef4ec1b68331ade1d022074919e79376c363d4575b2fc21513d5949471703efebd4c5ca2885e810eb1fa4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b000000008b483045022100886c07cad489dfcf4b364af561835d5cf985f07adf8bd1d5bd6ddea82b0ce6b2022045bdcbcc2b5fc55191bb997039cf59ff70e8515c56b62f293a9add770ba26738014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffe6f17f35bf9f0aa7a4242ab3e29edbdb74c5274bf263e53043dddb8045cb585b010000008a4730440220535d49b819fdf294d27d82aff2865ed4e18580f0ca9796d793f611cb43a44f47022019584d5e300c415f642e37ba2a814a1e1106b4a9b91dc2a30fb57ceafe041181014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffd3051677216ea53baa2e6d7f6a75434ac338438c59f314801c8496d1e6d1bf6d010000008b483045022100bf612b0fa46f49e70ab318ca3458d1ed5f59727aa782f7fac5503f54d9b43a590220358d7ed0e3cee63a5a7e972d9fad41f825d95de2fd0c5560382468610848d489014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff1e751ccc4e7d973201e9174ec78ece050ef2fadd6a108f40f76a9fa314979c31010000008b483045022006e263d5f73e05c48a603e3bd236e8314e5420721d5e9020114b93e8c9220e1102210099d3dead22f4a792123347a238c87e67b55b28a94a0bb7793144cc7ad94a0168014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff25c4cf2c61743b3f4252d921d937cca942cf32e4f3fa4a544d0b26f014337084010000008a47304402207d6e87588be47bf2d97eaf427bdd992e9d6b306255711328aee38533366a88b50220623099595ae442cb77eaddb3f91753a4fc9df56fde69cfec584c7f97e05533c8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffecd93c87eb43c48481e6694904305349bdea94b01104579fa9f02bff66c89663010000008a473044022020f59498aee0cf82cb113768ef3cb721000346d381ff439adb4d405f791252510220448de723aa59412266fabbc689ec25dc94b1688c27a614982047513a80173514014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa1fdc0a79ff98d5b6154176e321c22f4f8450dbd950bd013ad31135f5604411e010000008b48304502210088167867f87327f9c0db0444267ff0b6a026eedd629d8f16fe44a34c18e706bf0220675c8baebf89930e2d6e4463adefc50922653af99375242e38f5ee677418738a014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffb89e8249c3573b58bf1ec7433185452dd57ab8e1daab01c3cc6ddc8b66ad3de8000000008b4830450220073d50ac5ec8388d5b3906921f9368c31ad078c8e1fb72f26d36b533f35ee327022100c398b23e6692e11dca8a1b64aae2ff70c6a781ed5ee99181b56a2f583a967cd4014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff45ee07e182084454dacfad1e61b04ffdf9c7b01003060a6c841a01f4fff8a5a0010000008b483045022100991d1bf60c41358f08b20e53718a24e05ac0608915df4f6305a5b47cb61e5da7022003f14fc1cc5b737e2c3279a4f9be1852b49dbb3d9d6cc4c8af6a666f600dced8014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff4cba12549f1d70f8e60aea8b546c8357f7c099e7c7d9d8691d6ee16e7dfa3170010000008c493046022100f14e2b0ef8a8e206db350413d204bc0a5cd779e556b1191c2d30b5ec023cde6f022100b90b2d2bf256c98a88f7c3a653b93cec7d25bb6a517db9087d11dbd189e8851c014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffffa4b3aed39eb2a1dc6eae4609d9909724e211c153927c230d02bd33add3026959010000008b483045022100a8cebb4f1c58f5ba1af91cb8bd4a2ed4e684e9605f5a9dc8b432ed00922d289d0220251145d2d56f06d936fd0c51fa884b4a6a5fafd0c3318f72fb05a5c9aa372195014104aa592c859fd00ed2a02609aad3a1bf72e0b42de67713e632c70a33cc488c15598a0fb419370a54d1c275b44380e8777fc01b6dc3cd43a416c6bab0e30dc1e19fffffffff0201e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d01000000000323d540001976a914167c3e1f10cc3b691c73afbdb211e156e3e3f25c88ac01e44bd3955e62587468668f367b4702cdcc480454aeedc65c6a3d018e4e61ae3d0100000000002e4615001976a914290f7d617b75993e770e5606335fa0999a28d71388ac00000000", - "020000000101a5c44e1434a1f9b90652ff5a7fe35ab4ed349db0d73d428b63585dc87178dabb00000000171600143e5913dd0fdf12a0d4dd68007a55d734ef938dc1fdffffff030125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5e100001976a9140a5996dceab48274e3f915eb4db2c90ea26922ac88ac0125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a010000000005f5cad00017a914963f9bef50bf71a46a0a674b6f16f6d8ae2f61a5870125b251070e29ca19043cf33ccd7324e2ddab03ecc4ae0b5e77c4fc0e5cf6c95a01000000000000163000007900000000000247304402202fc73aad6932e25b3cb2a7da3213189bcdb4dbacceb5687ff713751d85e66f570220232951e9e820b3cdabb5c827ef9499e98aa90cd9275ea223f6f40549a940e596012103cbc1315ebc3d91dde32682be3c763260004cf60840908e72a50f4e59dfe7175700000000000000", - }, +func TestCopy(t *testing.T) { + file, err := ioutil.ReadFile("data/tx_valid.json") + if err != nil { + t.Fatal(err) } + var tests map[string]interface{} + json.Unmarshal(file, &tests) - for _, str := range tests.hex { - tx, err := NewTxFromHex(str) + for _, str := range tests["txCopy"].([]interface{}) { + tx, err := NewTxFromHex(str.(string)) if err != nil { t.Fatal(err) } @@ -182,3 +154,67 @@ func testCopy(t *testing.T) { } } } + +func TestHashForSignature(t *testing.T) { + file, err := ioutil.ReadFile("data/tx_valid.json") + if err != nil { + t.Fatal(err) + } + var tests map[string]interface{} + json.Unmarshal(file, &tests) + + for _, v := range tests["txHashForSignature"].([]interface{}) { + testVector := v.(map[string]interface{}) + tx, err := NewTxFromHex(testVector["txHex"].(string)) + if err != nil { + t.Fatal(err) + } + inIndex := int(testVector["inIndex"].(float64)) + script, _ := hex.DecodeString(testVector["script"].(string)) + hashType := txscript.SigHashType(testVector["hashType"].(float64)) + hash, err := tx.HashForSignature(inIndex, script, hashType) + if err != nil { + t.Fatal(err) + } + expectedHash := testVector["expectedHash"].(string) + if res := hex.EncodeToString(hash[:]); res != expectedHash { + t.Fatalf("Got: %s, expected: %s", res, expectedHash) + } + } +} + +func TestHashForWitnessV0(t *testing.T) { + file, err := ioutil.ReadFile("data/tx_valid.json") + if err != nil { + t.Fatal(err) + } + var tests map[string]interface{} + json.Unmarshal(file, &tests) + + for _, v := range tests["txHashForWitnessV0"].([]interface{}) { + testVector := v.(map[string]interface{}) + tx, err := NewTxFromHex(testVector["txHex"].(string)) + if err != nil { + t.Fatal(err) + } + inIndex := int(testVector["inIndex"].(float64)) + script, _ := hex.DecodeString(testVector["script"].(string)) + hashType := txscript.SigHashType(testVector["hashType"].(float64)) + value, _ := toConfidentialValue(int(testVector["amount"].(float64))) + + hash := tx.HashForWitnessV0(inIndex, script, value, hashType) + expectedHash := testVector["expectedHash"].(string) + if res := hex.EncodeToString(hash[:]); res != expectedHash { + t.Fatalf("Got: %s, expected: %s", res, expectedHash) + } + } +} + +func toConfidentialValue(val int) ([]byte, error) { + unconfPrefix := byte(1) + b := bytes.NewBuffer([]byte{}) + if err := BinarySerializer.PutUint64(b, binary.LittleEndian, uint64(val)); err != nil { + return nil, err + } + return append([]byte{unconfPrefix}, bufferutil.ReverseBytes(b.Bytes())...), nil +}