diff --git a/script/interpreter/operations.go b/script/interpreter/operations.go index c0b2026..99d06d2 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 9c4e208..dca8873 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 c6e5fc7..afb9215 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 c7debac..42b3c16 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