diff --git a/script/interpreter/operations.go b/script/interpreter/operations.go index c263079..99d06d2 100644 --- a/script/interpreter/operations.go +++ b/script/interpreter/operations.go @@ -2017,8 +2017,8 @@ func opcodeCheckSig(op *ParsedOpcode, t *thread) error { } txCopy := t.tx.Clone() - txCopy.Inputs[t.inputIdx].SourceTransaction.Outputs[txCopy.Inputs[t.inputIdx].SourceTxOutIndex].LockingScript = up - // txCopy.Inputs[t.inputIdx].SourceTxScript = up + sourceTxOut := txCopy.Inputs[t.inputIdx].SourceTxOutput() + sourceTxOut.LockingScript = up hash, err = txCopy.CalcInputSignatureHash(uint32(t.inputIdx), shf) if err != nil { @@ -2284,7 +2284,10 @@ func opcodeCheckMultiSig(op *ParsedOpcode, t *thread) error { // Generate the signature hash based on the signature hash type. txCopy := t.tx.Clone() input := txCopy.Inputs[t.inputIdx] - input.SourceTransaction.Outputs[input.SourceTxOutIndex].LockingScript = up + sourceOut := input.SourceTxOutput() + if sourceOut != nil { + sourceOut.LockingScript = up + } signatureHash, err := txCopy.CalcInputSignatureHash(uint32(t.inputIdx), shf) if err != nil { diff --git a/script/interpreter/reference_test.go b/script/interpreter/reference_test.go index 8cf49a0..6f3bd4e 100644 --- a/script/interpreter/reference_test.go +++ b/script/interpreter/reference_test.go @@ -323,7 +323,7 @@ func createSpendingTx(sigScript, pkScript *script.Script, outputValue int64) *tr LockingScript: script.NewFromBytes([]byte{}), }}, } - spendingTx.Inputs[0].SetSourceTxFromOutput(&transaction.TransactionOutput{ + spendingTx.Inputs[0].SetSourceTxOutput(&transaction.TransactionOutput{ LockingScript: pkScript, }) @@ -612,7 +612,7 @@ testloop: for k, txin := range tx.Inputs { prevOut, ok := prevOuts[txIOKey{id: txin.SourceTXID.String(), idx: txin.SourceTxOutIndex}] - txin.SetSourceTxFromOutput(prevOut) + txin.SetSourceTxOutput(prevOut) if !ok { t.Errorf("bad test (missing %dth input) %d:%v", k, i, test) @@ -762,7 +762,7 @@ testloop: for k, txin := range tx.Inputs { prevOut, ok := prevOuts[txIOKey{id: txin.SourceTXID.String(), idx: txin.SourceTxOutIndex}] - txin.SetSourceTxFromOutput(prevOut) + txin.SetSourceTxOutput(prevOut) if !ok { t.Errorf("bad test (missing %dth input) %d:%v", k, i, test) diff --git a/script/interpreter/thread.go b/script/interpreter/thread.go index 78b6d1f..3b85933 100644 --- a/script/interpreter/thread.go +++ b/script/interpreter/thread.go @@ -352,7 +352,7 @@ func (t *thread) apply(opts *execOpts) error { t.astack = newStack(t.cfg, t.hasFlag(scriptflag.VerifyMinimalData)) if t.tx != nil { - t.tx.Inputs[t.inputIdx].SetSourceTxFromOutput(&transaction.TransactionOutput{ + t.tx.Inputs[t.inputIdx].SetSourceTxOutput(&transaction.TransactionOutput{ LockingScript: t.prevOutput.LockingScript, Satoshis: t.prevOutput.Satoshis, }) diff --git a/transaction/broadcaster/arc.go b/transaction/broadcaster/arc.go index be4d33e..88ffbe0 100644 --- a/transaction/broadcaster/arc.go +++ b/transaction/broadcaster/arc.go @@ -67,7 +67,7 @@ func (f *ArcResponse) Scan(value interface{}) error { func (a *Arc) Broadcast(t *transaction.Transaction) (*transaction.BroadcastSuccess, *transaction.BroadcastFailure) { var buf *bytes.Buffer for _, input := range t.Inputs { - if input.SourceTransaction == nil { + if input.SourceTxOutput() == nil { buf = bytes.NewBuffer(t.Bytes()) break } diff --git a/transaction/fees.go b/transaction/fees.go index 1e0c84c..de65fde 100644 --- a/transaction/fees.go +++ b/transaction/fees.go @@ -24,10 +24,11 @@ func (tx *Transaction) Fee(f FeeModel, changeDistribution ChangeDistribution) er } satsIn := uint64(0) for _, i := range tx.Inputs { - if i.SourceTransaction == nil { + sourceSats := i.SourceTxSatoshis() + if sourceSats == nil { return ErrEmptyPreviousTx } - satsIn += *i.SourceTxSatoshis() + satsIn += *sourceSats } satsOut := uint64(0) changeOuts := uint64(0) diff --git a/transaction/input.go b/transaction/input.go index 9bd9f6e..2c75f8a 100644 --- a/transaction/input.go +++ b/transaction/input.go @@ -35,21 +35,31 @@ type TransactionInput struct { SourceTxOutIndex uint32 SequenceNumber uint32 SourceTransaction *Transaction + sourceOutput *TransactionOutput UnlockingScriptTemplate UnlockingScriptTemplate } +func (i *TransactionInput) SourceTxOutput() *TransactionOutput { + if i.SourceTransaction != nil { + return i.SourceTransaction.Outputs[i.SourceTxOutIndex] + } + return i.sourceOutput +} + func (i *TransactionInput) SourceTxScript() *script.Script { - if i.SourceTransaction == nil { - return nil + sourceTxOut := i.SourceTxOutput() + if sourceTxOut != nil { + return sourceTxOut.LockingScript } - return i.SourceTransaction.Outputs[i.SourceTxOutIndex].LockingScript + return nil } func (i *TransactionInput) SourceTxSatoshis() *uint64 { - if i.SourceTransaction == nil { - return nil + sourceTxOut := i.SourceTxOutput() + if sourceTxOut != nil { + return &sourceTxOut.Satoshis } - return &i.SourceTransaction.Outputs[i.SourceTxOutIndex].Satoshis + return nil } // ReadFrom reads from the `io.Reader` into the `transaction.TransactionInput`. @@ -132,7 +142,7 @@ func (i *TransactionInput) readFrom(r io.Reader, extended bool) (int64, error) { return bytesRead, errors.Wrapf(err, "script(%d): got %d bytes", scriptLen.Length(), n) } - i.SetSourceTxFromOutput(&TransactionOutput{ + i.SetSourceTxOutput(&TransactionOutput{ Satoshis: binary.LittleEndian.Uint64(prevSatoshis), LockingScript: script.NewFromBytes(scriptBytes), }) @@ -179,9 +189,6 @@ func (i *TransactionInput) Bytes(clear bool) []byte { return append(h, util.LittleEndianBytes(i.SequenceNumber, 4)...) } -func (i *TransactionInput) SetSourceTxFromOutput(txo *TransactionOutput) { - prevTx := &Transaction{} - prevTx.Outputs = make([]*TransactionOutput, i.SourceTxOutIndex+1) - prevTx.Outputs[i.SourceTxOutIndex] = txo - i.SourceTransaction = prevTx +func (i *TransactionInput) SetSourceTxOutput(txo *TransactionOutput) { + i.sourceOutput = txo } diff --git a/transaction/signaturehash.go b/transaction/signaturehash.go index 8f74d60..85c7713 100644 --- a/transaction/signaturehash.go +++ b/transaction/signaturehash.go @@ -67,7 +67,7 @@ func (tx *Transaction) CalcInputPreimage(inputNumber uint32, sigHashFlag sighash if len(in.SourceTXID) == 0 { return nil, ErrEmptyPreviousTxID } - if in.SourceTransaction == nil { + if in.SourceTxOutput() == nil { return nil, ErrEmptyPreviousTx } @@ -160,7 +160,7 @@ func (tx *Transaction) CalcInputPreimageLegacy(inputNumber uint32, shf sighash.F if len(in.SourceTXID) == 0 { return nil, ErrEmptyPreviousTxID } - if in.SourceTransaction == nil { + if in.SourceTxOutput() == nil { return nil, ErrEmptyPreviousTx } @@ -192,10 +192,10 @@ func (tx *Transaction) CalcInputPreimageLegacy(inputNumber uint32, shf sighash.F for i := range txCopy.Inputs { if i == int(inputNumber) { - txCopy.Inputs[i].SourceTransaction = tx.Inputs[inputNumber].SourceTransaction + txCopy.Inputs[i].sourceOutput = in.SourceTxOutput() } else { txCopy.Inputs[i].UnlockingScript = &script.Script{} - txCopy.Inputs[i].SetSourceTxFromOutput(&TransactionOutput{}) + txCopy.Inputs[i].sourceOutput = &TransactionOutput{} } } diff --git a/transaction/signaturehash_test.go b/transaction/signaturehash_test.go index e249252..1e4979d 100644 --- a/transaction/signaturehash_test.go +++ b/transaction/signaturehash_test.go @@ -63,7 +63,7 @@ func TestTx_CalcInputPreimage(t *testing.T) { // Add the UTXO amount and script (PreviousTx already in unsigned tx) prevScript, err := script.NewFromHex(test.SourceTxScript) require.NoError(t, err) - tx.InputIdx(test.index).SetSourceTxFromOutput(&transaction.TransactionOutput{ + tx.InputIdx(test.index).SetSourceTxOutput(&transaction.TransactionOutput{ LockingScript: prevScript, Satoshis: test.previousTxSatoshis, }) @@ -156,7 +156,7 @@ func TestTx_CalcInputSignatureHash(t *testing.T) { // Add the UTXO amount and script (PreviousTx already in unsigned tx) prevScript, err := script.NewFromHex(test.SourceTxScript) require.NoError(t, err) - tx.Inputs[test.index].SetSourceTxFromOutput(&transaction.TransactionOutput{ + tx.Inputs[test.index].SetSourceTxOutput(&transaction.TransactionOutput{ LockingScript: prevScript, Satoshis: test.previousTxSatoshis, }) @@ -222,7 +222,7 @@ func TestTx_CalcInputPreimageLegacy(t *testing.T) { // Add the UTXO amount and script (PreviousTx already in unsigned tx) prevScript, err := script.NewFromHex(test.SourceTxScript) require.NoError(t, err) - tx.Inputs[test.index].SetSourceTxFromOutput(&transaction.TransactionOutput{ + tx.Inputs[test.index].SetSourceTxOutput(&transaction.TransactionOutput{ LockingScript: prevScript, Satoshis: test.previousTxSatoshis, }) diff --git a/transaction/template/p2pkh/p2pkh.go b/transaction/template/p2pkh/p2pkh.go index 0534181..6f01087 100644 --- a/transaction/template/p2pkh/p2pkh.go +++ b/transaction/template/p2pkh/p2pkh.go @@ -47,7 +47,7 @@ type P2PKH struct { } func (p *P2PKH) Sign(tx *transaction.Transaction, inputIndex uint32) (*script.Script, error) { - if tx.Inputs[inputIndex].SourceTransaction == nil { + if tx.Inputs[inputIndex].SourceTxOutput() == nil { return nil, transaction.ErrEmptyPreviousTx } diff --git a/transaction/transaction.go b/transaction/transaction.go index f7cec38..df1266e 100644 --- a/transaction/transaction.go +++ b/transaction/transaction.go @@ -291,7 +291,7 @@ func (tx *Transaction) Bytes() []byte { // (with PreviousTxSatoshis and SourceTxScript included) func (tx *Transaction) EF() ([]byte, error) { for _, in := range tx.Inputs { - if in.SourceTransaction == nil { + if in.SourceTransaction == nil && in.sourceOutput == nil { return nil, ErrEmptyPreviousTx } } @@ -321,10 +321,11 @@ func (tx *Transaction) Clone() *Transaction { } for i, input := range tx.Inputs { - // if input.SourceTransaction != nil { - // clone.Inputs[i].SourceTransaction = input.SourceTransaction.Clone() - // } - clone.Inputs[i].SourceTransaction = input.SourceTransaction + if input.SourceTransaction != nil { + clone.Inputs[i].SourceTransaction = input.SourceTransaction.Clone() + } + // clone.Inputs[i].SourceTransaction = input.SourceTransaction + clone.Inputs[i].sourceOutput = input.sourceOutput } return clone @@ -352,19 +353,16 @@ func (tx *Transaction) toBytesHelper(index int, lockingScript []byte, extended b if extended { b := make([]byte, 8) - prevSats := uint64(0) - if in.SourceTxSatoshis() != nil { - prevSats = *in.SourceTxSatoshis() - } - binary.LittleEndian.PutUint64(b, prevSats) - h = append(h, b...) - - prevScript := in.SourceTxScript() - if prevScript != nil { - l := uint64(len(*prevScript)) + sourceTxOut := in.SourceTxOutput() + if sourceTxOut != nil { + binary.LittleEndian.PutUint64(b, sourceTxOut.Satoshis) + h = append(h, b...) + l := uint64(len(*sourceTxOut.LockingScript)) h = append(h, VarInt(l).Bytes()...) - h = append(h, *prevScript...) + h = append(h, *sourceTxOut.LockingScript...) } else { + binary.LittleEndian.PutUint64(b, 0) + h = append(h, b...) h = append(h, 0x00) // The length of the script is zero } } diff --git a/transaction/txinput.go b/transaction/txinput.go index ad562a0..62234c1 100644 --- a/transaction/txinput.go +++ b/transaction/txinput.go @@ -25,7 +25,7 @@ func (tx *Transaction) AddInput(input *TransactionInput) { } func (tx *Transaction) AddInputWithOutput(input *TransactionInput, output *TransactionOutput) { - input.SetSourceTxFromOutput(output) + input.SetSourceTxOutput(output) tx.Inputs = append(tx.Inputs, input) } @@ -109,7 +109,7 @@ func (tx *Transaction) AddInputsFromUTXOs(utxos ...*UTXO) error { SequenceNumber: DefaultSequenceNumber, // use default finalized sequence number UnlockingScriptTemplate: utxo.UnlockingScriptTemplate, } - i.SetSourceTxFromOutput(&TransactionOutput{ + i.SetSourceTxOutput(&TransactionOutput{ Satoshis: utxo.Satoshis, LockingScript: utxo.LockingScript, })