From 8823d79651928c34533f2204e57fe2fac38360b0 Mon Sep 17 00:00:00 2001 From: Satchmo Date: Tue, 10 Sep 2024 08:47:08 -0400 Subject: [PATCH 01/10] add sign unsigned and check for uncomputed change --- CHANGELOG.md | 11 +++++++++++ transaction/transaction.go | 29 ++++++++++++++++++++++++++++- 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b0a788db..ef05e7b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file. The format ## Table of Contents - [Unreleased](#unreleased) +- [1.1.7 - 2024-09-10](#117---2024-09-10) - [1.1.6 - 2024-09-09](#116---2024-09-09) - [1.1.5 - 2024-09-06](#115---2024-09-06) - [1.1.4 - 2024-09-05](#114---2024-09-05) @@ -14,6 +15,16 @@ All notable changes to this project will be documented in this file. The format - [1.1.0 - 2024-08-19](#110---2024-08-19) - [1.0.0 - 2024-06-06](#100---2024-06-06) + +## [1.1.7] - 2024-09-10 + - Introduce `tx.ShallowClone()` + - Introduce SignUnsigned to sign only inputs that have not already been signed + - Other minor performance improvements. + + ### Added + - New method `Transaction.ShallowClone()` + - New method `Transaction.SignUnsigned()` + ## [1.1.6] - 2024-09-09 - Optimize handling of source transaction inputs. Avoid mocking up entire transaction when adding source inputs. - Minor alignment in ECIES helper function diff --git a/transaction/transaction.go b/transaction/transaction.go index bcffb360..de3e833d 100644 --- a/transaction/transaction.go +++ b/transaction/transaction.go @@ -12,6 +12,7 @@ import ( crypto "github.com/bitcoin-sv/go-sdk/primitives/hash" "github.com/bitcoin-sv/go-sdk/script" "github.com/bitcoin-sv/go-sdk/util" + "github.com/pkg/errors" ) type Transaction struct { @@ -325,7 +326,6 @@ func (tx *Transaction) Clone() *Transaction { if input.SourceTransaction != nil { clone.Inputs[i].SourceTransaction = input.SourceTransaction.Clone() } - // clone.Inputs[i].SourceTransaction = input.SourceTransaction clone.Inputs[i].sourceOutput = input.sourceOutput } @@ -437,6 +437,7 @@ func (tx *Transaction) AddMerkleProof(bump *MerklePath) error { } func (tx *Transaction) Sign() error { + tx.checkFeeCompluted() for vin, i := range tx.Inputs { if i.UnlockingScriptTemplate != nil { unlock, err := i.UnlockingScriptTemplate.Sign(tx, uint32(vin)) @@ -448,3 +449,29 @@ func (tx *Transaction) Sign() error { } return nil } + +func (tx *Transaction) SignUnsigned() error { + tx.checkFeeCompluted() + for vin, i := range tx.Inputs { + if i.UnlockingScript == nil { + if i.UnlockingScriptTemplate != nil { + unlock, err := i.UnlockingScriptTemplate.Sign(tx, uint32(vin)) + if err != nil { + return err + } + i.UnlockingScript = unlock + } + } + } + return nil +} + +func (tx *Transaction) checkFeeCompluted() error { + for _, out := range tx.Outputs { + if out.Satoshis == 0 { + if out.Change { + return errors.New("There are still change outputs with uncomputed amounts. Use the Fee() method to compute the change amounts and transaction fees prior to signing.") + } + } + } +} From 295103b3643dc3f95ba7104eba8102c889046875 Mon Sep 17 00:00:00 2001 From: Satchmo Date: Tue, 10 Sep 2024 09:08:39 -0400 Subject: [PATCH 02/10] Add comments on sign methods --- transaction/transaction.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/transaction/transaction.go b/transaction/transaction.go index de3e833d..3293e20e 100644 --- a/transaction/transaction.go +++ b/transaction/transaction.go @@ -436,6 +436,7 @@ func (tx *Transaction) AddMerkleProof(bump *MerklePath) error { return nil } +// Fee returns the fee of the transaction. func (tx *Transaction) Sign() error { tx.checkFeeCompluted() for vin, i := range tx.Inputs { @@ -450,6 +451,7 @@ func (tx *Transaction) Sign() error { return nil } +// SignUnsigned signs the transaction without the unlocking script. func (tx *Transaction) SignUnsigned() error { tx.checkFeeCompluted() for vin, i := range tx.Inputs { @@ -474,4 +476,5 @@ func (tx *Transaction) checkFeeCompluted() error { } } } + return nil } From bd93a7f309788743528bfd51a7959fa37cf801f3 Mon Sep 17 00:00:00 2001 From: Satchmo Date: Tue, 10 Sep 2024 09:11:35 -0400 Subject: [PATCH 03/10] lint --- transaction/transaction.go | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/transaction/transaction.go b/transaction/transaction.go index 3293e20e..c6e5fc78 100644 --- a/transaction/transaction.go +++ b/transaction/transaction.go @@ -438,7 +438,10 @@ func (tx *Transaction) AddMerkleProof(bump *MerklePath) error { // Fee returns the fee of the transaction. func (tx *Transaction) Sign() error { - tx.checkFeeCompluted() + err := tx.checkFeeComputed() + if err != nil { + return err + } for vin, i := range tx.Inputs { if i.UnlockingScriptTemplate != nil { unlock, err := i.UnlockingScriptTemplate.Sign(tx, uint32(vin)) @@ -453,7 +456,10 @@ func (tx *Transaction) Sign() error { // SignUnsigned signs the transaction without the unlocking script. func (tx *Transaction) SignUnsigned() error { - tx.checkFeeCompluted() + err := tx.checkFeeComputed() + if err != nil { + return err + } for vin, i := range tx.Inputs { if i.UnlockingScript == nil { if i.UnlockingScriptTemplate != nil { @@ -468,12 +474,10 @@ func (tx *Transaction) SignUnsigned() error { return nil } -func (tx *Transaction) checkFeeCompluted() error { +func (tx *Transaction) checkFeeComputed() error { for _, out := range tx.Outputs { - if out.Satoshis == 0 { - if out.Change { - return errors.New("There are still change outputs with uncomputed amounts. Use the Fee() method to compute the change amounts and transaction fees prior to signing.") - } + if out.Satoshis == 0 && out.Change { + return errors.New("fee not computed") } } return nil From 69c01eef2c38e2f957c897f2e23d94b9bddfb0a3 Mon Sep 17 00:00:00 2001 From: Satchmo Date: Tue, 10 Sep 2024 09:15:30 -0400 Subject: [PATCH 04/10] add fee not computed test --- transaction/transaction_test.go | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/transaction/transaction_test.go b/transaction/transaction_test.go index ac05eedc..90c2c819 100644 --- a/transaction/transaction_test.go +++ b/transaction/transaction_test.go @@ -79,7 +79,7 @@ func TestEF(t *testing.T) { }) } -func Benchmark_ShallowClone(b *testing.B) { +func BenchmarkShallowClone(b *testing.B) { tx, _ := transaction.NewTransactionFromHex("0200000003a9bc457fdc6a54d99300fb137b23714d860c350a9d19ff0f571e694a419ff3a0010000006b48304502210086c83beb2b2663e4709a583d261d75be538aedcafa7766bd983e5c8db2f8b2fc02201a88b178624ab0ad1748b37c875f885930166237c88f5af78ee4e61d337f935f412103e8be830d98bb3b007a0343ee5c36daa48796ae8bb57946b1e87378ad6e8a090dfeffffff0092bb9a47e27bf64fc98f557c530c04d9ac25e2f2a8b600e92a0b1ae7c89c20010000006b483045022100f06b3db1c0a11af348401f9cebe10ae2659d6e766a9dcd9e3a04690ba10a160f02203f7fbd7dfcfc70863aface1a306fcc91bbadf6bc884c21a55ef0d32bd6b088c8412103e8be830d98bb3b007a0343ee5c36daa48796ae8bb57946b1e87378ad6e8a090dfeffffff9d0d4554fa692420a0830ca614b6c60f1bf8eaaa21afca4aa8c99fb052d9f398000000006b483045022100d920f2290548e92a6235f8b2513b7f693a64a0d3fa699f81a034f4b4608ff82f0220767d7d98025aff3c7bd5f2a66aab6a824f5990392e6489aae1e1ae3472d8dffb412103e8be830d98bb3b007a0343ee5c36daa48796ae8bb57946b1e87378ad6e8a090dfeffffff02807c814a000000001976a9143a6bf34ebfcf30e8541bbb33a7882845e5a29cb488ac76b0e60e000000001976a914bd492b67f90cb85918494767ebb23102c4f06b7088ac67000000") b.Run("clone", func(b *testing.B) { @@ -89,3 +89,15 @@ func Benchmark_ShallowClone(b *testing.B) { } }) } + +func TestUncomputedFee(t *testing.T) { + tx, _ := transaction.NewTransactionFromBEEFHex(BRC62Hex) + + tx.AddOutput(&transaction.TransactionOutput{ + Change: true, + LockingScript: tx.Outputs[0].LockingScript, + }) + + err := tx.Sign() + require.Error(t, err) +} From d2dfdb999528d57d9b14f88b7c68d11ceb980e45 Mon Sep 17 00:00:00 2001 From: Satchmo Date: Tue, 10 Sep 2024 09:28:08 -0400 Subject: [PATCH 05/10] add tests for signunsigned --- transaction/transaction_test.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/transaction/transaction_test.go b/transaction/transaction_test.go index 90c2c819..c7debac9 100644 --- a/transaction/transaction_test.go +++ b/transaction/transaction_test.go @@ -101,3 +101,30 @@ func TestUncomputedFee(t *testing.T) { err := tx.Sign() require.Error(t, err) } + +func TestSignUnsigned(t *testing.T) { + tx, err := transaction.NewTransactionFromBEEFHex(BRC62Hex) + require.NoError(t, err) + + cloneTx := tx.ShallowClone() + pk, _ := ec.NewPrivateKey() + + // Adding a script template with random key so sigs will be different + for i := range tx.Inputs { + cloneTx.Inputs[i].UnlockingScriptTemplate, err = p2pkh.Unlock(pk, nil) + require.NoError(t, err) + } + + // This should do nothing because the inputs from hex are already signed + err = cloneTx.SignUnsigned() + require.NoError(t, err) + for i := range cloneTx.Inputs { + require.Equal(t, tx.Inputs[i].UnlockingScript, cloneTx.Inputs[i].UnlockingScript) + } + + // This should sign the inputs with the incorrect key which should change the sigs + cloneTx.Sign() + for i := range tx.Inputs { + require.NotEqual(t, tx.Inputs[i].UnlockingScript, cloneTx.Inputs[i].UnlockingScript) + } +} From 22df5933feca4dbc7d6c3b23bfd4651293c21350 Mon Sep 17 00:00:00 2001 From: Satchmo Date: Tue, 10 Sep 2024 09:34:10 -0400 Subject: [PATCH 06/10] rename shallowClone to clone, add test for clone --- script/interpreter/operations.go | 4 ++-- transaction/signaturehash.go | 2 +- transaction/transaction.go | 26 ++++---------------------- transaction/transaction_test.go | 12 ++++++++++-- 4 files changed, 17 insertions(+), 27 deletions(-) diff --git a/script/interpreter/operations.go b/script/interpreter/operations.go index c0b20263..99d06d2d 100644 --- a/script/interpreter/operations.go +++ b/script/interpreter/operations.go @@ -2016,7 +2016,7 @@ func opcodeCheckSig(op *ParsedOpcode, t *thread) error { return err } - txCopy := t.tx.ShallowClone() + txCopy := t.tx.Clone() sourceTxOut := txCopy.Inputs[t.inputIdx].SourceTxOutput() sourceTxOut.LockingScript = up @@ -2282,7 +2282,7 @@ func opcodeCheckMultiSig(op *ParsedOpcode, t *thread) error { } // Generate the signature hash based on the signature hash type. - txCopy := t.tx.ShallowClone() + txCopy := t.tx.Clone() input := txCopy.Inputs[t.inputIdx] sourceOut := input.SourceTxOutput() if sourceOut != nil { diff --git a/transaction/signaturehash.go b/transaction/signaturehash.go index 9c4e2086..dca8873a 100644 --- a/transaction/signaturehash.go +++ b/transaction/signaturehash.go @@ -188,7 +188,7 @@ func (tx *Transaction) CalcInputPreimageLegacy(inputNumber uint32, shf sighash.F return defaultHex, nil } - txCopy := tx.ShallowClone() + txCopy := tx.Clone() for i := range txCopy.Inputs { if i == int(inputNumber) { diff --git a/transaction/transaction.go b/transaction/transaction.go index c6e5fc78..afb9215b 100644 --- a/transaction/transaction.go +++ b/transaction/transaction.go @@ -5,7 +5,6 @@ import ( "encoding/binary" "encoding/hex" "io" - "log" "slices" "github.com/bitcoin-sv/go-sdk/chainhash" @@ -314,25 +313,7 @@ func (tx *Transaction) BytesWithClearedInputs(index int, lockingScript []byte) [ return tx.toBytesHelper(index, lockingScript, false) } -// Clone returns a clone of the tx func (tx *Transaction) Clone() *Transaction { - // Ignore err as byte slice passed in is created from valid tx - clone, err := NewTransactionFromBytes(tx.Bytes()) - if err != nil { - log.Fatal(err) - } - - for i, input := range tx.Inputs { - if input.SourceTransaction != nil { - clone.Inputs[i].SourceTransaction = input.SourceTransaction.Clone() - } - clone.Inputs[i].sourceOutput = input.sourceOutput - } - - return clone -} - -func (tx *Transaction) ShallowClone() *Transaction { // Creating a new Tx from scratch is much faster than cloning from bytes // ~ 420ns/op vs 2200ns/op of the above function in benchmarking // this matters as we clone txs a couple of times when verifying signatures @@ -345,9 +326,10 @@ func (tx *Transaction) ShallowClone() *Transaction { for i, input := range tx.Inputs { clone.Inputs[i] = &TransactionInput{ - SourceTXID: (*chainhash.Hash)(input.SourceTXID[:]), - SourceTxOutIndex: input.SourceTxOutIndex, - SequenceNumber: input.SequenceNumber, + SourceTXID: (*chainhash.Hash)(input.SourceTXID[:]), + SourceTxOutIndex: input.SourceTxOutIndex, + SequenceNumber: input.SequenceNumber, + UnlockingScriptTemplate: input.UnlockingScriptTemplate, } if input.UnlockingScript != nil { clone.Inputs[i].UnlockingScript = input.UnlockingScript diff --git a/transaction/transaction_test.go b/transaction/transaction_test.go index c7debac9..42b3c16c 100644 --- a/transaction/transaction_test.go +++ b/transaction/transaction_test.go @@ -79,12 +79,20 @@ func TestEF(t *testing.T) { }) } +func TestClone(t *testing.T) { + tx, err := transaction.NewTransactionFromBEEFHex(BRC62Hex) + require.NoError(t, err) + + clone := tx.Clone() + require.Equal(t, tx.Bytes(), clone.Bytes()) +} + func BenchmarkShallowClone(b *testing.B) { tx, _ := transaction.NewTransactionFromHex("0200000003a9bc457fdc6a54d99300fb137b23714d860c350a9d19ff0f571e694a419ff3a0010000006b48304502210086c83beb2b2663e4709a583d261d75be538aedcafa7766bd983e5c8db2f8b2fc02201a88b178624ab0ad1748b37c875f885930166237c88f5af78ee4e61d337f935f412103e8be830d98bb3b007a0343ee5c36daa48796ae8bb57946b1e87378ad6e8a090dfeffffff0092bb9a47e27bf64fc98f557c530c04d9ac25e2f2a8b600e92a0b1ae7c89c20010000006b483045022100f06b3db1c0a11af348401f9cebe10ae2659d6e766a9dcd9e3a04690ba10a160f02203f7fbd7dfcfc70863aface1a306fcc91bbadf6bc884c21a55ef0d32bd6b088c8412103e8be830d98bb3b007a0343ee5c36daa48796ae8bb57946b1e87378ad6e8a090dfeffffff9d0d4554fa692420a0830ca614b6c60f1bf8eaaa21afca4aa8c99fb052d9f398000000006b483045022100d920f2290548e92a6235f8b2513b7f693a64a0d3fa699f81a034f4b4608ff82f0220767d7d98025aff3c7bd5f2a66aab6a824f5990392e6489aae1e1ae3472d8dffb412103e8be830d98bb3b007a0343ee5c36daa48796ae8bb57946b1e87378ad6e8a090dfeffffff02807c814a000000001976a9143a6bf34ebfcf30e8541bbb33a7882845e5a29cb488ac76b0e60e000000001976a914bd492b67f90cb85918494767ebb23102c4f06b7088ac67000000") b.Run("clone", func(b *testing.B) { for i := 0; i < b.N; i++ { - clone := tx.ShallowClone() + clone := tx.Clone() _ = clone } }) @@ -106,7 +114,7 @@ func TestSignUnsigned(t *testing.T) { tx, err := transaction.NewTransactionFromBEEFHex(BRC62Hex) require.NoError(t, err) - cloneTx := tx.ShallowClone() + cloneTx := tx.Clone() pk, _ := ec.NewPrivateKey() // Adding a script template with random key so sigs will be different From 32a4cb2e513061b6dab5e1b5279711f43898f4cf Mon Sep 17 00:00:00 2001 From: Satchmo Date: Tue, 10 Sep 2024 09:35:51 -0400 Subject: [PATCH 07/10] update changelog --- CHANGELOG.md | 7 +++++-- transaction/transaction_test.go | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef05e7b5..201d2d12 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,14 +17,17 @@ All notable changes to this project will be documented in this file. The format ## [1.1.7] - 2024-09-10 - - Introduce `tx.ShallowClone()` + - Rework `tx.Clone()` to be more efficient - Introduce SignUnsigned to sign only inputs that have not already been signed + - Added tests - Other minor performance improvements. ### Added - - New method `Transaction.ShallowClone()` - New method `Transaction.SignUnsigned()` + ### Changed + - `Transaction.Clone()` does not reconstitute the source transaction from bytes. Creates a new transaction. + ## [1.1.6] - 2024-09-09 - Optimize handling of source transaction inputs. Avoid mocking up entire transaction when adding source inputs. - Minor alignment in ECIES helper function diff --git a/transaction/transaction_test.go b/transaction/transaction_test.go index 42b3c16c..01413880 100644 --- a/transaction/transaction_test.go +++ b/transaction/transaction_test.go @@ -87,7 +87,7 @@ func TestClone(t *testing.T) { require.Equal(t, tx.Bytes(), clone.Bytes()) } -func BenchmarkShallowClone(b *testing.B) { +func BenchmarkClone(b *testing.B) { tx, _ := transaction.NewTransactionFromHex("0200000003a9bc457fdc6a54d99300fb137b23714d860c350a9d19ff0f571e694a419ff3a0010000006b48304502210086c83beb2b2663e4709a583d261d75be538aedcafa7766bd983e5c8db2f8b2fc02201a88b178624ab0ad1748b37c875f885930166237c88f5af78ee4e61d337f935f412103e8be830d98bb3b007a0343ee5c36daa48796ae8bb57946b1e87378ad6e8a090dfeffffff0092bb9a47e27bf64fc98f557c530c04d9ac25e2f2a8b600e92a0b1ae7c89c20010000006b483045022100f06b3db1c0a11af348401f9cebe10ae2659d6e766a9dcd9e3a04690ba10a160f02203f7fbd7dfcfc70863aface1a306fcc91bbadf6bc884c21a55ef0d32bd6b088c8412103e8be830d98bb3b007a0343ee5c36daa48796ae8bb57946b1e87378ad6e8a090dfeffffff9d0d4554fa692420a0830ca614b6c60f1bf8eaaa21afca4aa8c99fb052d9f398000000006b483045022100d920f2290548e92a6235f8b2513b7f693a64a0d3fa699f81a034f4b4608ff82f0220767d7d98025aff3c7bd5f2a66aab6a824f5990392e6489aae1e1ae3472d8dffb412103e8be830d98bb3b007a0343ee5c36daa48796ae8bb57946b1e87378ad6e8a090dfeffffff02807c814a000000001976a9143a6bf34ebfcf30e8541bbb33a7882845e5a29cb488ac76b0e60e000000001976a914bd492b67f90cb85918494767ebb23102c4f06b7088ac67000000") b.Run("clone", func(b *testing.B) { From f1b38fa7c12b9112ec72ea464c99b5ebc0ed92a1 Mon Sep 17 00:00:00 2001 From: Satchmo Date: Tue, 10 Sep 2024 09:44:39 -0400 Subject: [PATCH 08/10] add transaction tests --- transaction/transaction_test.go | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/transaction/transaction_test.go b/transaction/transaction_test.go index 01413880..bc6295bb 100644 --- a/transaction/transaction_test.go +++ b/transaction/transaction_test.go @@ -1,6 +1,7 @@ package transaction_test import ( + "encoding/hex" "testing" ec "github.com/bitcoin-sv/go-sdk/primitives/ec" @@ -57,6 +58,19 @@ func TestNewTransaction(t *testing.T) { }) } +func TestIsCoinbase(t *testing.T) { + tx, err := transaction.NewTransactionFromHex("01000000010000000000000000000000000000000000000000000000000000000000000000ffffffff17033f250d2f43555656452f2c903fb60859897700d02700ffffffff01d864a012000000001976a914d648686cf603c11850f39600e37312738accca8f88ac00000000") + require.NoError(t, err) + require.True(t, tx.IsCoinbase()) +} + +func TestIsValidTxID(t *testing.T) { + valid, _ := hex.DecodeString("fe77aa03d5563d3ec98455a76655ea3b58e19a4eb102baf7b2a47af37e94b295") + require.True(t, transaction.IsValidTxID(valid)) + invalid, _ := hex.DecodeString("fe77aa03d5563d3ec98455a76655ea3b58e19a4eb102baf7b2a47af37e94b2") + require.False(t, transaction.IsValidTxID(invalid)) +} + func TestBEEF(t *testing.T) { t.Parallel() t.Run("deserialize and serialize", func(t *testing.T) { From 7f27c0f9efb16d3b40214f1e7d1850b139dcf2bf Mon Sep 17 00:00:00 2001 From: Satchmo Date: Tue, 10 Sep 2024 09:47:10 -0400 Subject: [PATCH 09/10] additional tx tests --- transaction/transaction_test.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/transaction/transaction_test.go b/transaction/transaction_test.go index bc6295bb..6c891dfa 100644 --- a/transaction/transaction_test.go +++ b/transaction/transaction_test.go @@ -122,6 +122,9 @@ func TestUncomputedFee(t *testing.T) { err := tx.Sign() require.Error(t, err) + + err = tx.SignUnsigned() + require.Error(t, err) } func TestSignUnsigned(t *testing.T) { From e028a9526c09d9177211a34eb214afbaf1155975 Mon Sep 17 00:00:00 2001 From: Satchmo Date: Tue, 10 Sep 2024 10:06:11 -0400 Subject: [PATCH 10/10] test sign unsigned from new transaction --- transaction/transaction_test.go | 35 +++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/transaction/transaction_test.go b/transaction/transaction_test.go index 6c891dfa..e7bd3bca 100644 --- a/transaction/transaction_test.go +++ b/transaction/transaction_test.go @@ -4,6 +4,7 @@ import ( "encoding/hex" "testing" + "github.com/bitcoin-sv/go-sdk/chainhash" ec "github.com/bitcoin-sv/go-sdk/primitives/ec" "github.com/bitcoin-sv/go-sdk/script" "github.com/bitcoin-sv/go-sdk/transaction" @@ -153,3 +154,37 @@ func TestSignUnsigned(t *testing.T) { require.NotEqual(t, tx.Inputs[i].UnlockingScript, cloneTx.Inputs[i].UnlockingScript) } } + +func TestSignUnsignedNew(t *testing.T) { + pk, _ := ec.PrivateKeyFromWif("L1y6DgX4TuonxXzRPuk9reK2TD2THjwQReNUwVrvWN3aRkjcbauB") + address, _ := script.NewAddressFromPublicKey(pk.PubKey(), true) + tx := transaction.NewTransaction() + lockingScript, err := p2pkh.Lock(address) + require.NoError(t, err) + sourceTxID, _ := chainhash.NewHashFromHex("fe77aa03d5563d3ec98455a76655ea3b58e19a4eb102baf7b2a47af37e94b295") + unlockingScript, _ := p2pkh.Unlock(pk, nil) + tx.AddInput(&transaction.TransactionInput{ + SourceTransaction: &transaction.Transaction{ + Outputs: []*transaction.TransactionOutput{ + { + Satoshis: 1, + LockingScript: lockingScript, + }, + }, + }, + SourceTXID: sourceTxID, + UnlockingScriptTemplate: unlockingScript, + }) + + tx.AddOutput(&transaction.TransactionOutput{ + Satoshis: 1, + LockingScript: lockingScript, + }) + + err = tx.SignUnsigned() + require.NoError(t, err) + + for _, input := range tx.Inputs { + require.Positive(t, len(input.UnlockingScript.Bytes())) + } +}