From 5bf00db2c9c8505fe3a84c8852babe6471d82584 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 Sep 2019 12:18:13 +0300 Subject: [PATCH] io: move BinReader/BinWriter there, redo Serializable with it The logic here is that we'll have all binary encoding/decoding done via our io package, which simplifies error handling. This functionality doesn't belong to util, so it's moved. This also expands BufBinWriter with Reset() method to fit the needs of core package. --- pkg/core/account_state.go | 23 ++++----- pkg/core/account_state_test.go | 8 ++-- pkg/core/asset_state.go | 18 +++---- pkg/core/asset_state_test.go | 8 ++-- pkg/core/block.go | 46 ++++++++---------- pkg/core/block_base.go | 27 +++++------ pkg/core/block_test.go | 21 +++++---- pkg/core/blockchain.go | 27 ++++++----- pkg/core/header.go | 20 ++++---- pkg/core/header_hash_list.go | 8 ++-- pkg/core/header_test.go | 8 ++-- pkg/core/helper_test.go | 4 +- pkg/core/spent_coin_state.go | 15 +++--- pkg/core/spent_coin_state_test.go | 8 ++-- pkg/core/storage/helpers.go | 3 +- pkg/core/transaction/attribute.go | 8 ++-- pkg/core/transaction/claim.go | 13 ++--- pkg/core/transaction/contract.go | 6 +-- pkg/core/transaction/contract_test.go | 6 +-- pkg/core/transaction/enrollment.go | 7 ++- pkg/core/transaction/enrollment_test.go | 6 +-- pkg/core/transaction/helper_test.go | 4 +- pkg/core/transaction/input.go | 9 ++-- pkg/core/transaction/invocation.go | 9 ++-- pkg/core/transaction/issue.go | 6 +-- pkg/core/transaction/miner.go | 13 ++--- pkg/core/transaction/miner_test.go | 6 +-- pkg/core/transaction/output.go | 8 ++-- pkg/core/transaction/publish.go | 9 ++-- pkg/core/transaction/register.go | 11 ++--- pkg/core/transaction/register_test.go | 18 +++---- pkg/core/transaction/state.go | 26 ++++------ pkg/core/transaction/state_descriptor.go | 29 +++++------- pkg/core/transaction/state_test.go | 7 ++- pkg/core/transaction/transaction.go | 46 ++++++++---------- pkg/core/transaction/transaction_test.go | 34 +++++++------- pkg/core/transaction/txer.go | 6 +-- pkg/core/transaction/witness.go | 10 ++-- pkg/core/unspent_coin_state.go | 21 ++++----- pkg/core/unspent_coint_state_test.go | 8 ++-- pkg/core/util.go | 34 ++++++-------- pkg/crypto/keys/publickey.go | 39 ++++++++------- pkg/crypto/keys/publickey_test.go | 20 ++++---- pkg/{util => io}/binaryBufWriter.go | 12 ++++- pkg/{util => io}/binaryReader.go | 2 +- pkg/{util => io}/binaryWriter.go | 2 +- pkg/{util => io}/binaryrw_test.go | 14 +++++- pkg/io/serializable.go | 6 +-- pkg/network/message.go | 60 ++++++++++-------------- pkg/network/payload/address.go | 19 +++----- pkg/network/payload/address_test.go | 18 ++++--- pkg/network/payload/getblocks.go | 9 ++-- pkg/network/payload/getblocks_test.go | 18 ++++--- pkg/network/payload/headers.go | 14 ++---- pkg/network/payload/headers_test.go | 16 ++++--- pkg/network/payload/inventory.go | 9 ++-- pkg/network/payload/inventory_test.go | 14 +++--- pkg/network/payload/merkleblock.go | 10 ++-- pkg/network/payload/payload.go | 6 +-- pkg/network/payload/version.go | 8 ++-- pkg/network/payload/version_test.go | 12 +++-- pkg/network/tcp_peer.go | 4 +- pkg/network/tcp_transport.go | 4 +- pkg/rpc/rpc.go | 6 +-- pkg/rpc/server.go | 4 +- pkg/rpc/txBuilder.go | 7 ++- pkg/smartcontract/contract_test.go | 4 +- pkg/util/size_test.go | 6 +-- 68 files changed, 446 insertions(+), 501 deletions(-) rename pkg/{util => io}/binaryBufWriter.go (62%) rename pkg/{util => io}/binaryReader.go (99%) rename pkg/{util => io}/binaryWriter.go (99%) rename pkg/{util => io}/binaryrw_test.go (94%) diff --git a/pkg/core/account_state.go b/pkg/core/account_state.go index 7325b1b4d..d5c1f6bbb 100644 --- a/pkg/core/account_state.go +++ b/pkg/core/account_state.go @@ -1,12 +1,11 @@ package core import ( - "bytes" "fmt" - "io" "github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -21,7 +20,7 @@ func (a Accounts) getAndUpdate(s storage.Store, hash util.Uint160) (*AccountStat account := &AccountState{} key := storage.AppendPrefix(storage.STAccount, hash.Bytes()) if b, err := s.Get(key); err == nil { - if err := account.DecodeBinary(bytes.NewReader(b)); err != nil { + if err := account.DecodeBinary(io.NewBinReaderFromBuf(b)); err != nil { return nil, fmt.Errorf("failed to decode (AccountState): %s", err) } } else { @@ -34,9 +33,9 @@ func (a Accounts) getAndUpdate(s storage.Store, hash util.Uint160) (*AccountStat // commit writes all account states to the given Batch. func (a Accounts) commit(b storage.Batch) error { - buf := new(bytes.Buffer) + buf := io.NewBufBinWriter() for hash, state := range a { - if err := state.EncodeBinary(buf); err != nil { + if err := state.EncodeBinary(buf.BinWriter); err != nil { return err } key := storage.AppendPrefix(storage.STAccount, hash.Bytes()) @@ -66,9 +65,8 @@ func NewAccountState(scriptHash util.Uint160) *AccountState { } } -// DecodeBinary decodes AccountState from the given io.Reader. -func (s *AccountState) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +// DecodeBinary decodes AccountState from the given BinReader. +func (s *AccountState) DecodeBinary(br *io.BinReader) error { br.ReadLE(&s.Version) br.ReadLE(&s.ScriptHash) br.ReadLE(&s.IsFrozen) @@ -76,7 +74,7 @@ func (s *AccountState) DecodeBinary(r io.Reader) error { s.Votes = make([]*keys.PublicKey, lenVotes) for i := 0; i < int(lenVotes); i++ { s.Votes[i] = &keys.PublicKey{} - if err := s.Votes[i].DecodeBinary(r); err != nil { + if err := s.Votes[i].DecodeBinary(br); err != nil { return err } } @@ -94,15 +92,14 @@ func (s *AccountState) DecodeBinary(r io.Reader) error { return br.Err } -// EncodeBinary encode AccountState to the given io.Writer. -func (s *AccountState) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +// EncodeBinary encodes AccountState to the given BinWriter. +func (s *AccountState) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(s.Version) bw.WriteLE(s.ScriptHash) bw.WriteLE(s.IsFrozen) bw.WriteVarUint(uint64(len(s.Votes))) for _, point := range s.Votes { - if err := point.EncodeBinary(w); err != nil { + if err := point.EncodeBinary(bw); err != nil { return err } } diff --git a/pkg/core/account_state_test.go b/pkg/core/account_state_test.go index 82009be0d..a6b0a8645 100644 --- a/pkg/core/account_state_test.go +++ b/pkg/core/account_state_test.go @@ -1,10 +1,10 @@ package core import ( - "bytes" "testing" "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" ) @@ -30,13 +30,13 @@ func TestDecodeEncodeAccountState(t *testing.T) { Balances: balances, } - buf := new(bytes.Buffer) - if err := a.EncodeBinary(buf); err != nil { + buf := io.NewBufBinWriter() + if err := a.EncodeBinary(buf.BinWriter); err != nil { t.Fatal(err) } aDecode := &AccountState{} - if err := aDecode.DecodeBinary(buf); err != nil { + if err := aDecode.DecodeBinary(io.NewBinReaderFromBuf(buf.Bytes())); err != nil { t.Fatal(err) } diff --git a/pkg/core/asset_state.go b/pkg/core/asset_state.go index 02707eee9..712be5bcc 100644 --- a/pkg/core/asset_state.go +++ b/pkg/core/asset_state.go @@ -1,12 +1,10 @@ package core import ( - "bytes" - "io" - "github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -16,9 +14,9 @@ const feeMode = 0x0 type Assets map[util.Uint256]*AssetState func (a Assets) commit(b storage.Batch) error { - buf := new(bytes.Buffer) + buf := io.NewBufBinWriter() for hash, state := range a { - if err := state.EncodeBinary(buf); err != nil { + if err := state.EncodeBinary(buf.BinWriter); err != nil { return err } key := storage.AppendPrefix(storage.STAsset, hash.Bytes()) @@ -46,8 +44,7 @@ type AssetState struct { } // DecodeBinary implements the Payload interface. -func (a *AssetState) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (a *AssetState) DecodeBinary(br *io.BinReader) error { br.ReadLE(&a.ID) br.ReadLE(&a.AssetType) @@ -63,7 +60,7 @@ func (a *AssetState) DecodeBinary(r io.Reader) error { return br.Err } a.Owner = &keys.PublicKey{} - if err := a.Owner.DecodeBinary(r); err != nil { + if err := a.Owner.DecodeBinary(br); err != nil { return err } br.ReadLE(&a.Admin) @@ -75,8 +72,7 @@ func (a *AssetState) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (a *AssetState) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (a *AssetState) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(a.ID) bw.WriteLE(a.AssetType) bw.WriteString(a.Name) @@ -89,7 +85,7 @@ func (a *AssetState) EncodeBinary(w io.Writer) error { if bw.Err != nil { return bw.Err } - if err := a.Owner.EncodeBinary(w); err != nil { + if err := a.Owner.EncodeBinary(bw); err != nil { return err } bw.WriteLE(a.Admin) diff --git a/pkg/core/asset_state_test.go b/pkg/core/asset_state_test.go index 952c81fc4..cbebd3db2 100644 --- a/pkg/core/asset_state_test.go +++ b/pkg/core/asset_state_test.go @@ -1,11 +1,11 @@ package core import ( - "bytes" "testing" "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" ) @@ -26,9 +26,9 @@ func TestEncodeDecodeAssetState(t *testing.T) { IsFrozen: false, } - buf := new(bytes.Buffer) - assert.Nil(t, asset.EncodeBinary(buf)) + buf := io.NewBufBinWriter() + assert.Nil(t, asset.EncodeBinary(buf.BinWriter)) assetDecode := &AssetState{} - assert.Nil(t, assetDecode.DecodeBinary(buf)) + assert.Nil(t, assetDecode.DecodeBinary(io.NewBinReaderFromBuf(buf.Bytes()))) assert.Equal(t, asset, assetDecode) } diff --git a/pkg/core/block.go b/pkg/core/block.go index e17483e4d..19d8cedd7 100644 --- a/pkg/core/block.go +++ b/pkg/core/block.go @@ -1,11 +1,9 @@ package core import ( - "bytes" - "io" - "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" log "github.com/sirupsen/logrus" ) @@ -73,12 +71,11 @@ func NewBlockFromTrimmedBytes(b []byte) (*Block, error) { Trimmed: true, } - r := bytes.NewReader(b) - if err := block.decodeHashableFields(r); err != nil { + br := io.NewBinReaderFromBuf(b) + if err := block.decodeHashableFields(br); err != nil { return block, err } - br := util.NewBinReaderFromIO(r) var padding uint8 br.ReadLE(&padding) if br.Err != nil { @@ -86,7 +83,7 @@ func NewBlockFromTrimmedBytes(b []byte) (*Block, error) { } block.Script = &transaction.Witness{} - if err := block.Script.DecodeBinary(r); err != nil { + if err := block.Script.DecodeBinary(br); err != nil { return block, err } @@ -105,36 +102,34 @@ func NewBlockFromTrimmedBytes(b []byte) (*Block, error) { // in storage. // Notice that only the hashes of the transactions are stored. func (b *Block) Trim() ([]byte, error) { - buf := new(bytes.Buffer) - if err := b.encodeHashableFields(buf); err != nil { + buf := io.NewBufBinWriter() + if err := b.encodeHashableFields(buf.BinWriter); err != nil { return nil, err } - bw := util.NewBinWriterFromIO(buf) - bw.WriteLE(uint8(1)) - if bw.Err != nil { - return nil, bw.Err + buf.WriteLE(uint8(1)) + if buf.Err != nil { + return nil, buf.Err } - if err := b.Script.EncodeBinary(buf); err != nil { + if err := b.Script.EncodeBinary(buf.BinWriter); err != nil { return nil, err } - bw.WriteVarUint(uint64(len(b.Transactions))) + buf.WriteVarUint(uint64(len(b.Transactions))) for _, tx := range b.Transactions { - bw.WriteLE(tx.Hash()) + buf.WriteLE(tx.Hash()) } - if bw.Err != nil { - return nil, bw.Err + if buf.Err != nil { + return nil, buf.Err } return buf.Bytes(), nil } // DecodeBinary decodes the block from the given reader. -func (b *Block) DecodeBinary(r io.Reader) error { - if err := b.BlockBase.DecodeBinary(r); err != nil { +func (b *Block) DecodeBinary(br *io.BinReader) error { + if err := b.BlockBase.DecodeBinary(br); err != nil { return err } - br := util.NewBinReaderFromIO(r) lentx := br.ReadVarUint() if br.Err != nil { return br.Err @@ -142,7 +137,7 @@ func (b *Block) DecodeBinary(r io.Reader) error { b.Transactions = make([]*transaction.Transaction, lentx) for i := 0; i < int(lentx); i++ { b.Transactions[i] = &transaction.Transaction{} - if err := b.Transactions[i].DecodeBinary(r); err != nil { + if err := b.Transactions[i].DecodeBinary(br); err != nil { return err } } @@ -151,18 +146,17 @@ func (b *Block) DecodeBinary(r io.Reader) error { } // EncodeBinary encodes the block to the given writer. -func (b *Block) EncodeBinary(w io.Writer) error { - err := b.BlockBase.EncodeBinary(w) +func (b *Block) EncodeBinary(bw *io.BinWriter) error { + err := b.BlockBase.EncodeBinary(bw) if err != nil { return err } - bw := util.NewBinWriterFromIO(w) bw.WriteVarUint(uint64(len(b.Transactions))) if bw.Err != nil { return err } for _, tx := range b.Transactions { - err := tx.EncodeBinary(w) + err := tx.EncodeBinary(bw) if err != nil { return err } diff --git a/pkg/core/block_base.go b/pkg/core/block_base.go index 75f769340..4e063db0e 100644 --- a/pkg/core/block_base.go +++ b/pkg/core/block_base.go @@ -1,12 +1,11 @@ package core import ( - "bytes" "fmt" - "io" "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -60,13 +59,12 @@ func (b *BlockBase) Hash() util.Uint256 { } // DecodeBinary implements the payload interface. -func (b *BlockBase) DecodeBinary(r io.Reader) error { - if err := b.decodeHashableFields(r); err != nil { +func (b *BlockBase) DecodeBinary(br *io.BinReader) error { + if err := b.decodeHashableFields(br); err != nil { return err } var padding uint8 - br := util.NewBinReaderFromIO(r) br.ReadLE(&padding) if br.Err != nil { return br.Err @@ -76,20 +74,19 @@ func (b *BlockBase) DecodeBinary(r io.Reader) error { } b.Script = &transaction.Witness{} - return b.Script.DecodeBinary(r) + return b.Script.DecodeBinary(br) } // EncodeBinary implements the Payload interface -func (b *BlockBase) EncodeBinary(w io.Writer) error { - if err := b.encodeHashableFields(w); err != nil { +func (b *BlockBase) EncodeBinary(bw *io.BinWriter) error { + if err := b.encodeHashableFields(bw); err != nil { return err } - bw := util.NewBinWriterFromIO(w) bw.WriteLE(uint8(1)) if bw.Err != nil { return bw.Err } - return b.Script.EncodeBinary(w) + return b.Script.EncodeBinary(bw) } // createHash creates the hash of the block. @@ -99,8 +96,8 @@ func (b *BlockBase) EncodeBinary(w io.Writer) error { // Since MerkleRoot already contains the hash value of all transactions, // the modification of transaction will influence the hash value of the block. func (b *BlockBase) createHash() error { - buf := new(bytes.Buffer) - if err := b.encodeHashableFields(buf); err != nil { + buf := io.NewBufBinWriter() + if err := b.encodeHashableFields(buf.BinWriter); err != nil { return err } b.hash = hash.DoubleSha256(buf.Bytes()) @@ -110,8 +107,7 @@ func (b *BlockBase) createHash() error { // encodeHashableFields will only encode the fields used for hashing. // see Hash() for more information about the fields. -func (b *BlockBase) encodeHashableFields(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (b *BlockBase) encodeHashableFields(bw *io.BinWriter) error { bw.WriteLE(b.Version) bw.WriteLE(b.PrevHash) bw.WriteLE(b.MerkleRoot) @@ -124,8 +120,7 @@ func (b *BlockBase) encodeHashableFields(w io.Writer) error { // decodeHashableFields will only decode the fields used for hashing. // see Hash() for more information about the fields. -func (b *BlockBase) decodeHashableFields(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (b *BlockBase) decodeHashableFields(br *io.BinReader) error { br.ReadLE(&b.Version) br.ReadLE(&b.PrevHash) br.ReadLE(&b.MerkleRoot) diff --git a/pkg/core/block_test.go b/pkg/core/block_test.go index 3191e959d..ffa159e40 100644 --- a/pkg/core/block_test.go +++ b/pkg/core/block_test.go @@ -1,12 +1,12 @@ package core import ( - "bytes" "encoding/hex" "testing" "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) @@ -24,7 +24,7 @@ func TestDecodeBlock1(t *testing.T) { } block := &Block{} - if err := block.DecodeBinary(bytes.NewReader(b)); err != nil { + if err := block.DecodeBinary(io.NewBinReaderFromBuf(b)); err != nil { t.Fatal(err) } @@ -109,7 +109,7 @@ func TestBinBlockDecodeEncode(t *testing.T) { b := Block{} - r := bytes.NewReader(rawtxBytes) + r := io.NewBinReaderFromBuf(rawtxBytes) err := b.DecodeBinary(r) assert.Nil(t, err) expected := map[string]bool{ // 18 trans @@ -165,9 +165,9 @@ func TestBinBlockDecodeEncode(t *testing.T) { } assert.Equal(t, true, val) - buf := new(bytes.Buffer) + buf := io.NewBufBinWriter() - err = b.EncodeBinary(buf) + err = b.EncodeBinary(buf.BinWriter) assert.Nil(t, err) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) @@ -185,7 +185,7 @@ func TestBlockSizeCalculation(t *testing.T) { b := Block{} - r := bytes.NewReader(rawBlockBytes) + r := io.NewBinReaderFromBuf(rawBlockBytes) err := b.DecodeBinary(r) assert.Nil(t, err) @@ -250,11 +250,12 @@ func TestBlockSizeCalculation(t *testing.T) { assert.Equal(t, "552102486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a7021024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d2102aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e2103b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c2103b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a2102ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba5542102df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e89509357ae", hex.EncodeToString(b.Script.VerificationScript)) assert.Equal(t, "0006d3ff96e269f599eb1b5c5a527c218439e498dcc65b63794591bbcdc0516b", b.Hash().ReverseString()) - buf := new(bytes.Buffer) + buf := io.NewBufBinWriter() - err = b.EncodeBinary(buf) + err = b.EncodeBinary(buf.BinWriter) assert.Nil(t, err) + benc := buf.Bytes() // test size of the block - assert.Equal(t, 7360, buf.Len()) - assert.Equal(t, rawBlock, hex.EncodeToString(buf.Bytes())) + assert.Equal(t, 7360, len(benc)) + assert.Equal(t, rawBlock, hex.EncodeToString(benc)) } diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index f751fe2e8..a31b0b037 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -1,9 +1,7 @@ package core import ( - "bytes" "context" - "encoding/binary" "fmt" "math" "sync/atomic" @@ -12,6 +10,7 @@ import ( "github.com/CityOfZion/neo-go/config" "github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/transaction" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" "github.com/pkg/errors" log "github.com/sirupsen/logrus" @@ -243,9 +242,9 @@ func (bc *Blockchain) AddHeaders(headers ...*Header) (err error) { func (bc *Blockchain) processHeader(h *Header, batch storage.Batch, headerList *HeaderHashList) error { headerList.Add(h.Hash()) - buf := new(bytes.Buffer) + buf := io.NewBufBinWriter() for int(h.Index)-headerBatchCount >= int(bc.storedHeaderCount) { - if err := headerList.Write(buf, int(bc.storedHeaderCount), headerBatchCount); err != nil { + if err := headerList.Write(buf.BinWriter, int(bc.storedHeaderCount), headerBatchCount); err != nil { return err } key := storage.AppendPrefixInt(storage.IXHeaderHashList, int(bc.storedHeaderCount)) @@ -255,7 +254,7 @@ func (bc *Blockchain) processHeader(h *Header, batch storage.Batch, headerList * } buf.Reset() - if err := h.EncodeBinary(buf); err != nil { + if err := h.EncodeBinary(buf.BinWriter); err != nil { return err } @@ -467,11 +466,12 @@ func (bc *Blockchain) GetTransaction(hash util.Uint256) (*transaction.Transactio if err != nil { return nil, 0, err } - r := bytes.NewReader(b) + r := io.NewBinReaderFromBuf(b) var height uint32 - if err := binary.Read(r, binary.LittleEndian, &height); err != nil { - return nil, 0, err + r.ReadLE(&height) + if r.Err != nil { + return nil, 0, r.Err } tx := &transaction.Transaction{} @@ -578,7 +578,7 @@ func (bc *Blockchain) GetAssetState(assetID util.Uint256) *AssetState { var as *AssetState bc.Store.Seek(storage.STAsset.Bytes(), func(k, v []byte) { var a AssetState - if err := a.DecodeBinary(bytes.NewReader(v)); err == nil && a.ID == assetID { + if err := a.DecodeBinary(io.NewBinReaderFromBuf(v)); err == nil && a.ID == assetID { as = &a } }) @@ -591,7 +591,7 @@ func (bc *Blockchain) GetAccountState(scriptHash util.Uint160) *AccountState { var as *AccountState bc.Store.Seek(storage.STAccount.Bytes(), func(k, v []byte) { var a AccountState - if err := a.DecodeBinary(bytes.NewReader(v)); err == nil && a.ScriptHash == scriptHash { + if err := a.DecodeBinary(io.NewBinReaderFromBuf(v)); err == nil && a.ScriptHash == scriptHash { as = &a } }) @@ -921,9 +921,10 @@ func (bc *Blockchain) VerifyWitnesses(t *transaction.Transaction) error { } func hashAndIndexToBytes(h util.Uint256, index uint32) []byte { - buf := make([]byte, 4) - binary.LittleEndian.PutUint32(buf, index) - return append(h.BytesReverse(), buf...) + buf := io.NewBufBinWriter() + buf.WriteLE(h.BytesReverse()) + buf.WriteLE(index) + return buf.Bytes() } func (bc *Blockchain) secondsPerBlock() int { diff --git a/pkg/core/header.go b/pkg/core/header.go index 79b0e56ed..659270cc5 100644 --- a/pkg/core/header.go +++ b/pkg/core/header.go @@ -1,9 +1,9 @@ package core import ( - "encoding/binary" "fmt" - "io" + + "github.com/CityOfZion/neo-go/pkg/io" ) // Header holds the head info of a block. @@ -15,14 +15,15 @@ type Header struct { } // DecodeBinary implements the Payload interface. -func (h *Header) DecodeBinary(r io.Reader) error { +func (h *Header) DecodeBinary(r *io.BinReader) error { if err := h.BlockBase.DecodeBinary(r); err != nil { return err } var padding uint8 - if err := binary.Read(r, binary.LittleEndian, &padding); err != nil { - return err + r.ReadLE(&padding) + if r.Err != nil { + return r.Err } if padding != 0 { @@ -33,9 +34,8 @@ func (h *Header) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (h *Header) EncodeBinary(w io.Writer) error { - if err := h.BlockBase.EncodeBinary(w); err != nil { - return err - } - return binary.Write(w, binary.LittleEndian, uint8(0)) +func (h *Header) EncodeBinary(w *io.BinWriter) error { + h.BlockBase.EncodeBinary(w) + w.WriteLE(uint8(0)) + return w.Err } diff --git a/pkg/core/header_hash_list.go b/pkg/core/header_hash_list.go index d54723aba..9f6ffbdf2 100644 --- a/pkg/core/header_hash_list.go +++ b/pkg/core/header_hash_list.go @@ -1,8 +1,7 @@ package core import ( - "io" - + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -56,10 +55,9 @@ func (l *HeaderHashList) Slice(start, end int) []util.Uint256 { return l.hashes[start:end] } -// WriteTo will write n underlying hashes to the given io.Writer +// WriteTo will write n underlying hashes to the given BinWriter // starting from start. -func (l *HeaderHashList) Write(w io.Writer, start, n int) error { - bw := util.NewBinWriterFromIO(w) +func (l *HeaderHashList) Write(bw *io.BinWriter, start, n int) error { bw.WriteVarUint(uint64(n)) hashes := l.Slice(start, start+n) for _, hash := range hashes { diff --git a/pkg/core/header_test.go b/pkg/core/header_test.go index dcd83d7c0..8b7bcf19f 100644 --- a/pkg/core/header_test.go +++ b/pkg/core/header_test.go @@ -1,12 +1,12 @@ package core import ( - "bytes" "testing" "time" "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" ) @@ -26,13 +26,13 @@ func TestHeaderEncodeDecode(t *testing.T) { }, }} - buf := new(bytes.Buffer) - if err := header.EncodeBinary(buf); err != nil { + buf := io.NewBufBinWriter() + if err := header.EncodeBinary(buf.BinWriter); err != nil { t.Fatal(err) } headerDecode := &Header{} - if err := headerDecode.DecodeBinary(buf); err != nil { + if err := headerDecode.DecodeBinary(io.NewBinReaderFromBuf(buf.Bytes())); err != nil { t.Fatal(err) } assert.Equal(t, header.Version, headerDecode.Version, "expected both versions to be equal") diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index 27317f64a..1ab25d3e9 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -1,7 +1,6 @@ package core import ( - "bytes" "encoding/hex" "encoding/json" "fmt" @@ -11,6 +10,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -63,7 +63,7 @@ func getDecodedBlock(t *testing.T, i int) *Block { } block := &Block{} - if err := block.DecodeBinary(bytes.NewReader(b)); err != nil { + if err := block.DecodeBinary(io.NewBinReaderFromBuf(b)); err != nil { t.Fatal(err) } diff --git a/pkg/core/spent_coin_state.go b/pkg/core/spent_coin_state.go index 594fd3756..21db15fb9 100644 --- a/pkg/core/spent_coin_state.go +++ b/pkg/core/spent_coin_state.go @@ -1,11 +1,10 @@ package core import ( - "bytes" "fmt" - "io" "github.com/CityOfZion/neo-go/pkg/core/storage" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -21,7 +20,7 @@ func (s SpentCoins) getAndUpdate(store storage.Store, hash util.Uint256) (*Spent spent := &SpentCoinState{} key := storage.AppendPrefix(storage.STSpentCoin, hash.BytesReverse()) if b, err := store.Get(key); err == nil { - if err := spent.DecodeBinary(bytes.NewReader(b)); err != nil { + if err := spent.DecodeBinary(io.NewBinReaderFromBuf(b)); err != nil { return nil, fmt.Errorf("failed to decode (UnspentCoinState): %s", err) } } else { @@ -35,9 +34,9 @@ func (s SpentCoins) getAndUpdate(store storage.Store, hash util.Uint256) (*Spent } func (s SpentCoins) commit(b storage.Batch) error { - buf := new(bytes.Buffer) + buf := io.NewBufBinWriter() for hash, state := range s { - if err := state.EncodeBinary(buf); err != nil { + if err := state.EncodeBinary(buf.BinWriter); err != nil { return err } key := storage.AppendPrefix(storage.STSpentCoin, hash.BytesReverse()) @@ -66,8 +65,7 @@ func NewSpentCoinState(hash util.Uint256, height uint32) *SpentCoinState { } // DecodeBinary implements the Payload interface. -func (s *SpentCoinState) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (s *SpentCoinState) DecodeBinary(br *io.BinReader) error { br.ReadLE(&s.txHash) br.ReadLE(&s.txHeight) @@ -86,8 +84,7 @@ func (s *SpentCoinState) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (s *SpentCoinState) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (s *SpentCoinState) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(s.txHash) bw.WriteLE(s.txHeight) bw.WriteVarUint(uint64(len(s.items))) diff --git a/pkg/core/spent_coin_state_test.go b/pkg/core/spent_coin_state_test.go index 8a2b03981..dde497e3d 100644 --- a/pkg/core/spent_coin_state_test.go +++ b/pkg/core/spent_coin_state_test.go @@ -1,10 +1,10 @@ package core import ( - "bytes" "testing" "github.com/CityOfZion/neo-go/pkg/core/storage" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" ) @@ -20,10 +20,10 @@ func TestEncodeDecodeSpentCoinState(t *testing.T) { }, } - buf := new(bytes.Buffer) - assert.Nil(t, spent.EncodeBinary(buf)) + buf := io.NewBufBinWriter() + assert.Nil(t, spent.EncodeBinary(buf.BinWriter)) spentDecode := new(SpentCoinState) - assert.Nil(t, spentDecode.DecodeBinary(buf)) + assert.Nil(t, spentDecode.DecodeBinary(io.NewBinReaderFromBuf(buf.Bytes()))) assert.Equal(t, spent, spentDecode) } diff --git a/pkg/core/storage/helpers.go b/pkg/core/storage/helpers.go index ca3c1a7c2..8916a5615 100644 --- a/pkg/core/storage/helpers.go +++ b/pkg/core/storage/helpers.go @@ -5,6 +5,7 @@ import ( "encoding/binary" "sort" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -84,7 +85,7 @@ func HeaderHashes(s Store) ([]util.Uint256, error) { // the given byte array. func read2000Uint256Hashes(b []byte) ([]util.Uint256, error) { r := bytes.NewReader(b) - br := util.NewBinReaderFromIO(r) + br := io.NewBinReaderFromIO(r) lenHashes := br.ReadVarUint() hashes := make([]util.Uint256, lenHashes) br.ReadLE(hashes) diff --git a/pkg/core/transaction/attribute.go b/pkg/core/transaction/attribute.go index c5df619f3..b4e07aee4 100644 --- a/pkg/core/transaction/attribute.go +++ b/pkg/core/transaction/attribute.go @@ -4,8 +4,8 @@ import ( "encoding/hex" "encoding/json" "fmt" - "io" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -16,8 +16,7 @@ type Attribute struct { } // DecodeBinary implements the Payload interface. -func (attr *Attribute) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (attr *Attribute) DecodeBinary(br *io.BinReader) error { br.ReadLE(&attr.Usage) // very special case @@ -53,8 +52,7 @@ func (attr *Attribute) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (attr *Attribute) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (attr *Attribute) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(&attr.Usage) switch attr.Usage { case ECDH02, ECDH03: diff --git a/pkg/core/transaction/claim.go b/pkg/core/transaction/claim.go index f5c7c8e8d..bb864548c 100644 --- a/pkg/core/transaction/claim.go +++ b/pkg/core/transaction/claim.go @@ -1,8 +1,7 @@ package transaction import ( - "io" - + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -12,8 +11,7 @@ type ClaimTX struct { } // DecodeBinary implements the Payload interface. -func (tx *ClaimTX) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (tx *ClaimTX) DecodeBinary(br *io.BinReader) error { lenClaims := br.ReadVarUint() if br.Err != nil { return br.Err @@ -21,7 +19,7 @@ func (tx *ClaimTX) DecodeBinary(r io.Reader) error { tx.Claims = make([]*Input, lenClaims) for i := 0; i < int(lenClaims); i++ { tx.Claims[i] = &Input{} - if err := tx.Claims[i].DecodeBinary(r); err != nil { + if err := tx.Claims[i].DecodeBinary(br); err != nil { return err } } @@ -29,14 +27,13 @@ func (tx *ClaimTX) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (tx *ClaimTX) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (tx *ClaimTX) EncodeBinary(bw *io.BinWriter) error { bw.WriteVarUint(uint64(len(tx.Claims))) if bw.Err != nil { return bw.Err } for _, claim := range tx.Claims { - if err := claim.EncodeBinary(w); err != nil { + if err := claim.EncodeBinary(bw); err != nil { return err } } diff --git a/pkg/core/transaction/contract.go b/pkg/core/transaction/contract.go index e36a1ded4..c7d91fa12 100644 --- a/pkg/core/transaction/contract.go +++ b/pkg/core/transaction/contract.go @@ -1,7 +1,7 @@ package transaction import ( - "io" + "github.com/CityOfZion/neo-go/pkg/io" ) // ContractTX represents a contract transaction. @@ -16,12 +16,12 @@ func NewContractTX() *Transaction { } // DecodeBinary implements the Payload interface. -func (tx *ContractTX) DecodeBinary(r io.Reader) error { +func (tx *ContractTX) DecodeBinary(r *io.BinReader) error { return nil } // EncodeBinary implements the Payload interface. -func (tx *ContractTX) EncodeBinary(w io.Writer) error { +func (tx *ContractTX) EncodeBinary(w *io.BinWriter) error { return nil } diff --git a/pkg/core/transaction/contract_test.go b/pkg/core/transaction/contract_test.go index cd3e512b9..43e7d19b2 100644 --- a/pkg/core/transaction/contract_test.go +++ b/pkg/core/transaction/contract_test.go @@ -1,10 +1,10 @@ package transaction import ( - "bytes" "encoding/hex" "testing" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) @@ -29,9 +29,9 @@ func TestEncodeDecodeContract(t *testing.T) { assert.Equal(t, "bdf6cc3b9af12a7565bda80933a75ee8cef1bc771d0d58effc08e4c8b436da79", tx.Hash().ReverseString()) // Encode - buf := new(bytes.Buffer) + buf := io.NewBufBinWriter() - err := tx.EncodeBinary(buf) + err := tx.EncodeBinary(buf.BinWriter) assert.Equal(t, nil, err) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) } diff --git a/pkg/core/transaction/enrollment.go b/pkg/core/transaction/enrollment.go index 752f6b9ee..9ef1b4f68 100644 --- a/pkg/core/transaction/enrollment.go +++ b/pkg/core/transaction/enrollment.go @@ -1,9 +1,8 @@ package transaction import ( - "io" - "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/CityOfZion/neo-go/pkg/io" ) // EnrollmentTX transaction represents an enrollment form, which indicates @@ -17,13 +16,13 @@ type EnrollmentTX struct { } // DecodeBinary implements the Payload interface. -func (tx *EnrollmentTX) DecodeBinary(r io.Reader) error { +func (tx *EnrollmentTX) DecodeBinary(r *io.BinReader) error { tx.PublicKey = &keys.PublicKey{} return tx.PublicKey.DecodeBinary(r) } // EncodeBinary implements the Payload interface. -func (tx *EnrollmentTX) EncodeBinary(w io.Writer) error { +func (tx *EnrollmentTX) EncodeBinary(w *io.BinWriter) error { return tx.PublicKey.EncodeBinary(w) } diff --git a/pkg/core/transaction/enrollment_test.go b/pkg/core/transaction/enrollment_test.go index efec21d71..fa669fc0e 100644 --- a/pkg/core/transaction/enrollment_test.go +++ b/pkg/core/transaction/enrollment_test.go @@ -1,10 +1,10 @@ package transaction import ( - "bytes" "encoding/hex" "testing" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) @@ -16,8 +16,8 @@ func TestEncodeDecodeEnrollment(t *testing.T) { assert.IsType(t, tx.Data, &EnrollmentTX{}) assert.Equal(t, 0, int(tx.Version)) - buf := new(bytes.Buffer) - err := tx.EncodeBinary(buf) + buf := io.NewBufBinWriter() + err := tx.EncodeBinary(buf.BinWriter) assert.Equal(t, nil, err) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) diff --git a/pkg/core/transaction/helper_test.go b/pkg/core/transaction/helper_test.go index d727ca73d..2cc7cc121 100644 --- a/pkg/core/transaction/helper_test.go +++ b/pkg/core/transaction/helper_test.go @@ -1,10 +1,10 @@ package transaction import ( - "bytes" "encoding/hex" "testing" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) @@ -21,7 +21,7 @@ func decodeTransaction(rawTX string, t *testing.T) *Transaction { b, err1 := hex.DecodeString(rawTX) assert.Nil(t, err1) tx := &Transaction{} - err2 := tx.DecodeBinary(bytes.NewReader(b)) + err2 := tx.DecodeBinary(io.NewBinReaderFromBuf(b)) assert.Nil(t, err2) return tx } diff --git a/pkg/core/transaction/input.go b/pkg/core/transaction/input.go index f2bd3e4df..cce3db6c3 100644 --- a/pkg/core/transaction/input.go +++ b/pkg/core/transaction/input.go @@ -1,8 +1,7 @@ package transaction import ( - "io" - + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -16,16 +15,14 @@ type Input struct { } // DecodeBinary implements the Payload interface. -func (in *Input) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (in *Input) DecodeBinary(br *io.BinReader) error { br.ReadLE(&in.PrevHash) br.ReadLE(&in.PrevIndex) return br.Err } // EncodeBinary implements the Payload interface. -func (in *Input) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (in *Input) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(in.PrevHash) bw.WriteLE(in.PrevIndex) return bw.Err diff --git a/pkg/core/transaction/invocation.go b/pkg/core/transaction/invocation.go index 36df0a948..52a105bcb 100644 --- a/pkg/core/transaction/invocation.go +++ b/pkg/core/transaction/invocation.go @@ -1,8 +1,7 @@ package transaction import ( - "io" - + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -33,8 +32,7 @@ func NewInvocationTX(script []byte) *Transaction { } // DecodeBinary implements the Payload interface. -func (tx *InvocationTX) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (tx *InvocationTX) DecodeBinary(br *io.BinReader) error { tx.Script = br.ReadBytes() if tx.Version >= 1 { br.ReadLE(&tx.Gas) @@ -45,8 +43,7 @@ func (tx *InvocationTX) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (tx *InvocationTX) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (tx *InvocationTX) EncodeBinary(bw *io.BinWriter) error { bw.WriteBytes(tx.Script) if tx.Version >= 1 { bw.WriteLE(tx.Gas) diff --git a/pkg/core/transaction/issue.go b/pkg/core/transaction/issue.go index 1a82d2df6..7555d267b 100644 --- a/pkg/core/transaction/issue.go +++ b/pkg/core/transaction/issue.go @@ -1,7 +1,7 @@ package transaction import ( - "io" + "github.com/CityOfZion/neo-go/pkg/io" ) // IssueTX represents a issue transaction. @@ -9,12 +9,12 @@ import ( type IssueTX struct{} // DecodeBinary implements the Payload interface. -func (tx *IssueTX) DecodeBinary(r io.Reader) error { +func (tx *IssueTX) DecodeBinary(r *io.BinReader) error { return nil } // EncodeBinary implements the Payload interface. -func (tx *IssueTX) EncodeBinary(w io.Writer) error { +func (tx *IssueTX) EncodeBinary(w *io.BinWriter) error { return nil } diff --git a/pkg/core/transaction/miner.go b/pkg/core/transaction/miner.go index 3f99ad125..b64fbee9b 100644 --- a/pkg/core/transaction/miner.go +++ b/pkg/core/transaction/miner.go @@ -1,8 +1,7 @@ package transaction import ( - "encoding/binary" - "io" + "github.com/CityOfZion/neo-go/pkg/io" ) // MinerTX represents a miner transaction. @@ -12,13 +11,15 @@ type MinerTX struct { } // DecodeBinary implements the Payload interface. -func (tx *MinerTX) DecodeBinary(r io.Reader) error { - return binary.Read(r, binary.LittleEndian, &tx.Nonce) +func (tx *MinerTX) DecodeBinary(r *io.BinReader) error { + r.ReadLE(&tx.Nonce) + return r.Err } // EncodeBinary implements the Payload interface. -func (tx *MinerTX) EncodeBinary(w io.Writer) error { - return binary.Write(w, binary.LittleEndian, tx.Nonce) +func (tx *MinerTX) EncodeBinary(w *io.BinWriter) error { + w.WriteLE(tx.Nonce) + return w.Err } // Size returns serialized binary size for this transaction. diff --git a/pkg/core/transaction/miner_test.go b/pkg/core/transaction/miner_test.go index b26096ba5..c5c7a77ee 100644 --- a/pkg/core/transaction/miner_test.go +++ b/pkg/core/transaction/miner_test.go @@ -1,10 +1,10 @@ package transaction import ( - "bytes" "encoding/hex" "testing" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) @@ -21,9 +21,9 @@ func TestEncodeDecodeMiner(t *testing.T) { assert.Equal(t, "a1f219dc6be4c35eca172e65e02d4591045220221b1543f1a4b67b9e9442c264", tx.Hash().ReverseString()) // Encode - buf := new(bytes.Buffer) + buf := io.NewBufBinWriter() - err := tx.EncodeBinary(buf) + err := tx.EncodeBinary(buf.BinWriter) assert.Equal(t, nil, err) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) diff --git a/pkg/core/transaction/output.go b/pkg/core/transaction/output.go index 1afa21e5a..887bcb18f 100644 --- a/pkg/core/transaction/output.go +++ b/pkg/core/transaction/output.go @@ -2,9 +2,9 @@ package transaction import ( "encoding/json" - "io" "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -34,8 +34,7 @@ func NewOutput(assetID util.Uint256, amount util.Fixed8, scriptHash util.Uint160 } // DecodeBinary implements the Payload interface. -func (out *Output) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (out *Output) DecodeBinary(br *io.BinReader) error { br.ReadLE(&out.AssetID) br.ReadLE(&out.Amount) br.ReadLE(&out.ScriptHash) @@ -43,8 +42,7 @@ func (out *Output) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (out *Output) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (out *Output) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(out.AssetID) bw.WriteLE(out.Amount) bw.WriteLE(out.ScriptHash) diff --git a/pkg/core/transaction/publish.go b/pkg/core/transaction/publish.go index 4d20de820..c5149bc97 100644 --- a/pkg/core/transaction/publish.go +++ b/pkg/core/transaction/publish.go @@ -1,8 +1,7 @@ package transaction import ( - "io" - + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/smartcontract" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -23,8 +22,7 @@ type PublishTX struct { } // DecodeBinary implements the Payload interface. -func (tx *PublishTX) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (tx *PublishTX) DecodeBinary(br *io.BinReader) error { tx.Script = br.ReadBytes() lenParams := br.ReadVarUint() @@ -55,8 +53,7 @@ func (tx *PublishTX) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (tx *PublishTX) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) error { bw.WriteBytes(tx.Script) bw.WriteVarUint(uint64(len(tx.ParamList))) for _, param := range tx.ParamList { diff --git a/pkg/core/transaction/register.go b/pkg/core/transaction/register.go index 41ed9ca75..711cb7465 100644 --- a/pkg/core/transaction/register.go +++ b/pkg/core/transaction/register.go @@ -1,9 +1,8 @@ package transaction import ( - "io" - "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -30,8 +29,7 @@ type RegisterTX struct { } // DecodeBinary implements the Payload interface. -func (tx *RegisterTX) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (tx *RegisterTX) DecodeBinary(br *io.BinReader) error { br.ReadLE(&tx.AssetType) tx.Name = br.ReadString() @@ -43,7 +41,7 @@ func (tx *RegisterTX) DecodeBinary(r io.Reader) error { } tx.Owner = &keys.PublicKey{} - if err := tx.Owner.DecodeBinary(r); err != nil { + if err := tx.Owner.DecodeBinary(br); err != nil { return err } @@ -52,8 +50,7 @@ func (tx *RegisterTX) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (tx *RegisterTX) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(tx.AssetType) bw.WriteString(tx.Name) bw.WriteLE(tx.Amount) diff --git a/pkg/core/transaction/register_test.go b/pkg/core/transaction/register_test.go index 710979e3e..c8a9419d7 100644 --- a/pkg/core/transaction/register_test.go +++ b/pkg/core/transaction/register_test.go @@ -1,12 +1,12 @@ package transaction import ( - "bytes" "encoding/hex" "testing" "github.com/CityOfZion/neo-go/pkg/crypto" "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" ) @@ -26,11 +26,12 @@ func TestRegisterTX(t *testing.T) { }, } - buf := new(bytes.Buffer) - assert.Nil(t, tx.EncodeBinary(buf)) + buf := io.NewBufBinWriter() + assert.Nil(t, tx.EncodeBinary(buf.BinWriter)) + b := buf.Bytes() txDecode := &Transaction{} - assert.Nil(t, txDecode.DecodeBinary(buf)) + assert.Nil(t, txDecode.DecodeBinary(io.NewBinReaderFromBuf(b))) txData := tx.Data.(*RegisterTX) txDecodeData := txDecode.Data.(*RegisterTX) assert.Equal(t, txData, txDecodeData) @@ -45,7 +46,7 @@ func TestDecodeRegisterTXFromRawString(t *testing.T) { } tx := &Transaction{} - assert.Nil(t, tx.DecodeBinary(bytes.NewReader(b))) + assert.Nil(t, tx.DecodeBinary(io.NewBinReaderFromBuf(b))) assert.Equal(t, RegisterType, tx.Type) txData := tx.Data.(*RegisterTX) assert.Equal(t, GoverningToken, txData.AssetType) @@ -56,10 +57,11 @@ func TestDecodeRegisterTXFromRawString(t *testing.T) { assert.Equal(t, "Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt", crypto.AddressFromUint160(txData.Admin)) assert.Equal(t, "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", tx.Hash().ReverseString()) - buf := new(bytes.Buffer) - assert.Nil(t, tx.EncodeBinary(buf)) + buf := io.NewBufBinWriter() + assert.Nil(t, tx.EncodeBinary(buf.BinWriter)) + benc := buf.Bytes() txDecode := &Transaction{} - assert.Nil(t, txDecode.DecodeBinary(buf)) + assert.Nil(t, txDecode.DecodeBinary(io.NewBinReaderFromBuf(benc))) assert.Equal(t, tx, txDecode) } diff --git a/pkg/core/transaction/state.go b/pkg/core/transaction/state.go index 79127d14d..490c8f6a2 100644 --- a/pkg/core/transaction/state.go +++ b/pkg/core/transaction/state.go @@ -1,8 +1,7 @@ package transaction import ( - "io" - + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -12,36 +11,29 @@ type StateTX struct { } // DecodeBinary implements the Payload interface. -func (tx *StateTX) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) - lenDesc := br.ReadVarUint() - if br.Err != nil { - return br.Err - } +func (tx *StateTX) DecodeBinary(r *io.BinReader) error { + lenDesc := r.ReadVarUint() tx.Descriptors = make([]*StateDescriptor, lenDesc) for i := 0; i < int(lenDesc); i++ { tx.Descriptors[i] = &StateDescriptor{} - if err := tx.Descriptors[i].DecodeBinary(r); err != nil { + err := tx.Descriptors[i].DecodeBinary(r) + if err != nil { return err } } - return nil + return r.Err } // EncodeBinary implements the Payload interface. -func (tx *StateTX) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) - bw.WriteVarUint(uint64(len(tx.Descriptors))) - if bw.Err != nil { - return bw.Err - } +func (tx *StateTX) EncodeBinary(w *io.BinWriter) error { + w.WriteVarUint(uint64(len(tx.Descriptors))) for _, desc := range tx.Descriptors { err := desc.EncodeBinary(w) if err != nil { return err } } - return nil + return w.Err } // Size returns serialized binary size for this transaction. diff --git a/pkg/core/transaction/state_descriptor.go b/pkg/core/transaction/state_descriptor.go index 2ad49c494..c7e82822e 100644 --- a/pkg/core/transaction/state_descriptor.go +++ b/pkg/core/transaction/state_descriptor.go @@ -1,8 +1,7 @@ package transaction import ( - "io" - + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -24,25 +23,23 @@ type StateDescriptor struct { } // DecodeBinary implements the Payload interface. -func (s *StateDescriptor) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) - br.ReadLE(&s.Type) +func (s *StateDescriptor) DecodeBinary(r *io.BinReader) error { + r.ReadLE(&s.Type) - s.Key = br.ReadBytes() - s.Value = br.ReadBytes() - s.Field = br.ReadString() + s.Key = r.ReadBytes() + s.Value = r.ReadBytes() + s.Field = r.ReadString() - return br.Err + return r.Err } // EncodeBinary implements the Payload interface. -func (s *StateDescriptor) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) - bw.WriteLE(s.Type) - bw.WriteBytes(s.Key) - bw.WriteBytes(s.Value) - bw.WriteString(s.Field) - return bw.Err +func (s *StateDescriptor) EncodeBinary(w *io.BinWriter) error { + w.WriteLE(s.Type) + w.WriteBytes(s.Key) + w.WriteBytes(s.Value) + w.WriteString(s.Field) + return w.Err } // Size returns serialized binary size for state descriptor. diff --git a/pkg/core/transaction/state_test.go b/pkg/core/transaction/state_test.go index 65052058c..eb425b42e 100644 --- a/pkg/core/transaction/state_test.go +++ b/pkg/core/transaction/state_test.go @@ -1,10 +1,10 @@ package transaction import ( - "bytes" "encoding/hex" "testing" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) @@ -30,10 +30,9 @@ func TestEncodeDecodeState(t *testing.T) { assert.Equal(t, Validator, descriptor.Type) // Encode + buf := io.NewBufBinWriter() - buf := new(bytes.Buffer) - - err := tx.EncodeBinary(buf) + err := tx.EncodeBinary(buf.BinWriter) assert.Equal(t, nil, err) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) diff --git a/pkg/core/transaction/transaction.go b/pkg/core/transaction/transaction.go index 8dedd17c1..3bf651317 100644 --- a/pkg/core/transaction/transaction.go +++ b/pkg/core/transaction/transaction.go @@ -1,10 +1,8 @@ package transaction import ( - "bytes" - "io" - "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" log "github.com/sirupsen/logrus" ) @@ -77,14 +75,13 @@ func (t *Transaction) AddInput(in *Input) { } // DecodeBinary implements the payload interface. -func (t *Transaction) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (t *Transaction) DecodeBinary(br *io.BinReader) error { br.ReadLE(&t.Type) br.ReadLE(&t.Version) if br.Err != nil { return br.Err } - if err := t.decodeData(r); err != nil { + if err := t.decodeData(br); err != nil { return err } @@ -92,7 +89,7 @@ func (t *Transaction) DecodeBinary(r io.Reader) error { t.Attributes = make([]*Attribute, lenAttrs) for i := 0; i < int(lenAttrs); i++ { t.Attributes[i] = &Attribute{} - if err := t.Attributes[i].DecodeBinary(r); err != nil { + if err := t.Attributes[i].DecodeBinary(br); err != nil { log.Warnf("failed to decode TX %s", t.hash) return err } @@ -102,7 +99,7 @@ func (t *Transaction) DecodeBinary(r io.Reader) error { t.Inputs = make([]*Input, lenInputs) for i := 0; i < int(lenInputs); i++ { t.Inputs[i] = &Input{} - if err := t.Inputs[i].DecodeBinary(r); err != nil { + if err := t.Inputs[i].DecodeBinary(br); err != nil { return err } } @@ -111,7 +108,7 @@ func (t *Transaction) DecodeBinary(r io.Reader) error { t.Outputs = make([]*Output, lenOutputs) for i := 0; i < int(lenOutputs); i++ { t.Outputs[i] = &Output{} - if err := t.Outputs[i].DecodeBinary(r); err != nil { + if err := t.Outputs[i].DecodeBinary(br); err != nil { return err } } @@ -120,7 +117,7 @@ func (t *Transaction) DecodeBinary(r io.Reader) error { t.Scripts = make([]*Witness, lenScripts) for i := 0; i < int(lenScripts); i++ { t.Scripts[i] = &Witness{} - if err := t.Scripts[i].DecodeBinary(r); err != nil { + if err := t.Scripts[i].DecodeBinary(br); err != nil { return err } } @@ -133,7 +130,7 @@ func (t *Transaction) DecodeBinary(r io.Reader) error { return t.createHash() } -func (t *Transaction) decodeData(r io.Reader) error { +func (t *Transaction) decodeData(r *io.BinReader) error { switch t.Type { case InvocationType: t.Data = &InvocationTX{Version: t.Version} @@ -169,17 +166,16 @@ func (t *Transaction) decodeData(r io.Reader) error { } // EncodeBinary implements the payload interface. -func (t *Transaction) EncodeBinary(w io.Writer) error { - if err := t.encodeHashableFields(w); err != nil { +func (t *Transaction) EncodeBinary(bw *io.BinWriter) error { + if err := t.encodeHashableFields(bw); err != nil { return err } - bw := util.NewBinWriterFromIO(w) bw.WriteVarUint(uint64(len(t.Scripts))) if bw.Err != nil { return bw.Err } for _, s := range t.Scripts { - if err := s.EncodeBinary(w); err != nil { + if err := s.EncodeBinary(bw); err != nil { return err } } @@ -188,9 +184,7 @@ func (t *Transaction) EncodeBinary(w io.Writer) error { // encodeHashableFields will only encode the fields that are not used for // signing the transaction, which are all fields except the scripts. -func (t *Transaction) encodeHashableFields(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) - +func (t *Transaction) encodeHashableFields(bw *io.BinWriter) error { bw.WriteLE(t.Type) bw.WriteLE(t.Version) if bw.Err != nil { @@ -199,7 +193,7 @@ func (t *Transaction) encodeHashableFields(w io.Writer) error { // Underlying TXer. if t.Data != nil { - if err := t.Data.EncodeBinary(w); err != nil { + if err := t.Data.EncodeBinary(bw); err != nil { return err } } @@ -210,7 +204,7 @@ func (t *Transaction) encodeHashableFields(w io.Writer) error { return bw.Err } for _, attr := range t.Attributes { - if err := attr.EncodeBinary(w); err != nil { + if err := attr.EncodeBinary(bw); err != nil { return err } } @@ -221,7 +215,7 @@ func (t *Transaction) encodeHashableFields(w io.Writer) error { return bw.Err } for _, in := range t.Inputs { - if err := in.EncodeBinary(w); err != nil { + if err := in.EncodeBinary(bw); err != nil { return err } } @@ -232,7 +226,7 @@ func (t *Transaction) encodeHashableFields(w io.Writer) error { return bw.Err } for _, out := range t.Outputs { - if err := out.EncodeBinary(w); err != nil { + if err := out.EncodeBinary(bw); err != nil { return err } } @@ -241,8 +235,8 @@ func (t *Transaction) encodeHashableFields(w io.Writer) error { // createHash creates the hash of the transaction. func (t *Transaction) createHash() error { - buf := new(bytes.Buffer) - if err := t.encodeHashableFields(buf); err != nil { + buf := io.NewBufBinWriter() + if err := t.encodeHashableFields(buf.BinWriter); err != nil { return err } @@ -281,8 +275,8 @@ func (t *Transaction) Size() int { // Bytes convert the transaction to []byte func (t *Transaction) Bytes() []byte { - buf := new(bytes.Buffer) - if err := t.EncodeBinary(buf); err != nil { + buf := io.NewBufBinWriter() + if err := t.EncodeBinary(buf.BinWriter); err != nil { return nil } return buf.Bytes() diff --git a/pkg/core/transaction/transaction_test.go b/pkg/core/transaction/transaction_test.go index 3bfeb94da..a5387bb5f 100644 --- a/pkg/core/transaction/transaction_test.go +++ b/pkg/core/transaction/transaction_test.go @@ -1,11 +1,11 @@ package transaction import ( - "bytes" "encoding/hex" "testing" "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/smartcontract" "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" @@ -27,15 +27,14 @@ func TestWitnessEncodeDecode(t *testing.T) { VerificationScript: verif, } - buf := new(bytes.Buffer) - if err := wit.EncodeBinary(buf); err != nil { - t.Fatal(err) - } + buf := io.NewBufBinWriter() + err = wit.EncodeBinary(buf.BinWriter) + assert.Nil(t, err) + benc := buf.Bytes() witDecode := &Witness{} - if err := witDecode.DecodeBinary(buf); err != nil { - t.Fatal(err) - } + err = witDecode.DecodeBinary(io.NewBinReaderFromBuf(benc)) + assert.Nil(t, err) t.Log(len(witDecode.VerificationScript)) t.Log(len(witDecode.InvocationScript)) @@ -61,10 +60,9 @@ func TestDecodeEncodeClaimTX(t *testing.T) { assert.Equal(t, invoc, hex.EncodeToString(tx.Scripts[0].InvocationScript)) assert.Equal(t, verif, hex.EncodeToString(tx.Scripts[0].VerificationScript)) - buf := new(bytes.Buffer) - if err := tx.EncodeBinary(buf); err != nil { - t.Fatal(err) - } + buf := io.NewBufBinWriter() + err := tx.EncodeBinary(buf.BinWriter) + assert.Nil(t, err) assert.Equal(t, rawClaimTX, hex.EncodeToString(buf.Bytes())) hash := "2c6a45547b3898318e400e541628990a07acb00f3b9a15a8e966ae49525304da" @@ -90,10 +88,10 @@ func TestDecodeEncodeInvocationTX(t *testing.T) { assert.Equal(t, invoc, hex.EncodeToString(tx.Scripts[0].InvocationScript)) assert.Equal(t, verif, hex.EncodeToString(tx.Scripts[0].VerificationScript)) - buf := new(bytes.Buffer) - if err := tx.EncodeBinary(buf); err != nil { - t.Fatal(err) - } + buf := io.NewBufBinWriter() + err := tx.EncodeBinary(buf.BinWriter) + assert.Nil(t, err) + assert.Equal(t, rawInvocationTX, hex.EncodeToString(buf.Bytes())) } @@ -145,8 +143,8 @@ func TestDecodePublishTX(t *testing.T) { assert.Equal(t, expectedTX.Type, actualTX.Type) assert.Equal(t, expectedTX.Version, actualTX.Version) - buf := new(bytes.Buffer) - err := actualTX.EncodeBinary(buf) + buf := io.NewBufBinWriter() + err := actualTX.EncodeBinary(buf.BinWriter) assert.Nil(t, err) assert.Equal(t, rawPublishTX, hex.EncodeToString(buf.Bytes())) } diff --git a/pkg/core/transaction/txer.go b/pkg/core/transaction/txer.go index e87187bfd..c26c6364c 100644 --- a/pkg/core/transaction/txer.go +++ b/pkg/core/transaction/txer.go @@ -1,11 +1,11 @@ package transaction -import "io" +import "github.com/CityOfZion/neo-go/pkg/io" // TXer is interface that can act as the underlying data of // a transaction. type TXer interface { - DecodeBinary(io.Reader) error - EncodeBinary(io.Writer) error + DecodeBinary(*io.BinReader) error + EncodeBinary(*io.BinWriter) error Size() int } diff --git a/pkg/core/transaction/witness.go b/pkg/core/transaction/witness.go index d3a07e44d..20c1d8d91 100644 --- a/pkg/core/transaction/witness.go +++ b/pkg/core/transaction/witness.go @@ -3,9 +3,9 @@ package transaction import ( "encoding/hex" "encoding/json" - "io" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -16,18 +16,14 @@ type Witness struct { } // DecodeBinary implements the payload interface. -func (w *Witness) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) - +func (w *Witness) DecodeBinary(br *io.BinReader) error { w.InvocationScript = br.ReadBytes() w.VerificationScript = br.ReadBytes() return br.Err } // EncodeBinary implements the payload interface. -func (w *Witness) EncodeBinary(writer io.Writer) error { - bw := util.NewBinWriterFromIO(writer) - +func (w *Witness) EncodeBinary(bw *io.BinWriter) error { bw.WriteBytes(w.InvocationScript) bw.WriteBytes(w.VerificationScript) diff --git a/pkg/core/unspent_coin_state.go b/pkg/core/unspent_coin_state.go index 1954a750c..504dc68dd 100644 --- a/pkg/core/unspent_coin_state.go +++ b/pkg/core/unspent_coin_state.go @@ -1,12 +1,11 @@ package core import ( - "bytes" "fmt" - "io" "github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/transaction" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -22,7 +21,7 @@ func (u UnspentCoins) getAndUpdate(s storage.Store, hash util.Uint256) (*Unspent unspent := &UnspentCoinState{} key := storage.AppendPrefix(storage.STCoin, hash.BytesReverse()) if b, err := s.Get(key); err == nil { - if err := unspent.DecodeBinary(bytes.NewReader(b)); err != nil { + if err := unspent.DecodeBinary(io.NewBinReaderFromBuf(b)); err != nil { return nil, fmt.Errorf("failed to decode (UnspentCoinState): %s", err) } } else { @@ -53,9 +52,9 @@ func NewUnspentCoinState(n int) *UnspentCoinState { // commit writes all unspent coin states to the given Batch. func (u UnspentCoins) commit(b storage.Batch) error { - buf := new(bytes.Buffer) + buf := io.NewBufBinWriter() for hash, state := range u { - if err := state.EncodeBinary(buf); err != nil { + if err := state.EncodeBinary(buf.BinWriter); err != nil { return err } key := storage.AppendPrefix(storage.STCoin, hash.BytesReverse()) @@ -65,9 +64,8 @@ func (u UnspentCoins) commit(b storage.Batch) error { return nil } -// EncodeBinary encodes UnspentCoinState to the given io.Writer. -func (s *UnspentCoinState) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +// EncodeBinary encodes UnspentCoinState to the given BinWriter. +func (s *UnspentCoinState) EncodeBinary(bw *io.BinWriter) error { bw.WriteVarUint(uint64(len(s.states))) for _, state := range s.states { bw.WriteLE(byte(state)) @@ -75,9 +73,8 @@ func (s *UnspentCoinState) EncodeBinary(w io.Writer) error { return bw.Err } -// DecodeBinary decodes UnspentCoinState from the given io.Reader. -func (s *UnspentCoinState) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +// DecodeBinary decodes UnspentCoinState from the given BinReader. +func (s *UnspentCoinState) DecodeBinary(br *io.BinReader) error { lenStates := br.ReadVarUint() s.states = make([]CoinState, lenStates) for i := 0; i < int(lenStates); i++ { @@ -98,7 +95,7 @@ func IsDoubleSpend(s storage.Store, tx *transaction.Transaction) bool { unspent := &UnspentCoinState{} key := storage.AppendPrefix(storage.STCoin, prevHash.BytesReverse()) if b, err := s.Get(key); err == nil { - if err := unspent.DecodeBinary(bytes.NewReader(b)); err != nil { + if err := unspent.DecodeBinary(io.NewBinReaderFromBuf(b)); err != nil { return false } if unspent == nil { diff --git a/pkg/core/unspent_coint_state_test.go b/pkg/core/unspent_coint_state_test.go index 3338f6b8a..8fb649f19 100644 --- a/pkg/core/unspent_coint_state_test.go +++ b/pkg/core/unspent_coint_state_test.go @@ -1,10 +1,10 @@ package core import ( - "bytes" "testing" "github.com/CityOfZion/neo-go/pkg/core/storage" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) @@ -19,10 +19,10 @@ func TestDecodeEncodeUnspentCoinState(t *testing.T) { }, } - buf := new(bytes.Buffer) - assert.Nil(t, unspent.EncodeBinary(buf)) + buf := io.NewBufBinWriter() + assert.Nil(t, unspent.EncodeBinary(buf.BinWriter)) unspentDecode := &UnspentCoinState{} - assert.Nil(t, unspentDecode.DecodeBinary(buf)) + assert.Nil(t, unspentDecode.DecodeBinary(io.NewBinReaderFromBuf(buf.Bytes()))) } func TestCommitUnspentCoins(t *testing.T) { diff --git a/pkg/core/util.go b/pkg/core/util.go index de359a38f..b092a2da4 100644 --- a/pkg/core/util.go +++ b/pkg/core/util.go @@ -1,8 +1,6 @@ package core import ( - "bytes" - "encoding/binary" "time" "github.com/CityOfZion/neo-go/config" @@ -10,6 +8,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/smartcontract" "github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/vm" @@ -181,11 +180,9 @@ func headerSliceReverse(dest []*Header) { // storeAsCurrentBlock stores the given block witch prefix // SYSCurrentBlock. func storeAsCurrentBlock(batch storage.Batch, block *Block) { - buf := new(bytes.Buffer) - buf.Write(block.Hash().BytesReverse()) - b := make([]byte, 4) - binary.LittleEndian.PutUint32(b, block.Index) - buf.Write(b) + buf := io.NewBufBinWriter() + buf.WriteLE(block.Hash().BytesReverse()) + buf.WriteLE(block.Index) batch.Put(storage.SYSCurrentBlock.Bytes(), buf.Bytes()) } @@ -193,17 +190,18 @@ func storeAsCurrentBlock(batch storage.Batch, block *Block) { func storeAsBlock(batch storage.Batch, block *Block, sysFee uint32) error { var ( key = storage.AppendPrefix(storage.DataBlock, block.Hash().BytesReverse()) - buf = new(bytes.Buffer) + buf = io.NewBufBinWriter() ) - - b := make([]byte, 4) - binary.LittleEndian.PutUint32(b, sysFee) - + // sysFee needs to be handled somehow + // buf.WriteLE(sysFee) b, err := block.Trim() if err != nil { return err } - buf.Write(b) + buf.WriteLE(b) + if buf.Err != nil { + return buf.Err + } batch.Put(key, buf.Bytes()) return nil } @@ -211,15 +209,13 @@ func storeAsBlock(batch storage.Batch, block *Block, sysFee uint32) error { // storeAsTransaction stores the given TX as DataTransaction. func storeAsTransaction(batch storage.Batch, tx *transaction.Transaction, index uint32) error { key := storage.AppendPrefix(storage.DataTransaction, tx.Hash().BytesReverse()) - buf := new(bytes.Buffer) - if err := tx.EncodeBinary(buf); err != nil { + buf := io.NewBufBinWriter() + buf.WriteLE(index) + if err := tx.EncodeBinary(buf.BinWriter); err != nil { return err } - dest := make([]byte, buf.Len()+4) - binary.LittleEndian.PutUint32(dest[:4], index) - copy(dest[4:], buf.Bytes()) - batch.Put(key, dest) + batch.Put(key, buf.Bytes()) return nil } diff --git a/pkg/crypto/keys/publickey.go b/pkg/crypto/keys/publickey.go index a03734688..2a30c2626 100644 --- a/pkg/crypto/keys/publickey.go +++ b/pkg/crypto/keys/publickey.go @@ -5,14 +5,13 @@ import ( "crypto/ecdsa" "crypto/elliptic" "crypto/x509" - "encoding/binary" "encoding/hex" "fmt" - "io" "math/big" "github.com/CityOfZion/neo-go/pkg/crypto" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/pkg/errors" ) @@ -51,7 +50,7 @@ func NewPublicKeyFromString(s string) (*PublicKey, error) { } pubKey := new(PublicKey) - if err := pubKey.DecodeBinary(bytes.NewReader(b)); err != nil { + if err := pubKey.DecodeBinary(io.NewBinReaderFromBuf(b)); err != nil { return nil, err } @@ -122,20 +121,19 @@ func decodeCompressedY(x *big.Int, ylsb uint) (*big.Int, error) { // DecodeBytes decodes a PublicKey from the given slice of bytes. func (p *PublicKey) DecodeBytes(data []byte) error { - var datab []byte - copy(datab, data) - b := bytes.NewBuffer(datab) + b := io.NewBinReaderFromBuf(data) return p.DecodeBinary(b) } -// DecodeBinary decodes a PublicKey from the given io.Reader. -func (p *PublicKey) DecodeBinary(r io.Reader) error { +// DecodeBinary decodes a PublicKey from the given BinReader. +func (p *PublicKey) DecodeBinary(r *io.BinReader) error { var prefix uint8 var x, y *big.Int var err error - if err = binary.Read(r, binary.LittleEndian, &prefix); err != nil { - return err + r.ReadLE(&prefix) + if r.Err != nil { + return r.Err } // Infinity @@ -146,8 +144,9 @@ func (p *PublicKey) DecodeBinary(r io.Reader) error { case 0x02, 0x03: // Compressed public keys xbytes := make([]byte, 32) - if _, err := io.ReadFull(r, xbytes); err != nil { - return err + r.ReadLE(xbytes) + if r.Err != nil { + return r.Err } x = new(big.Int).SetBytes(xbytes) ylsb := uint(prefix & 0x1) @@ -158,11 +157,10 @@ func (p *PublicKey) DecodeBinary(r io.Reader) error { case 0x04: xbytes := make([]byte, 32) ybytes := make([]byte, 32) - if _, err = io.ReadFull(r, xbytes); err != nil { - return err - } - if _, err = io.ReadFull(r, ybytes); err != nil { - return err + r.ReadLE(xbytes) + r.ReadLE(ybytes) + if r.Err != nil { + return r.Err } x = new(big.Int).SetBytes(xbytes) y = new(big.Int).SetBytes(ybytes) @@ -182,9 +180,10 @@ func (p *PublicKey) DecodeBinary(r io.Reader) error { return nil } -// EncodeBinary encodes a PublicKey to the given io.Writer. -func (p *PublicKey) EncodeBinary(w io.Writer) error { - return binary.Write(w, binary.LittleEndian, p.Bytes()) +// EncodeBinary encodes a PublicKey to the given BinWriter. +func (p *PublicKey) EncodeBinary(w *io.BinWriter) error { + w.WriteLE(p.Bytes()) + return w.Err } // Signature returns a NEO-specific hash of the key. diff --git a/pkg/crypto/keys/publickey_test.go b/pkg/crypto/keys/publickey_test.go index 34c0b334d..71e73f5ef 100644 --- a/pkg/crypto/keys/publickey_test.go +++ b/pkg/crypto/keys/publickey_test.go @@ -1,21 +1,23 @@ package keys import ( - "bytes" "encoding/hex" "testing" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) func TestEncodeDecodeInfinity(t *testing.T) { key := &PublicKey{} - buf := new(bytes.Buffer) - assert.Nil(t, key.EncodeBinary(buf)) - assert.Equal(t, 1, buf.Len()) + buf := io.NewBufBinWriter() + assert.Nil(t, key.EncodeBinary(buf.BinWriter)) + assert.Nil(t, buf.Err) + b := buf.Bytes() + assert.Equal(t, 1, len(b)) keyDecode := &PublicKey{} - assert.Nil(t, keyDecode.DecodeBinary(buf)) + assert.Nil(t, keyDecode.DecodeBytes(b)) assert.Equal(t, []byte{0x00}, keyDecode.Bytes()) } @@ -24,11 +26,13 @@ func TestEncodeDecodePublicKey(t *testing.T) { k, err := NewPrivateKey() assert.Nil(t, err) p := k.PublicKey() - buf := new(bytes.Buffer) - assert.Nil(t, p.EncodeBinary(buf)) + buf := io.NewBufBinWriter() + assert.Nil(t, p.EncodeBinary(buf.BinWriter)) + assert.Nil(t, buf.Err) + b := buf.Bytes() pDecode := &PublicKey{} - assert.Nil(t, pDecode.DecodeBinary(buf)) + assert.Nil(t, pDecode.DecodeBytes(b)) assert.Equal(t, p.X, pDecode.X) } } diff --git a/pkg/util/binaryBufWriter.go b/pkg/io/binaryBufWriter.go similarity index 62% rename from pkg/util/binaryBufWriter.go rename to pkg/io/binaryBufWriter.go index 0a2ba4cfc..31ba262ac 100644 --- a/pkg/util/binaryBufWriter.go +++ b/pkg/io/binaryBufWriter.go @@ -1,4 +1,4 @@ -package util +package io import ( "bytes" @@ -27,3 +27,13 @@ func (bw *BufBinWriter) Bytes() []byte { bw.Err = errors.New("buffer already drained") return bw.buf.Bytes() } + +// Reset resets the state of the buffer, making it usable again. It can +// make buffer usage somewhat more efficient, because you don't need to +// create it again, but beware that the buffer is gonna be the same as the one +// returned by Bytes(), so if you need that data after Reset() you have to copy +// it yourself. +func (bw *BufBinWriter) Reset() { + bw.Err = nil + bw.buf.Reset() +} diff --git a/pkg/util/binaryReader.go b/pkg/io/binaryReader.go similarity index 99% rename from pkg/util/binaryReader.go rename to pkg/io/binaryReader.go index 47694891a..27845b21d 100644 --- a/pkg/util/binaryReader.go +++ b/pkg/io/binaryReader.go @@ -1,4 +1,4 @@ -package util +package io import ( "bytes" diff --git a/pkg/util/binaryWriter.go b/pkg/io/binaryWriter.go similarity index 99% rename from pkg/util/binaryWriter.go rename to pkg/io/binaryWriter.go index a867c94eb..b85cda48b 100644 --- a/pkg/util/binaryWriter.go +++ b/pkg/io/binaryWriter.go @@ -1,4 +1,4 @@ -package util +package io import ( "encoding/binary" diff --git a/pkg/util/binaryrw_test.go b/pkg/io/binaryrw_test.go similarity index 94% rename from pkg/util/binaryrw_test.go rename to pkg/io/binaryrw_test.go index 466504057..dc69a92c4 100644 --- a/pkg/util/binaryrw_test.go +++ b/pkg/io/binaryrw_test.go @@ -1,4 +1,4 @@ -package util +package io import ( "errors" @@ -101,6 +101,18 @@ func TestBufBinWriterErr(t *testing.T) { assert.Nil(t, res) } +func TestBufBinWriterReset(t *testing.T) { + bw := NewBufBinWriter() + for i := 0; i < 3; i++ { + bw.WriteLE(uint32(i)) + assert.Nil(t, bw.Err) + _ = bw.Bytes() + assert.NotNil(t, bw.Err) + bw.Reset() + assert.Nil(t, bw.Err) + } +} + func TestWriteString(t *testing.T) { var ( str string = "teststring" diff --git a/pkg/io/serializable.go b/pkg/io/serializable.go index 359c8513e..0f49c61d8 100644 --- a/pkg/io/serializable.go +++ b/pkg/io/serializable.go @@ -1,10 +1,8 @@ package io -import "io" - // Serializable defines the binary encoding/decoding interface. type Serializable interface { Size() int - DecodeBinary(io.Reader) error - EncodeBinary(io.Writer) error + DecodeBinary(*BinReader) error + EncodeBinary(*BinWriter) error } diff --git a/pkg/network/message.go b/pkg/network/message.go index 01b1a0947..69fe8b2d8 100644 --- a/pkg/network/message.go +++ b/pkg/network/message.go @@ -1,18 +1,15 @@ package network import ( - "bytes" "encoding/binary" "errors" - "fmt" - "io" "github.com/CityOfZion/neo-go/config" "github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/network/payload" - "github.com/CityOfZion/neo-go/pkg/util" ) const ( @@ -80,12 +77,13 @@ func NewMessage(magic config.NetMode, cmd CommandType, p payload.Payload) *Messa ) if p != nil { - buf := new(bytes.Buffer) - if err := p.EncodeBinary(buf); err != nil { + buf := io.NewBufBinWriter() + if err := p.EncodeBinary(buf.BinWriter); err != nil { panic(err) } - size = uint32(buf.Len()) - checksum = hash.Checksum(buf.Bytes()) + b := buf.Bytes() + size = uint32(len(b)) + checksum = hash.Checksum(b) } else { checksum = hash.Checksum([]byte{}) } @@ -147,8 +145,7 @@ func (m *Message) CommandType() CommandType { } // Decode a Message from the given reader. -func (m *Message) Decode(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (m *Message) Decode(br *io.BinReader) error { br.ReadLE(&m.Magic) br.ReadLE(&m.Command) br.ReadLE(&m.Length) @@ -160,67 +157,63 @@ func (m *Message) Decode(r io.Reader) error { if m.Length == 0 { return nil } - return m.decodePayload(r) + return m.decodePayload(br) } -func (m *Message) decodePayload(r io.Reader) error { - buf := new(bytes.Buffer) - n, err := io.CopyN(buf, r, int64(m.Length)) - if err != nil { - return err +func (m *Message) decodePayload(br *io.BinReader) error { + buf := make([]byte, m.Length) + br.ReadLE(buf) + if br.Err != nil { + return br.Err } - - if uint32(n) != m.Length { - return fmt.Errorf("expected to have read exactly %d bytes got %d", m.Length, n) - } - // Compare the checksum of the payload. - if !compareChecksum(m.Checksum, buf.Bytes()) { + if !compareChecksum(m.Checksum, buf) { return errChecksumMismatch } + r := io.NewBinReaderFromBuf(buf) var p payload.Payload switch m.CommandType() { case CMDVersion: p = &payload.Version{} - if err := p.DecodeBinary(buf); err != nil { + if err := p.DecodeBinary(r); err != nil { return err } case CMDInv, CMDGetData: p = &payload.Inventory{} - if err := p.DecodeBinary(buf); err != nil { + if err := p.DecodeBinary(r); err != nil { return err } case CMDAddr: p = &payload.AddressList{} - if err := p.DecodeBinary(buf); err != nil { + if err := p.DecodeBinary(r); err != nil { return err } case CMDBlock: p = &core.Block{} - if err := p.DecodeBinary(buf); err != nil { + if err := p.DecodeBinary(r); err != nil { return err } case CMDGetBlocks: fallthrough case CMDGetHeaders: p = &payload.GetBlocks{} - if err := p.DecodeBinary(buf); err != nil { + if err := p.DecodeBinary(r); err != nil { return err } case CMDHeaders: p = &payload.Headers{} - if err := p.DecodeBinary(buf); err != nil { + if err := p.DecodeBinary(r); err != nil { return err } case CMDTX: p = &transaction.Transaction{} - if err := p.DecodeBinary(buf); err != nil { + if err := p.DecodeBinary(r); err != nil { return err } case CMDMerkleBlock: p = &payload.MerkleBlock{} - if err := p.DecodeBinary(buf); err != nil { + if err := p.DecodeBinary(r); err != nil { return err } } @@ -230,9 +223,8 @@ func (m *Message) decodePayload(r io.Reader) error { return nil } -// Encode a Message to any given io.Writer. -func (m *Message) Encode(w io.Writer) error { - br := util.NewBinWriterFromIO(w) +// Encode a Message to any given BinWriter. +func (m *Message) Encode(br *io.BinWriter) error { br.WriteLE(m.Magic) br.WriteLE(m.Command) br.WriteLE(m.Length) @@ -241,7 +233,7 @@ func (m *Message) Encode(w io.Writer) error { return br.Err } if m.Payload != nil { - return m.Payload.EncodeBinary(w) + return m.Payload.EncodeBinary(br) } return nil } diff --git a/pkg/network/payload/address.go b/pkg/network/payload/address.go index d0b1765cd..e562f0b21 100644 --- a/pkg/network/payload/address.go +++ b/pkg/network/payload/address.go @@ -1,12 +1,11 @@ package payload import ( - "io" "net" "strconv" "time" - "github.com/CityOfZion/neo-go/pkg/util" + "github.com/CityOfZion/neo-go/pkg/io" ) // AddressAndTime payload. @@ -29,8 +28,7 @@ func NewAddressAndTime(e *net.TCPAddr, t time.Time) *AddressAndTime { } // DecodeBinary implements the Payload interface. -func (p *AddressAndTime) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (p *AddressAndTime) DecodeBinary(br *io.BinReader) error { br.ReadLE(&p.Timestamp) br.ReadLE(&p.Services) br.ReadBE(&p.IP) @@ -39,8 +37,7 @@ func (p *AddressAndTime) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (p *AddressAndTime) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (p *AddressAndTime) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(p.Timestamp) bw.WriteLE(p.Services) bw.WriteBE(p.IP) @@ -71,8 +68,7 @@ func NewAddressList(n int) *AddressList { } // DecodeBinary implements the Payload interface. -func (p *AddressList) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (p *AddressList) DecodeBinary(br *io.BinReader) error { listLen := br.ReadVarUint() if br.Err != nil { return br.Err @@ -81,7 +77,7 @@ func (p *AddressList) DecodeBinary(r io.Reader) error { p.Addrs = make([]*AddressAndTime, listLen) for i := 0; i < int(listLen); i++ { p.Addrs[i] = &AddressAndTime{} - if err := p.Addrs[i].DecodeBinary(r); err != nil { + if err := p.Addrs[i].DecodeBinary(br); err != nil { return err } } @@ -89,14 +85,13 @@ func (p *AddressList) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (p *AddressList) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (p *AddressList) EncodeBinary(bw *io.BinWriter) error { bw.WriteVarUint(uint64(len(p.Addrs))) if bw.Err != nil { return bw.Err } for _, addr := range p.Addrs { - if err := addr.EncodeBinary(w); err != nil { + if err := addr.EncodeBinary(bw); err != nil { return err } } diff --git a/pkg/network/payload/address_test.go b/pkg/network/payload/address_test.go index afece415a..dbe5db885 100644 --- a/pkg/network/payload/address_test.go +++ b/pkg/network/payload/address_test.go @@ -1,12 +1,12 @@ package payload import ( - "bytes" "fmt" "net" "testing" "time" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) @@ -15,7 +15,7 @@ func TestEncodeDecodeAddress(t *testing.T) { e, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:2000") ts = time.Now() addr = NewAddressAndTime(e, ts) - buf = new(bytes.Buffer) + buf = io.NewBufBinWriter() ) assert.Equal(t, ts.UTC().Unix(), int64(addr.Timestamp)) @@ -23,11 +23,13 @@ func TestEncodeDecodeAddress(t *testing.T) { copy(aatip, addr.IP[:]) assert.Equal(t, e.IP, aatip) assert.Equal(t, e.Port, int(addr.Port)) - err := addr.EncodeBinary(buf) + err := addr.EncodeBinary(buf.BinWriter) assert.Nil(t, err) + b := buf.Bytes() + r := io.NewBinReaderFromBuf(b) addrDecode := &AddressAndTime{} - err = addrDecode.DecodeBinary(buf) + err = addrDecode.DecodeBinary(r) assert.Nil(t, err) assert.Equal(t, addr, addrDecode) @@ -41,12 +43,14 @@ func TestEncodeDecodeAddressList(t *testing.T) { addrList.Addrs[i] = NewAddressAndTime(e, time.Now()) } - buf := new(bytes.Buffer) - err := addrList.EncodeBinary(buf) + buf := io.NewBufBinWriter() + err := addrList.EncodeBinary(buf.BinWriter) assert.Nil(t, err) + b := buf.Bytes() + r := io.NewBinReaderFromBuf(b) addrListDecode := &AddressList{} - err = addrListDecode.DecodeBinary(buf) + err = addrListDecode.DecodeBinary(r) assert.Nil(t, err) assert.Equal(t, addrList, addrListDecode) diff --git a/pkg/network/payload/getblocks.go b/pkg/network/payload/getblocks.go index 1246a9348..f1e3e1fc1 100644 --- a/pkg/network/payload/getblocks.go +++ b/pkg/network/payload/getblocks.go @@ -1,8 +1,7 @@ package payload import ( - "io" - + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -23,8 +22,7 @@ func NewGetBlocks(start []util.Uint256, stop util.Uint256) *GetBlocks { } // DecodeBinary implements the payload interface. -func (p *GetBlocks) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (p *GetBlocks) DecodeBinary(br *io.BinReader) error { lenStart := br.ReadVarUint() p.HashStart = make([]util.Uint256, lenStart) @@ -34,8 +32,7 @@ func (p *GetBlocks) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the payload interface. -func (p *GetBlocks) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (p *GetBlocks) EncodeBinary(bw *io.BinWriter) error { bw.WriteVarUint(uint64(len(p.HashStart))) bw.WriteLE(p.HashStart) bw.WriteLE(p.HashStop) diff --git a/pkg/network/payload/getblocks_test.go b/pkg/network/payload/getblocks_test.go index e0745a3fb..5844c9bbd 100644 --- a/pkg/network/payload/getblocks_test.go +++ b/pkg/network/payload/getblocks_test.go @@ -1,10 +1,10 @@ package payload import ( - "bytes" "testing" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" ) @@ -18,12 +18,14 @@ func TestGetBlockEncodeDecode(t *testing.T) { } p := NewGetBlocks(start, util.Uint256{}) - buf := new(bytes.Buffer) - err := p.EncodeBinary(buf) + buf := io.NewBufBinWriter() + err := p.EncodeBinary(buf.BinWriter) assert.Nil(t, err) + b := buf.Bytes() + r := io.NewBinReaderFromBuf(b) pDecode := &GetBlocks{} - err = pDecode.DecodeBinary(buf) + err = pDecode.DecodeBinary(r) assert.Nil(t, err) assert.Equal(t, p, pDecode) } @@ -39,12 +41,14 @@ func TestGetBlockEncodeDecodeWithHashStop(t *testing.T) { stop = hash.Sha256([]byte("e")) ) p := NewGetBlocks(start, stop) - buf := new(bytes.Buffer) - err := p.EncodeBinary(buf) + buf := io.NewBufBinWriter() + err := p.EncodeBinary(buf.BinWriter) assert.Nil(t, err) + b := buf.Bytes() + r := io.NewBinReaderFromBuf(b) pDecode := &GetBlocks{} - err = pDecode.DecodeBinary(buf) + err = pDecode.DecodeBinary(r) assert.Nil(t, err) assert.Equal(t, p, pDecode) } diff --git a/pkg/network/payload/headers.go b/pkg/network/payload/headers.go index 1e3904d1b..66771fb5e 100644 --- a/pkg/network/payload/headers.go +++ b/pkg/network/payload/headers.go @@ -1,10 +1,8 @@ package payload import ( - "io" - "github.com/CityOfZion/neo-go/pkg/core" - "github.com/CityOfZion/neo-go/pkg/util" + "github.com/CityOfZion/neo-go/pkg/io" log "github.com/sirupsen/logrus" ) @@ -19,8 +17,7 @@ const ( ) // DecodeBinary implements the Payload interface. -func (p *Headers) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (p *Headers) DecodeBinary(br *io.BinReader) error { lenHeaders := br.ReadVarUint() if br.Err != nil { return br.Err @@ -35,7 +32,7 @@ func (p *Headers) DecodeBinary(r io.Reader) error { for i := 0; i < int(lenHeaders); i++ { header := &core.Header{} - if err := header.DecodeBinary(r); err != nil { + if err := header.DecodeBinary(br); err != nil { return err } p.Hdrs[i] = header @@ -45,15 +42,14 @@ func (p *Headers) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (p *Headers) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (p *Headers) EncodeBinary(bw *io.BinWriter) error { bw.WriteVarUint(uint64(len(p.Hdrs))) if bw.Err != nil { return bw.Err } for _, header := range p.Hdrs { - if err := header.EncodeBinary(w); err != nil { + if err := header.EncodeBinary(bw); err != nil { return err } } diff --git a/pkg/network/payload/headers_test.go b/pkg/network/payload/headers_test.go index 7b762d4b8..2ee849f27 100644 --- a/pkg/network/payload/headers_test.go +++ b/pkg/network/payload/headers_test.go @@ -1,12 +1,12 @@ package payload import ( - "bytes" "encoding/hex" "testing" "github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/core/transaction" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) @@ -41,12 +41,14 @@ func TestHeadersEncodeDecode(t *testing.T) { }}, }} - buf := new(bytes.Buffer) - err := headers.EncodeBinary(buf) + buf := io.NewBufBinWriter() + err := headers.EncodeBinary(buf.BinWriter) assert.Nil(t, err) + b := buf.Bytes() + r := io.NewBinReaderFromBuf(b) headersDecode := &Headers{} - err = headersDecode.DecodeBinary(buf) + err = headersDecode.DecodeBinary(r) assert.Nil(t, err) for i := 0; i < len(headers.Hdrs); i++ { @@ -63,7 +65,7 @@ func TestBinEncodeDecode(t *testing.T) { rawBlockBytes, _ := hex.DecodeString(rawBlockHeaders) - r := bytes.NewReader(rawBlockBytes) + r := io.NewBinReaderFromBuf(rawBlockBytes) err := headerMsg.DecodeBinary(r) assert.Nil(t, err) @@ -74,9 +76,9 @@ func TestBinEncodeDecode(t *testing.T) { assert.Equal(t, "f3c4ec44c07eccbda974f1ee34bc6654ab6d3f22cd89c2e5c593a16d6cc7e6e8", hash.ReverseString()) - buf := new(bytes.Buffer) + buf := io.NewBufBinWriter() - err = headerMsg.EncodeBinary(buf) + err = headerMsg.EncodeBinary(buf.BinWriter) assert.Equal(t, nil, err) assert.Equal(t, hex.EncodeToString(rawBlockBytes), hex.EncodeToString(buf.Bytes())) } diff --git a/pkg/network/payload/inventory.go b/pkg/network/payload/inventory.go index cdfd783fe..ade25c9c8 100644 --- a/pkg/network/payload/inventory.go +++ b/pkg/network/payload/inventory.go @@ -1,8 +1,7 @@ package payload import ( - "io" - + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -56,8 +55,7 @@ func NewInventory(typ InventoryType, hashes []util.Uint256) *Inventory { } // DecodeBinary implements the Payload interface. -func (p *Inventory) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (p *Inventory) DecodeBinary(br *io.BinReader) error { br.ReadLE(&p.Type) listLen := br.ReadVarUint() @@ -70,8 +68,7 @@ func (p *Inventory) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (p *Inventory) EncodeBinary(w io.Writer) error { - bw := util.NewBinWriterFromIO(w) +func (p *Inventory) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(p.Type) listLen := len(p.Hashes) diff --git a/pkg/network/payload/inventory_test.go b/pkg/network/payload/inventory_test.go index f9fffcc79..acbe7c7c2 100644 --- a/pkg/network/payload/inventory_test.go +++ b/pkg/network/payload/inventory_test.go @@ -1,10 +1,10 @@ package payload import ( - "bytes" "testing" "github.com/CityOfZion/neo-go/pkg/crypto/hash" + "github.com/CityOfZion/neo-go/pkg/io" . "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" ) @@ -16,12 +16,14 @@ func TestInventoryEncodeDecode(t *testing.T) { } inv := NewInventory(BlockType, hashes) - buf := new(bytes.Buffer) - err := inv.EncodeBinary(buf) + buf := io.NewBufBinWriter() + err := inv.EncodeBinary(buf.BinWriter) assert.Nil(t, err) + b := buf.Bytes() + r := io.NewBinReaderFromBuf(b) invDecode := &Inventory{} - err = invDecode.DecodeBinary(buf) + err = invDecode.DecodeBinary(r) assert.Nil(t, err) assert.Equal(t, inv, invDecode) } @@ -29,8 +31,8 @@ func TestInventoryEncodeDecode(t *testing.T) { func TestEmptyInv(t *testing.T) { msgInv := NewInventory(TXType, []Uint256{}) - buf := new(bytes.Buffer) - err := msgInv.EncodeBinary(buf) + buf := io.NewBufBinWriter() + err := msgInv.EncodeBinary(buf.BinWriter) assert.Nil(t, err) assert.Equal(t, []byte{byte(TXType), 0}, buf.Bytes()) assert.Equal(t, 0, len(msgInv.Hashes)) diff --git a/pkg/network/payload/merkleblock.go b/pkg/network/payload/merkleblock.go index 2396bec85..2c9cf979c 100644 --- a/pkg/network/payload/merkleblock.go +++ b/pkg/network/payload/merkleblock.go @@ -1,9 +1,8 @@ package payload import ( - "io" - "github.com/CityOfZion/neo-go/pkg/core" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -16,12 +15,11 @@ type MerkleBlock struct { } // DecodeBinary implements the Payload interface. -func (m *MerkleBlock) DecodeBinary(r io.Reader) error { +func (m *MerkleBlock) DecodeBinary(br *io.BinReader) error { m.BlockBase = &core.BlockBase{} - if err := m.BlockBase.DecodeBinary(r); err != nil { + if err := m.BlockBase.DecodeBinary(br); err != nil { return err } - br := util.NewBinReaderFromIO(r) m.TxCount = int(br.ReadVarUint()) n := br.ReadVarUint() @@ -34,6 +32,6 @@ func (m *MerkleBlock) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (m *MerkleBlock) EncodeBinary(w io.Writer) error { +func (m *MerkleBlock) EncodeBinary(bw *io.BinWriter) error { return nil } diff --git a/pkg/network/payload/payload.go b/pkg/network/payload/payload.go index e23f9955a..870b9972a 100644 --- a/pkg/network/payload/payload.go +++ b/pkg/network/payload/payload.go @@ -1,11 +1,11 @@ package payload -import "io" +import "github.com/CityOfZion/neo-go/pkg/io" // Payload is anything that can be binary encoded/decoded. type Payload interface { - EncodeBinary(io.Writer) error - DecodeBinary(io.Reader) error + EncodeBinary(*io.BinWriter) error + DecodeBinary(*io.BinReader) error } // NullPayload is a dummy payload with no fields. diff --git a/pkg/network/payload/version.go b/pkg/network/payload/version.go index 3402ed1cd..b9d347d45 100644 --- a/pkg/network/payload/version.go +++ b/pkg/network/payload/version.go @@ -1,9 +1,9 @@ package payload import ( - "io" "time" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -55,8 +55,7 @@ func NewVersion(id uint32, p uint16, ua string, h uint32, r bool) *Version { } // DecodeBinary implements the Payload interface. -func (p *Version) DecodeBinary(r io.Reader) error { - br := util.NewBinReaderFromIO(r) +func (p *Version) DecodeBinary(br *io.BinReader) error { br.ReadLE(&p.Version) br.ReadLE(&p.Services) br.ReadLE(&p.Timestamp) @@ -69,8 +68,7 @@ func (p *Version) DecodeBinary(r io.Reader) error { } // EncodeBinary implements the Payload interface. -func (p *Version) EncodeBinary(w io.Writer) error { - br := util.NewBinWriterFromIO(w) +func (p *Version) EncodeBinary(br *io.BinWriter) error { br.WriteLE(p.Version) br.WriteLE(p.Services) br.WriteLE(p.Timestamp) diff --git a/pkg/network/payload/version_test.go b/pkg/network/payload/version_test.go index ca4ed156d..559fe94ed 100644 --- a/pkg/network/payload/version_test.go +++ b/pkg/network/payload/version_test.go @@ -1,9 +1,9 @@ package payload import ( - "bytes" "testing" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) @@ -16,13 +16,15 @@ func TestVersionEncodeDecode(t *testing.T) { version := NewVersion(id, port, useragent, height, relay) - buf := new(bytes.Buffer) - err := version.EncodeBinary(buf) + buf := io.NewBufBinWriter() + err := version.EncodeBinary(buf.BinWriter) assert.Nil(t, err) - assert.Equal(t, int(version.Size()), buf.Len()) + b := buf.Bytes() + assert.Equal(t, int(version.Size()), len(b)) + r := io.NewBinReaderFromBuf(b) versionDecoded := &Version{} - err = versionDecoded.DecodeBinary(buf) + err = versionDecoded.DecodeBinary(r) assert.Nil(t, err) assert.Equal(t, versionDecoded.Nonce, id) assert.Equal(t, versionDecoded.Port, port) diff --git a/pkg/network/tcp_peer.go b/pkg/network/tcp_peer.go index 10dac0a82..a9a5b5a27 100644 --- a/pkg/network/tcp_peer.go +++ b/pkg/network/tcp_peer.go @@ -6,6 +6,7 @@ import ( "net" "sync" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/network/payload" ) @@ -68,7 +69,8 @@ func (p *TCPPeer) writeMsg(msg *Message) error { case err := <-p.done: return err default: - return msg.Encode(p.conn) + w := io.NewBinWriterFromIO(p.conn) + return msg.Encode(w) } } diff --git a/pkg/network/tcp_transport.go b/pkg/network/tcp_transport.go index 8f61b7607..b99c060dd 100644 --- a/pkg/network/tcp_transport.go +++ b/pkg/network/tcp_transport.go @@ -5,6 +5,7 @@ import ( "regexp" "time" + "github.com/CityOfZion/neo-go/pkg/io" log "github.com/sirupsen/logrus" ) @@ -77,9 +78,10 @@ func (t *TCPTransport) handleConn(conn net.Conn) { t.server.register <- p + r := io.NewBinReaderFromIO(p.conn) for { msg := &Message{} - if err = msg.Decode(p.conn); err != nil { + if err = msg.Decode(r); err != nil { break } if err = t.server.handleMessage(p, msg); err != nil { diff --git a/pkg/rpc/rpc.go b/pkg/rpc/rpc.go index 73d62c421..09684d114 100644 --- a/pkg/rpc/rpc.go +++ b/pkg/rpc/rpc.go @@ -1,10 +1,10 @@ package rpc import ( - "bytes" "encoding/hex" "github.com/CityOfZion/neo-go/pkg/core/transaction" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/smartcontract" "github.com/CityOfZion/neo-go/pkg/util" "github.com/pkg/errors" @@ -113,7 +113,7 @@ func (c *Client) sendRawTransaction(rawTX string) (*response, error) { func (c *Client) SendToAddress(asset util.Uint256, address string, amount util.Fixed8) (*SendToAddressResponse, error) { var ( err error - buf = &bytes.Buffer{} + buf = io.NewBufBinWriter() rawTx *transaction.Transaction rawTxStr string txParams = ContractTxParams{ @@ -130,7 +130,7 @@ func (c *Client) SendToAddress(asset util.Uint256, address string, amount util.F if rawTx, err = CreateRawContractTransaction(txParams); err != nil { return nil, errors.Wrap(err, "failed to create raw transaction for `sendtoaddress`") } - if err = rawTx.EncodeBinary(buf); err != nil { + if err = rawTx.EncodeBinary(buf.BinWriter); err != nil { return nil, errors.Wrap(err, "failed to encode raw transaction to binary for `sendtoaddress`") } rawTxStr = hex.EncodeToString(buf.Bytes()) diff --git a/pkg/rpc/server.go b/pkg/rpc/server.go index f8fcb836b..db73d2ae1 100644 --- a/pkg/rpc/server.go +++ b/pkg/rpc/server.go @@ -1,7 +1,6 @@ package rpc import ( - "bytes" "context" "encoding/hex" "fmt" @@ -11,6 +10,7 @@ import ( "github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/network" "github.com/CityOfZion/neo-go/pkg/rpc/result" "github.com/CityOfZion/neo-go/pkg/rpc/wrappers" @@ -294,7 +294,7 @@ func (s *Server) sendrawtransaction(reqParams Params) (interface{}, error) { } else if byteTx, err := hex.DecodeString(param.StringVal); err != nil { resultsErr = errInvalidParams } else { - r := bytes.NewReader(byteTx) + r := io.NewBinReaderFromBuf(byteTx) tx := &transaction.Transaction{} err = tx.DecodeBinary(r) if err != nil { diff --git a/pkg/rpc/txBuilder.go b/pkg/rpc/txBuilder.go index 3109c1424..d68f3b12a 100644 --- a/pkg/rpc/txBuilder.go +++ b/pkg/rpc/txBuilder.go @@ -1,11 +1,10 @@ package rpc import ( - "bytes" - "github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/crypto" "github.com/CityOfZion/neo-go/pkg/crypto/keys" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" errs "github.com/pkg/errors" ) @@ -71,10 +70,10 @@ func GetInvocationScript(tx *transaction.Transaction, wif keys.WIF) ([]byte, err ) var ( err error - buf = new(bytes.Buffer) + buf = io.NewBufBinWriter() signature []byte ) - if err = tx.EncodeBinary(buf); err != nil { + if err = tx.EncodeBinary(buf.BinWriter); err != nil { return nil, errs.Wrap(err, "Failed to encode transaction to binary") } data := buf.Bytes() diff --git a/pkg/smartcontract/contract_test.go b/pkg/smartcontract/contract_test.go index d42e41811..1cca3d229 100644 --- a/pkg/smartcontract/contract_test.go +++ b/pkg/smartcontract/contract_test.go @@ -4,7 +4,7 @@ import ( "testing" "github.com/CityOfZion/neo-go/pkg/crypto/keys" - "github.com/CityOfZion/neo-go/pkg/util" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/vm" "github.com/stretchr/testify/assert" ) @@ -21,7 +21,7 @@ func TestCreateMultiSigRedeemScript(t *testing.T) { t.Fatal(err) } - br := util.NewBinReaderFromBuf(out) + br := io.NewBinReaderFromBuf(out) var b uint8 br.ReadLE(&b) assert.Equal(t, vm.PUSH3, vm.Instruction(b)) diff --git a/pkg/util/size_test.go b/pkg/util/size_test.go index 9d1217424..d77ceaebc 100644 --- a/pkg/util/size_test.go +++ b/pkg/util/size_test.go @@ -2,9 +2,9 @@ package util import ( "fmt" - "io" "testing" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" ) @@ -12,11 +12,11 @@ import ( type smthSerializable struct { } -func (*smthSerializable) DecodeBinary(io.Reader) error { +func (*smthSerializable) DecodeBinary(*io.BinReader) error { return nil } -func (*smthSerializable) EncodeBinary(io.Writer) error { +func (*smthSerializable) EncodeBinary(*io.BinWriter) error { return nil }