From fa85e586fcbf297f1fba08fcd7cbce36d4df3cba Mon Sep 17 00:00:00 2001 From: Josh Rickmar Date: Mon, 9 Sep 2013 13:31:37 -0400 Subject: [PATCH] Save the pkScript for each Utxo. This is needed to create transactions. --- tx/tx.go | 72 ++++++++++++++++++++++++++++++++++++++++++++------- tx/tx_test.go | 36 ++++++++++++-------------- 2 files changed, 79 insertions(+), 29 deletions(-) diff --git a/tx/tx.go b/tx/tx.go index 7dc6d75..29bab80 100644 --- a/tx/tx.go +++ b/tx/tx.go @@ -44,19 +44,22 @@ type UtxoStore struct { type Utxo struct { Addr [ripemd160.Size]byte - Out OutPoint - Amt int64 // Measured in Satoshis + Out OutPoint + Subscript PKScript + Amt uint64 // Measured in Satoshis Height int64 } type OutPoint btcwire.OutPoint +type PKScript []byte + // TxStore is a slice holding RecvTx and SendTx pointers. type TxStore []interface{} type RecvTx struct { TxHash btcwire.ShaHash - Amt int64 // Measured in Satoshis + Amt uint64 // Measured in Satoshis SenderAddr [ripemd160.Size]byte ReceiverAddr [ripemd160.Size]byte } @@ -67,7 +70,7 @@ type SendTx struct { SenderAddr [ripemd160.Size]byte ReceiverAddrs []struct { Addr [ripemd160.Size]byte - Amt int64 // Measured in Satoshis + Amt uint64 // Measured in Satoshis } } @@ -178,13 +181,14 @@ func (u *UtxoStore) WriteTo(w io.Writer) (n int64, err error) { // ReadFrom satisifies the io.ReaderFrom interface. A Utxo is read // from r with the format: // -// [Addr (20 bytes), Out (36 bytes), Amt (8 bytes), Height (8 bytes)] +// [Addr (20 bytes), Out (36 bytes), Subscript (varies), Amt (8 bytes), Height (8 bytes)] // // Each field is read little endian. func (u *Utxo) ReadFrom(r io.Reader) (n int64, err error) { datas := []interface{}{ &u.Addr, &u.Out, + &u.Subscript, &u.Amt, &u.Height, } @@ -206,13 +210,14 @@ func (u *Utxo) ReadFrom(r io.Reader) (n int64, err error) { // WriteTo satisifies the io.WriterTo interface. A Utxo is written to // w in the format: // -// [Addr (20 bytes), Out (36 bytes), Amt (8 bytes), Height (8 bytes)] +// [Addr (20 bytes), Out (36 bytes), Subscript (varies), Amt (8 bytes), Height (8 bytes)] // // Each field is written little endian. func (u *Utxo) WriteTo(w io.Writer) (n int64, err error) { datas := []interface{}{ &u.Addr, &u.Out, + &u.Subscript, &u.Amt, &u.Height, } @@ -231,7 +236,7 @@ func (u *Utxo) WriteTo(w io.Writer) (n int64, err error) { return n, nil } -// ReadFrom satisifies the io.ReaderFrom interface. A OutPoint is read +// ReadFrom satisifies the io.ReaderFrom interface. An OutPoint is read // from r with the format: // // [Hash (32 bytes), Index (4 bytes)] @@ -253,7 +258,7 @@ func (o *OutPoint) ReadFrom(r io.Reader) (n int64, err error) { return n, nil } -// WriteTo satisifies the io.WriterTo interface. A OutPoit is written +// WriteTo satisifies the io.WriterTo interface. An OutPoint is written // to w in the format: // // [Hash (32 bytes), Index (4 bytes)] @@ -275,6 +280,55 @@ func (o *OutPoint) WriteTo(w io.Writer) (n int64, err error) { return n, nil } +// ReadFrom satisifies the io.ReaderFrom interface. A PKScript is read +// from r with the format: +// +// [Length (4 byte unsigned integer), ScriptBytes (Length bytes)] +// +// Length is read little endian. +func (s *PKScript) ReadFrom(r io.Reader) (n int64, err error) { + var scriptlen uint32 + var read int64 + read, err = binaryRead(r, binary.LittleEndian, &scriptlen) + if err != nil { + return n + read, err + } + n += read + + scriptbuf := new(bytes.Buffer) + read, err = scriptbuf.ReadFrom(io.LimitReader(r, int64(scriptlen))) + if err != nil { + return n + read, err + } + n += read + *s = scriptbuf.Bytes() + + return n, nil +} + +// WriteTo satisifies the io.WriterTo interface. A PKScript is written +// to w in the format: +// +// [Length (4 byte unsigned integer), ScriptBytes (Length bytes)] +// +// Length is written little endian. +func (s *PKScript) WriteTo(w io.Writer) (n int64, err error) { + var written int64 + written, err = binaryWrite(w, binary.LittleEndian, uint32(len(*s))) + if err != nil { + return n + written, nil + } + n += written + + written, err = bytes.NewBuffer(*s).WriteTo(w) + if err != nil { + return n + written, nil + } + n += written + + return n, nil +} + // ReadFrom satisifies the io.ReaderFrom interface. A TxStore is read // in from r with the format: // @@ -430,7 +484,7 @@ func (tx *SendTx) ReadFrom(r io.Reader) (n int64, err error) { tx.ReceiverAddrs = make([]struct { Addr [ripemd160.Size]byte - Amt int64 + Amt uint64 }, nReceivers) for i := uint32(0); i < nReceivers; i++ { diff --git a/tx/tx_test.go b/tx/tx_test.go index ccd35a8..16cd4d4 100644 --- a/tx/tx_test.go +++ b/tx/tx_test.go @@ -28,8 +28,6 @@ import ( ) var ( - utxoByteSize = binary.Size(Utxo{}) - recvtx = &RecvTx{ TxHash: [btcwire.HashSize]byte{ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -59,11 +57,11 @@ var ( }, ReceiverAddrs: []struct { Addr [ripemd160.Size]byte - Amt int64 + Amt uint64 }{ struct { Addr [ripemd160.Size]byte - Amt int64 + Amt uint64 }{ Amt: 69, Addr: [ripemd160.Size]byte{ @@ -73,7 +71,7 @@ var ( }, struct { Addr [ripemd160.Size]byte - Amt int64 + Amt uint64 }{ Amt: 96, Addr: [ripemd160.Size]byte{ @@ -99,26 +97,24 @@ func TestUtxoWriteRead(t *testing.T) { }, Index: 1, }, + Subscript: []byte{}, Amt: 69, Height: 1337, } bufWriter := &bytes.Buffer{} - n, err := utxo1.WriteTo(bufWriter) + written, err := utxo1.WriteTo(bufWriter) if err != nil { t.Error(err) } - if int(n) != binary.Size(utxo1) { - t.Error("Writing Utxo: Size Mismatch") - } utxoBytes := bufWriter.Bytes() utxo2 := new(Utxo) - n, err = utxo2.ReadFrom(bytes.NewBuffer(utxoBytes)) + read, err := utxo2.ReadFrom(bytes.NewBuffer(utxoBytes)) if err != nil { t.Error(err) } - if int(n) != binary.Size(utxo2) { - t.Error("Reading Utxo: Size Mismatch") + if written != read { + t.Error("Reading and Writing Utxo: Size Mismatch") } if !reflect.DeepEqual(utxo1, utxo2) { @@ -129,7 +125,7 @@ func TestUtxoWriteRead(t *testing.T) { truncatedReadBuf := bytes.NewBuffer(utxoBytes) truncatedReadBuf.Truncate(btcwire.HashSize) utxo3 := new(Utxo) - n, err = utxo3.ReadFrom(truncatedReadBuf) + n, err := utxo3.ReadFrom(truncatedReadBuf) if err != io.EOF { t.Error("Expected err = io.EOF reading from truncated buffer.") } @@ -146,7 +142,8 @@ func TestUtxoStoreWriteRead(t *testing.T) { utxo.Out.Hash[j] = byte(i) } utxo.Out.Index = uint32(i + 1) - utxo.Amt = int64(i + 2) + utxo.Subscript = []byte{} + utxo.Amt = uint64(i + 2) utxo.Height = int64(i + 3) store1.Confirmed = append(store1.Confirmed, utxo) } @@ -156,7 +153,8 @@ func TestUtxoStoreWriteRead(t *testing.T) { utxo.Out.Hash[j] = byte(i) } utxo.Out.Index = uint32(i + 1) - utxo.Amt = int64(i + 2) + utxo.Subscript = []byte{} + utxo.Amt = uint64(i + 2) utxo.Height = int64(i + 3) store1.Unconfirmed = append(store1.Unconfirmed, utxo) } @@ -166,9 +164,6 @@ func TestUtxoStoreWriteRead(t *testing.T) { if err != nil { t.Error(err) } - if n != 20*(1+int64(utxoByteSize)) { - t.Error("Incorrect number of bytes written.") - } storeBytes := bufWriter.Bytes() @@ -182,17 +177,18 @@ func TestUtxoStoreWriteRead(t *testing.T) { } if !reflect.DeepEqual(store1, store2) { + spew.Dump(store1, store2) t.Error("Stores do not match.") } truncatedReadBuf := bytes.NewBuffer(storeBytes) - truncatedReadBuf.Truncate(10*(1+utxoByteSize) + btcwire.HashSize) + truncatedReadBuf.Truncate(100) store3 := new(UtxoStore) n, err = store3.ReadFrom(truncatedReadBuf) if err != io.EOF { t.Error("Expected err = io.EOF reading from truncated buffer.") } - if n != 10*(1+int64(utxoByteSize))+btcwire.HashSize { + if n != 100 { t.Error("Incorrect number of bytes read from truncated buffer.") } }