|
1 | 1 | package bt |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "bytes" |
4 | 5 | "encoding/binary" |
5 | 6 | "encoding/hex" |
6 | 7 | "fmt" |
| 8 | + "io" |
7 | 9 |
|
8 | 10 | "github.com/libsv/go-bt/bscript" |
9 | 11 | ) |
@@ -46,28 +48,55 @@ func NewInput() *Input { |
46 | 48 | } |
47 | 49 |
|
48 | 50 | // NewInputFromBytes returns a transaction input from the bytes provided. |
49 | | -func NewInputFromBytes(bytes []byte) (*Input, int, error) { |
50 | | - if len(bytes) < 36 { |
| 51 | +func NewInputFromBytes(b []byte) (*Input, int, error) { |
| 52 | + if len(b) < 36 { |
51 | 53 | return nil, 0, fmt.Errorf("input length too short < 36") |
52 | 54 | } |
53 | 55 |
|
54 | | - offset := 36 |
55 | | - l, size := DecodeVarInt(bytes[offset:]) |
56 | | - offset += size |
| 56 | + r := bytes.NewReader(b) |
57 | 57 |
|
58 | | - totalLength := offset + int(l) + 4 // 4 bytes for nSeq |
| 58 | + i, err := NewInputFromReader(r) |
| 59 | + if err != nil { |
| 60 | + return nil, 0, err |
| 61 | + } |
| 62 | + |
| 63 | + return i, len(i.ToBytes(false)), nil |
| 64 | +} |
| 65 | + |
| 66 | +// NewInputFromReader returns a transaction input from the io.Reader provided. |
| 67 | +func NewInputFromReader(r io.Reader) (*Input, error) { |
| 68 | + previousTxID := make([]byte, 32) |
| 69 | + if n, err := io.ReadFull(r, previousTxID); n != 32 || err != nil { |
| 70 | + return nil, fmt.Errorf("Could not read previousTxID(32), got %d bytes and err: %w", n, err) |
| 71 | + } |
| 72 | + |
| 73 | + prevIndex := make([]byte, 4) |
| 74 | + if n, err := io.ReadFull(r, prevIndex); n != 4 || err != nil { |
| 75 | + return nil, fmt.Errorf("Could not read prevIndex(4), got %d bytes and err: %w", n, err) |
| 76 | + } |
| 77 | + |
| 78 | + l, _, err := DecodeVarIntFromReader(r) |
| 79 | + if err != nil { |
| 80 | + return nil, fmt.Errorf("Could not read varint: %w", err) |
| 81 | + } |
59 | 82 |
|
60 | | - if len(bytes) < totalLength { |
61 | | - return nil, 0, fmt.Errorf("input length too short < 36 + script + 4") |
| 83 | + script := make([]byte, l) |
| 84 | + if n, err := io.ReadFull(r, script); uint64(n) != l || err != nil { |
| 85 | + return nil, fmt.Errorf("Could not read script(%d), got %d bytes and err: %w", l, n, err) |
| 86 | + } |
| 87 | + |
| 88 | + sequence := make([]byte, 4) |
| 89 | + if n, err := io.ReadFull(r, sequence); n != 4 || err != nil { |
| 90 | + return nil, fmt.Errorf("Could not read sequence(4), got %d bytes and err: %w", n, err) |
62 | 91 | } |
63 | 92 |
|
64 | 93 | return &Input{ |
65 | | - PreviousTxIDBytes: ReverseBytes(bytes[0:32]), |
66 | | - PreviousTxID: hex.EncodeToString(ReverseBytes(bytes[0:32])), |
67 | | - PreviousTxOutIndex: binary.LittleEndian.Uint32(bytes[32:36]), |
68 | | - SequenceNumber: binary.LittleEndian.Uint32(bytes[offset+int(l):]), |
69 | | - UnlockingScript: bscript.NewFromBytes(bytes[offset : offset+int(l)]), |
70 | | - }, totalLength, nil |
| 94 | + PreviousTxIDBytes: ReverseBytes(previousTxID), |
| 95 | + PreviousTxID: hex.EncodeToString(ReverseBytes(previousTxID)), |
| 96 | + PreviousTxOutIndex: binary.LittleEndian.Uint32(prevIndex), |
| 97 | + UnlockingScript: bscript.NewFromBytes(script), |
| 98 | + SequenceNumber: binary.LittleEndian.Uint32(sequence), |
| 99 | + }, nil |
71 | 100 | } |
72 | 101 |
|
73 | 102 | // NewInputFromUTXO returns a transaction input from the UTXO fields provided. |
|
0 commit comments