From aacf58c9ab02388d3fb2e08c139be215c70e348d Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Sun, 15 Sep 2019 14:58:19 +0300 Subject: [PATCH 01/12] util: add 'constructors' for BinReader/BinWriter And an additional BufBinWriter to ease buffer management. --- pkg/core/account_state.go | 4 +-- pkg/core/asset_state.go | 4 +-- pkg/core/block.go | 8 ++--- pkg/core/block_base.go | 8 ++--- pkg/core/header_hash_list.go | 2 +- pkg/core/spent_coin_state.go | 4 +-- pkg/core/storage/helpers.go | 2 +- pkg/core/transaction/attribute.go | 4 +-- pkg/core/transaction/claim.go | 4 +-- pkg/core/transaction/input.go | 4 +-- pkg/core/transaction/invocation.go | 4 +-- pkg/core/transaction/output.go | 4 +-- pkg/core/transaction/publish.go | 4 +-- pkg/core/transaction/register.go | 4 +-- pkg/core/transaction/state.go | 4 +-- pkg/core/transaction/state_descriptor.go | 4 +-- pkg/core/transaction/transaction.go | 6 ++-- pkg/core/transaction/witness.go | 4 +-- pkg/core/unspent_coin_state.go | 4 +-- pkg/network/message.go | 4 +-- pkg/network/payload/address.go | 8 ++--- pkg/network/payload/getblocks.go | 4 +-- pkg/network/payload/headers.go | 4 +-- pkg/network/payload/inventory.go | 4 +-- pkg/network/payload/merkleblock.go | 2 +- pkg/network/payload/version.go | 4 +-- pkg/smartcontract/contract_test.go | 4 +-- pkg/util/binaryBufWriter.go | 29 +++++++++++++++++++ pkg/util/binaryReader.go | 26 ++++++++++++----- pkg/util/binaryWriter.go | 25 +++++++++------- pkg/util/binaryrw_test.go | 37 ++++++++++++------------ 31 files changed, 138 insertions(+), 95 deletions(-) create mode 100644 pkg/util/binaryBufWriter.go diff --git a/pkg/core/account_state.go b/pkg/core/account_state.go index 44d277e76..7325b1b4d 100644 --- a/pkg/core/account_state.go +++ b/pkg/core/account_state.go @@ -68,7 +68,7 @@ func NewAccountState(scriptHash util.Uint160) *AccountState { // DecodeBinary decodes AccountState from the given io.Reader. func (s *AccountState) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&s.Version) br.ReadLE(&s.ScriptHash) br.ReadLE(&s.IsFrozen) @@ -96,7 +96,7 @@ func (s *AccountState) DecodeBinary(r io.Reader) error { // EncodeBinary encode AccountState to the given io.Writer. func (s *AccountState) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteLE(s.Version) bw.WriteLE(s.ScriptHash) bw.WriteLE(s.IsFrozen) diff --git a/pkg/core/asset_state.go b/pkg/core/asset_state.go index 19f7db8c3..02707eee9 100644 --- a/pkg/core/asset_state.go +++ b/pkg/core/asset_state.go @@ -47,7 +47,7 @@ type AssetState struct { // DecodeBinary implements the Payload interface. func (a *AssetState) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&a.ID) br.ReadLE(&a.AssetType) @@ -76,7 +76,7 @@ func (a *AssetState) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (a *AssetState) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteLE(a.ID) bw.WriteLE(a.AssetType) bw.WriteString(a.Name) diff --git a/pkg/core/block.go b/pkg/core/block.go index 38d8a9122..e17483e4d 100644 --- a/pkg/core/block.go +++ b/pkg/core/block.go @@ -78,7 +78,7 @@ func NewBlockFromTrimmedBytes(b []byte) (*Block, error) { return block, err } - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) var padding uint8 br.ReadLE(&padding) if br.Err != nil { @@ -109,7 +109,7 @@ func (b *Block) Trim() ([]byte, error) { if err := b.encodeHashableFields(buf); err != nil { return nil, err } - bw := util.BinWriter{W: buf} + bw := util.NewBinWriterFromIO(buf) bw.WriteLE(uint8(1)) if bw.Err != nil { return nil, bw.Err @@ -134,7 +134,7 @@ func (b *Block) DecodeBinary(r io.Reader) error { return err } - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) lentx := br.ReadVarUint() if br.Err != nil { return br.Err @@ -156,7 +156,7 @@ func (b *Block) EncodeBinary(w io.Writer) error { if err != nil { return err } - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteVarUint(uint64(len(b.Transactions))) if bw.Err != nil { return err diff --git a/pkg/core/block_base.go b/pkg/core/block_base.go index 00fd4d277..75f769340 100644 --- a/pkg/core/block_base.go +++ b/pkg/core/block_base.go @@ -66,7 +66,7 @@ func (b *BlockBase) DecodeBinary(r io.Reader) error { } var padding uint8 - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&padding) if br.Err != nil { return br.Err @@ -84,7 +84,7 @@ func (b *BlockBase) EncodeBinary(w io.Writer) error { if err := b.encodeHashableFields(w); err != nil { return err } - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteLE(uint8(1)) if bw.Err != nil { return bw.Err @@ -111,7 +111,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.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteLE(b.Version) bw.WriteLE(b.PrevHash) bw.WriteLE(b.MerkleRoot) @@ -125,7 +125,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.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&b.Version) br.ReadLE(&b.PrevHash) br.ReadLE(&b.MerkleRoot) diff --git a/pkg/core/header_hash_list.go b/pkg/core/header_hash_list.go index 35c190afa..d54723aba 100644 --- a/pkg/core/header_hash_list.go +++ b/pkg/core/header_hash_list.go @@ -59,7 +59,7 @@ func (l *HeaderHashList) Slice(start, end int) []util.Uint256 { // WriteTo will write n underlying hashes to the given io.Writer // starting from start. func (l *HeaderHashList) Write(w io.Writer, start, n int) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteVarUint(uint64(n)) hashes := l.Slice(start, start+n) for _, hash := range hashes { diff --git a/pkg/core/spent_coin_state.go b/pkg/core/spent_coin_state.go index fcfde1ae7..594fd3756 100644 --- a/pkg/core/spent_coin_state.go +++ b/pkg/core/spent_coin_state.go @@ -67,7 +67,7 @@ func NewSpentCoinState(hash util.Uint256, height uint32) *SpentCoinState { // DecodeBinary implements the Payload interface. func (s *SpentCoinState) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&s.txHash) br.ReadLE(&s.txHeight) @@ -87,7 +87,7 @@ func (s *SpentCoinState) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (s *SpentCoinState) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteLE(s.txHash) bw.WriteLE(s.txHeight) bw.WriteVarUint(uint64(len(s.items))) diff --git a/pkg/core/storage/helpers.go b/pkg/core/storage/helpers.go index 4a35d9ad7..ca3c1a7c2 100644 --- a/pkg/core/storage/helpers.go +++ b/pkg/core/storage/helpers.go @@ -84,7 +84,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.BinReader{R: r} + br := util.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 1b3ca0c3b..c5df619f3 100644 --- a/pkg/core/transaction/attribute.go +++ b/pkg/core/transaction/attribute.go @@ -17,7 +17,7 @@ type Attribute struct { // DecodeBinary implements the Payload interface. func (attr *Attribute) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&attr.Usage) // very special case @@ -54,7 +54,7 @@ func (attr *Attribute) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (attr *Attribute) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) 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 468ce0f19..f5c7c8e8d 100644 --- a/pkg/core/transaction/claim.go +++ b/pkg/core/transaction/claim.go @@ -13,7 +13,7 @@ type ClaimTX struct { // DecodeBinary implements the Payload interface. func (tx *ClaimTX) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) lenClaims := br.ReadVarUint() if br.Err != nil { return br.Err @@ -30,7 +30,7 @@ func (tx *ClaimTX) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (tx *ClaimTX) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteVarUint(uint64(len(tx.Claims))) if bw.Err != nil { return bw.Err diff --git a/pkg/core/transaction/input.go b/pkg/core/transaction/input.go index ab923981f..f2bd3e4df 100644 --- a/pkg/core/transaction/input.go +++ b/pkg/core/transaction/input.go @@ -17,7 +17,7 @@ type Input struct { // DecodeBinary implements the Payload interface. func (in *Input) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&in.PrevHash) br.ReadLE(&in.PrevIndex) return br.Err @@ -25,7 +25,7 @@ func (in *Input) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (in *Input) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) 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 0b255426c..36df0a948 100644 --- a/pkg/core/transaction/invocation.go +++ b/pkg/core/transaction/invocation.go @@ -34,7 +34,7 @@ func NewInvocationTX(script []byte) *Transaction { // DecodeBinary implements the Payload interface. func (tx *InvocationTX) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) tx.Script = br.ReadBytes() if tx.Version >= 1 { br.ReadLE(&tx.Gas) @@ -46,7 +46,7 @@ func (tx *InvocationTX) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (tx *InvocationTX) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteBytes(tx.Script) if tx.Version >= 1 { bw.WriteLE(tx.Gas) diff --git a/pkg/core/transaction/output.go b/pkg/core/transaction/output.go index 60a55b5cf..1afa21e5a 100644 --- a/pkg/core/transaction/output.go +++ b/pkg/core/transaction/output.go @@ -35,7 +35,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.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&out.AssetID) br.ReadLE(&out.Amount) br.ReadLE(&out.ScriptHash) @@ -44,7 +44,7 @@ func (out *Output) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (out *Output) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) 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 3a3c735f3..4d20de820 100644 --- a/pkg/core/transaction/publish.go +++ b/pkg/core/transaction/publish.go @@ -24,7 +24,7 @@ type PublishTX struct { // DecodeBinary implements the Payload interface. func (tx *PublishTX) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) tx.Script = br.ReadBytes() lenParams := br.ReadVarUint() @@ -56,7 +56,7 @@ func (tx *PublishTX) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (tx *PublishTX) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) 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 96e5e1c6c..41ed9ca75 100644 --- a/pkg/core/transaction/register.go +++ b/pkg/core/transaction/register.go @@ -31,7 +31,7 @@ type RegisterTX struct { // DecodeBinary implements the Payload interface. func (tx *RegisterTX) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&tx.AssetType) tx.Name = br.ReadString() @@ -53,7 +53,7 @@ func (tx *RegisterTX) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (tx *RegisterTX) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteLE(tx.AssetType) bw.WriteString(tx.Name) bw.WriteLE(tx.Amount) diff --git a/pkg/core/transaction/state.go b/pkg/core/transaction/state.go index 5ee0c4a0d..79127d14d 100644 --- a/pkg/core/transaction/state.go +++ b/pkg/core/transaction/state.go @@ -13,7 +13,7 @@ type StateTX struct { // DecodeBinary implements the Payload interface. func (tx *StateTX) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) lenDesc := br.ReadVarUint() if br.Err != nil { return br.Err @@ -30,7 +30,7 @@ func (tx *StateTX) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (tx *StateTX) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteVarUint(uint64(len(tx.Descriptors))) if bw.Err != nil { return bw.Err diff --git a/pkg/core/transaction/state_descriptor.go b/pkg/core/transaction/state_descriptor.go index 80a30ab04..2ad49c494 100644 --- a/pkg/core/transaction/state_descriptor.go +++ b/pkg/core/transaction/state_descriptor.go @@ -25,7 +25,7 @@ type StateDescriptor struct { // DecodeBinary implements the Payload interface. func (s *StateDescriptor) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&s.Type) s.Key = br.ReadBytes() @@ -37,7 +37,7 @@ func (s *StateDescriptor) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (s *StateDescriptor) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteLE(s.Type) bw.WriteBytes(s.Key) bw.WriteBytes(s.Value) diff --git a/pkg/core/transaction/transaction.go b/pkg/core/transaction/transaction.go index 90efcc777..8dedd17c1 100644 --- a/pkg/core/transaction/transaction.go +++ b/pkg/core/transaction/transaction.go @@ -78,7 +78,7 @@ func (t *Transaction) AddInput(in *Input) { // DecodeBinary implements the payload interface. func (t *Transaction) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&t.Type) br.ReadLE(&t.Version) if br.Err != nil { @@ -173,7 +173,7 @@ func (t *Transaction) EncodeBinary(w io.Writer) error { if err := t.encodeHashableFields(w); err != nil { return err } - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteVarUint(uint64(len(t.Scripts))) if bw.Err != nil { return bw.Err @@ -189,7 +189,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.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteLE(t.Type) bw.WriteLE(t.Version) diff --git a/pkg/core/transaction/witness.go b/pkg/core/transaction/witness.go index 125fede63..d3a07e44d 100644 --- a/pkg/core/transaction/witness.go +++ b/pkg/core/transaction/witness.go @@ -17,7 +17,7 @@ type Witness struct { // DecodeBinary implements the payload interface. func (w *Witness) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) w.InvocationScript = br.ReadBytes() w.VerificationScript = br.ReadBytes() @@ -26,7 +26,7 @@ func (w *Witness) DecodeBinary(r io.Reader) error { // EncodeBinary implements the payload interface. func (w *Witness) EncodeBinary(writer io.Writer) error { - bw := util.BinWriter{W: writer} + bw := util.NewBinWriterFromIO(writer) 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 e8972934f..1954a750c 100644 --- a/pkg/core/unspent_coin_state.go +++ b/pkg/core/unspent_coin_state.go @@ -67,7 +67,7 @@ func (u UnspentCoins) commit(b storage.Batch) error { // EncodeBinary encodes UnspentCoinState to the given io.Writer. func (s *UnspentCoinState) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteVarUint(uint64(len(s.states))) for _, state := range s.states { bw.WriteLE(byte(state)) @@ -77,7 +77,7 @@ func (s *UnspentCoinState) EncodeBinary(w io.Writer) error { // DecodeBinary decodes UnspentCoinState from the given io.Reader. func (s *UnspentCoinState) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) lenStates := br.ReadVarUint() s.states = make([]CoinState, lenStates) for i := 0; i < int(lenStates); i++ { diff --git a/pkg/network/message.go b/pkg/network/message.go index 34bf4b137..01b1a0947 100644 --- a/pkg/network/message.go +++ b/pkg/network/message.go @@ -148,7 +148,7 @@ func (m *Message) CommandType() CommandType { // Decode a Message from the given reader. func (m *Message) Decode(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&m.Magic) br.ReadLE(&m.Command) br.ReadLE(&m.Length) @@ -232,7 +232,7 @@ func (m *Message) decodePayload(r io.Reader) error { // Encode a Message to any given io.Writer. func (m *Message) Encode(w io.Writer) error { - br := util.BinWriter{W: w} + br := util.NewBinWriterFromIO(w) br.WriteLE(m.Magic) br.WriteLE(m.Command) br.WriteLE(m.Length) diff --git a/pkg/network/payload/address.go b/pkg/network/payload/address.go index a83498a7d..d0b1765cd 100644 --- a/pkg/network/payload/address.go +++ b/pkg/network/payload/address.go @@ -30,7 +30,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.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&p.Timestamp) br.ReadLE(&p.Services) br.ReadBE(&p.IP) @@ -40,7 +40,7 @@ func (p *AddressAndTime) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (p *AddressAndTime) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteLE(p.Timestamp) bw.WriteLE(p.Services) bw.WriteBE(p.IP) @@ -72,7 +72,7 @@ func NewAddressList(n int) *AddressList { // DecodeBinary implements the Payload interface. func (p *AddressList) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) listLen := br.ReadVarUint() if br.Err != nil { return br.Err @@ -90,7 +90,7 @@ func (p *AddressList) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (p *AddressList) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteVarUint(uint64(len(p.Addrs))) if bw.Err != nil { return bw.Err diff --git a/pkg/network/payload/getblocks.go b/pkg/network/payload/getblocks.go index 0e0a3419e..1246a9348 100644 --- a/pkg/network/payload/getblocks.go +++ b/pkg/network/payload/getblocks.go @@ -24,7 +24,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.BinReader{R: r} + br := util.NewBinReaderFromIO(r) lenStart := br.ReadVarUint() p.HashStart = make([]util.Uint256, lenStart) @@ -35,7 +35,7 @@ func (p *GetBlocks) DecodeBinary(r io.Reader) error { // EncodeBinary implements the payload interface. func (p *GetBlocks) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteVarUint(uint64(len(p.HashStart))) bw.WriteLE(p.HashStart) bw.WriteLE(p.HashStop) diff --git a/pkg/network/payload/headers.go b/pkg/network/payload/headers.go index b0f45de9b..1e3904d1b 100644 --- a/pkg/network/payload/headers.go +++ b/pkg/network/payload/headers.go @@ -20,7 +20,7 @@ const ( // DecodeBinary implements the Payload interface. func (p *Headers) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) lenHeaders := br.ReadVarUint() if br.Err != nil { return br.Err @@ -46,7 +46,7 @@ func (p *Headers) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (p *Headers) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteVarUint(uint64(len(p.Hdrs))) if bw.Err != nil { return bw.Err diff --git a/pkg/network/payload/inventory.go b/pkg/network/payload/inventory.go index 012a9cf82..cdfd783fe 100644 --- a/pkg/network/payload/inventory.go +++ b/pkg/network/payload/inventory.go @@ -57,7 +57,7 @@ func NewInventory(typ InventoryType, hashes []util.Uint256) *Inventory { // DecodeBinary implements the Payload interface. func (p *Inventory) DecodeBinary(r io.Reader) error { - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&p.Type) listLen := br.ReadVarUint() @@ -71,7 +71,7 @@ func (p *Inventory) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (p *Inventory) EncodeBinary(w io.Writer) error { - bw := util.BinWriter{W: w} + bw := util.NewBinWriterFromIO(w) bw.WriteLE(p.Type) listLen := len(p.Hashes) diff --git a/pkg/network/payload/merkleblock.go b/pkg/network/payload/merkleblock.go index 3b1e90eae..2396bec85 100644 --- a/pkg/network/payload/merkleblock.go +++ b/pkg/network/payload/merkleblock.go @@ -21,7 +21,7 @@ func (m *MerkleBlock) DecodeBinary(r io.Reader) error { if err := m.BlockBase.DecodeBinary(r); err != nil { return err } - br := util.BinReader{R: r} + br := util.NewBinReaderFromIO(r) m.TxCount = int(br.ReadVarUint()) n := br.ReadVarUint() diff --git a/pkg/network/payload/version.go b/pkg/network/payload/version.go index 8f050d9f7..3402ed1cd 100644 --- a/pkg/network/payload/version.go +++ b/pkg/network/payload/version.go @@ -56,7 +56,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.BinReader{R: r} + br := util.NewBinReaderFromIO(r) br.ReadLE(&p.Version) br.ReadLE(&p.Services) br.ReadLE(&p.Timestamp) @@ -70,7 +70,7 @@ func (p *Version) DecodeBinary(r io.Reader) error { // EncodeBinary implements the Payload interface. func (p *Version) EncodeBinary(w io.Writer) error { - br := util.BinWriter{W: w} + br := util.NewBinWriterFromIO(w) br.WriteLE(p.Version) br.WriteLE(p.Services) br.WriteLE(p.Timestamp) diff --git a/pkg/smartcontract/contract_test.go b/pkg/smartcontract/contract_test.go index 37c76d575..d42e41811 100644 --- a/pkg/smartcontract/contract_test.go +++ b/pkg/smartcontract/contract_test.go @@ -1,7 +1,6 @@ package smartcontract import ( - "bytes" "testing" "github.com/CityOfZion/neo-go/pkg/crypto/keys" @@ -22,8 +21,7 @@ func TestCreateMultiSigRedeemScript(t *testing.T) { t.Fatal(err) } - buf := bytes.NewBuffer(out) - br := util.BinReader{R: buf} + br := util.NewBinReaderFromBuf(out) var b uint8 br.ReadLE(&b) assert.Equal(t, vm.PUSH3, vm.Instruction(b)) diff --git a/pkg/util/binaryBufWriter.go b/pkg/util/binaryBufWriter.go new file mode 100644 index 000000000..0a2ba4cfc --- /dev/null +++ b/pkg/util/binaryBufWriter.go @@ -0,0 +1,29 @@ +package util + +import ( + "bytes" + "errors" +) + +// BufBinWriter is an additional layer on top of BinWriter that +// automatically creates buffer to write into that you can get after all +// writes via Bytes(). +type BufBinWriter struct { + *BinWriter + buf *bytes.Buffer +} + +// NewBufBinWriter makes a BufBinWriter with an empty byte buffer. +func NewBufBinWriter() *BufBinWriter { + b := new(bytes.Buffer) + return &BufBinWriter{BinWriter: NewBinWriterFromIO(b), buf: b} +} + +// Bytes returns resulting buffer and makes future writes return an error. +func (bw *BufBinWriter) Bytes() []byte { + if bw.Err != nil { + return nil + } + bw.Err = errors.New("buffer already drained") + return bw.buf.Bytes() +} diff --git a/pkg/util/binaryReader.go b/pkg/util/binaryReader.go index fe92ae61a..47694891a 100644 --- a/pkg/util/binaryReader.go +++ b/pkg/util/binaryReader.go @@ -1,6 +1,7 @@ package util import ( + "bytes" "encoding/binary" "io" ) @@ -8,17 +9,28 @@ import ( //BinReader is a convenient wrapper around a io.Reader and err object // Used to simplify error handling when reading into a struct with many fields type BinReader struct { - R io.Reader + r io.Reader Err error } +// NewBinReaderFromIO makes a BinReader from io.Reader. +func NewBinReaderFromIO(ior io.Reader) *BinReader { + return &BinReader{r: ior} +} + +// NewBinReaderFromBuf makes a BinReader from byte buffer. +func NewBinReaderFromBuf(b []byte) *BinReader { + r := bytes.NewReader(b) + return NewBinReaderFromIO(r) +} + // ReadLE reads from the underlying io.Reader // into the interface v in little-endian format func (r *BinReader) ReadLE(v interface{}) { if r.Err != nil { return } - r.Err = binary.Read(r.R, binary.LittleEndian, v) + r.Err = binary.Read(r.r, binary.LittleEndian, v) } // ReadBE reads from the underlying io.Reader @@ -27,7 +39,7 @@ func (r *BinReader) ReadBE(v interface{}) { if r.Err != nil { return } - r.Err = binary.Read(r.R, binary.BigEndian, v) + r.Err = binary.Read(r.r, binary.BigEndian, v) } // ReadVarUint reads a variable-length-encoded integer from the @@ -38,21 +50,21 @@ func (r *BinReader) ReadVarUint() uint64 { } var b uint8 - r.Err = binary.Read(r.R, binary.LittleEndian, &b) + r.Err = binary.Read(r.r, binary.LittleEndian, &b) if b == 0xfd { var v uint16 - r.Err = binary.Read(r.R, binary.LittleEndian, &v) + r.Err = binary.Read(r.r, binary.LittleEndian, &v) return uint64(v) } if b == 0xfe { var v uint32 - r.Err = binary.Read(r.R, binary.LittleEndian, &v) + r.Err = binary.Read(r.r, binary.LittleEndian, &v) return uint64(v) } if b == 0xff { var v uint64 - r.Err = binary.Read(r.R, binary.LittleEndian, &v) + r.Err = binary.Read(r.r, binary.LittleEndian, &v) return v } diff --git a/pkg/util/binaryWriter.go b/pkg/util/binaryWriter.go index 8f2c5229d..b4e58fc36 100644 --- a/pkg/util/binaryWriter.go +++ b/pkg/util/binaryWriter.go @@ -10,16 +10,21 @@ import ( // Used to simplify error handling when writing into a io.Writer // from a struct with many fields type BinWriter struct { - W io.Writer + w io.Writer Err error } +// NewBinWriterFromIO makes a BinWriter from io.Writer. +func NewBinWriterFromIO(iow io.Writer) *BinWriter { + return &BinWriter{w: iow} +} + // WriteLE writes into the underlying io.Writer from an object v in little-endian format func (w *BinWriter) WriteLE(v interface{}) { if w.Err != nil { return } - w.Err = binary.Write(w.W, binary.LittleEndian, v) + w.Err = binary.Write(w.w, binary.LittleEndian, v) } // WriteBE writes into the underlying io.Writer from an object v in big-endian format @@ -27,7 +32,7 @@ func (w *BinWriter) WriteBE(v interface{}) { if w.Err != nil { return } - w.Err = binary.Write(w.W, binary.BigEndian, v) + w.Err = binary.Write(w.w, binary.BigEndian, v) } // WriteVarUint writes a uint64 into the underlying writer using variable-length encoding @@ -46,23 +51,23 @@ func (w *BinWriter) WriteVarUint(val uint64) { } if val < 0xfd { - w.Err = binary.Write(w.W, binary.LittleEndian, uint8(val)) + w.Err = binary.Write(w.w, binary.LittleEndian, uint8(val)) return } if val < 0xFFFF { - w.Err = binary.Write(w.W, binary.LittleEndian, byte(0xfd)) - w.Err = binary.Write(w.W, binary.LittleEndian, uint16(val)) + w.Err = binary.Write(w.w, binary.LittleEndian, byte(0xfd)) + w.Err = binary.Write(w.w, binary.LittleEndian, uint16(val)) return } if val < 0xFFFFFFFF { - w.Err = binary.Write(w.W, binary.LittleEndian, byte(0xfe)) - w.Err = binary.Write(w.W, binary.LittleEndian, uint32(val)) + w.Err = binary.Write(w.w, binary.LittleEndian, byte(0xfe)) + w.Err = binary.Write(w.w, binary.LittleEndian, uint32(val)) return } - w.Err = binary.Write(w.W, binary.LittleEndian, byte(0xff)) - w.Err = binary.Write(w.W, binary.LittleEndian, val) + w.Err = binary.Write(w.w, binary.LittleEndian, byte(0xff)) + w.Err = binary.Write(w.w, binary.LittleEndian, val) } diff --git a/pkg/util/binaryrw_test.go b/pkg/util/binaryrw_test.go index 7bf320f20..34931afd2 100644 --- a/pkg/util/binaryrw_test.go +++ b/pkg/util/binaryrw_test.go @@ -1,7 +1,6 @@ package util import ( - "bytes" "testing" "github.com/stretchr/testify/assert" @@ -10,25 +9,25 @@ import ( func TestWriteVarUint1(t *testing.T) { var ( val = uint64(1) - buf = new(bytes.Buffer) ) - bw := BinWriter{W: buf} + bw := NewBufBinWriter() bw.WriteVarUint(val) assert.Nil(t, bw.Err) - assert.Equal(t, 1, buf.Len()) + buf := bw.Bytes() + assert.Equal(t, 1, len(buf)) } func TestWriteVarUint1000(t *testing.T) { var ( val = uint64(1000) - buf = new(bytes.Buffer) ) - bw := BinWriter{W: buf} + bw := NewBufBinWriter() bw.WriteVarUint(val) assert.Nil(t, bw.Err) - assert.Equal(t, 3, buf.Len()) - assert.Equal(t, byte(0xfd), buf.Bytes()[0]) - br := BinReader{R: buf} + buf := bw.Bytes() + assert.Equal(t, 3, len(buf)) + assert.Equal(t, byte(0xfd), buf[0]) + br := NewBinReaderFromBuf(buf) res := br.ReadVarUint() assert.Nil(t, br.Err) assert.Equal(t, val, res) @@ -37,14 +36,14 @@ func TestWriteVarUint1000(t *testing.T) { func TestWriteVarUint100000(t *testing.T) { var ( val = uint64(100000) - buf = new(bytes.Buffer) ) - bw := BinWriter{W: buf} + bw := NewBufBinWriter() bw.WriteVarUint(val) assert.Nil(t, bw.Err) - assert.Equal(t, 5, buf.Len()) - assert.Equal(t, byte(0xfe), buf.Bytes()[0]) - br := BinReader{R: buf} + buf := bw.Bytes() + assert.Equal(t, 5, len(buf)) + assert.Equal(t, byte(0xfe), buf[0]) + br := NewBinReaderFromBuf(buf) res := br.ReadVarUint() assert.Nil(t, br.Err) assert.Equal(t, val, res) @@ -53,14 +52,14 @@ func TestWriteVarUint100000(t *testing.T) { func TestWriteVarUint100000000000(t *testing.T) { var ( val = uint64(1000000000000) - buf = new(bytes.Buffer) ) - bw := BinWriter{W: buf} + bw := NewBufBinWriter() bw.WriteVarUint(val) assert.Nil(t, bw.Err) - assert.Equal(t, 9, buf.Len()) - assert.Equal(t, byte(0xff), buf.Bytes()[0]) - br := BinReader{R: buf} + buf := bw.Bytes() + assert.Equal(t, 9, len(buf)) + assert.Equal(t, byte(0xff), buf[0]) + br := NewBinReaderFromBuf(buf) res := br.ReadVarUint() assert.Nil(t, br.Err) assert.Equal(t, val, res) From 72fc8801822c58f45c3203fa9efe80325aa7062a Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Sun, 15 Sep 2019 15:48:20 +0300 Subject: [PATCH 02/12] util: remove bogus check from BinWriter.WriteVarUint() val is uint64, it can't be less than zero by definition. --- pkg/util/binaryWriter.go | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/pkg/util/binaryWriter.go b/pkg/util/binaryWriter.go index b4e58fc36..a867c94eb 100644 --- a/pkg/util/binaryWriter.go +++ b/pkg/util/binaryWriter.go @@ -2,7 +2,6 @@ package util import ( "encoding/binary" - "errors" "io" ) @@ -41,15 +40,6 @@ func (w *BinWriter) WriteVarUint(val uint64) { return } - if val < 0 { - w.Err = errors.New("value out of range") - return - } - - if w.Err != nil { - return - } - if val < 0xfd { w.Err = binary.Write(w.w, binary.LittleEndian, uint8(val)) return From 031a260cb1c959429a2d3cdd255e0a3eaf872439 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Sun, 15 Sep 2019 15:54:53 +0300 Subject: [PATCH 03/12] util: add tests for BinaryReader/BinaryWriter 100% coverage. --- pkg/util/binaryrw_test.go | 115 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/pkg/util/binaryrw_test.go b/pkg/util/binaryrw_test.go index 34931afd2..466504057 100644 --- a/pkg/util/binaryrw_test.go +++ b/pkg/util/binaryrw_test.go @@ -1,11 +1,122 @@ package util import ( + "errors" "testing" "github.com/stretchr/testify/assert" ) +// mocks io.Reader and io.Writer, always fails to Write() or Read(). +type badRW struct{} + +func (w *badRW) Write(p []byte) (int, error) { + return 0, errors.New("it always fails") +} + +func (w *badRW) Read(p []byte) (int, error) { + return w.Write(p) +} + +func TestWriteLE(t *testing.T) { + var ( + val uint32 = 0xdeadbeef + readval uint32 + bin []byte = []byte{0xef, 0xbe, 0xad, 0xde} + ) + bw := NewBufBinWriter() + bw.WriteLE(val) + assert.Nil(t, bw.Err) + wrotebin := bw.Bytes() + assert.Equal(t, wrotebin, bin) + br := NewBinReaderFromBuf(bin) + br.ReadLE(&readval) + assert.Nil(t, br.Err) + assert.Equal(t, val, readval) +} + +func TestWriteBE(t *testing.T) { + var ( + val uint32 = 0xdeadbeef + readval uint32 + bin []byte = []byte{0xde, 0xad, 0xbe, 0xef} + ) + bw := NewBufBinWriter() + bw.WriteBE(val) + assert.Nil(t, bw.Err) + wrotebin := bw.Bytes() + assert.Equal(t, wrotebin, bin) + br := NewBinReaderFromBuf(bin) + br.ReadBE(&readval) + assert.Nil(t, br.Err) + assert.Equal(t, val, readval) +} + +func TestWriterErrHandling(t *testing.T) { + var badio = &badRW{} + bw := NewBinWriterFromIO(badio) + bw.WriteLE(uint32(0)) + assert.NotNil(t, bw.Err) + // these should work (without panic), preserving the Err + bw.WriteLE(uint32(0)) + bw.WriteBE(uint32(0)) + bw.WriteVarUint(0) + bw.WriteBytes([]byte{0x55, 0xaa}) + bw.WriteString("neo") + assert.NotNil(t, bw.Err) +} + +func TestReaderErrHandling(t *testing.T) { + var ( + i uint32 = 0xdeadbeef + iorig = i + badio = &badRW{} + ) + br := NewBinReaderFromIO(badio) + br.ReadLE(&i) + assert.NotNil(t, br.Err) + // i shouldn't change + assert.Equal(t, i, iorig) + // these should work (without panic), preserving the Err + br.ReadLE(&i) + br.ReadBE(&i) + assert.Equal(t, i, iorig) + val := br.ReadVarUint() + assert.Equal(t, val, uint64(0)) + b := br.ReadBytes() + assert.Equal(t, b, []byte{}) + s := br.ReadString() + assert.Equal(t, s, "") + assert.NotNil(t, br.Err) +} + +func TestBufBinWriterErr(t *testing.T) { + bw := NewBufBinWriter() + bw.WriteLE(uint32(0)) + assert.Nil(t, bw.Err) + // inject error + bw.Err = errors.New("oopsie") + res := bw.Bytes() + assert.NotNil(t, bw.Err) + assert.Nil(t, res) +} + +func TestWriteString(t *testing.T) { + var ( + str string = "teststring" + ) + bw := NewBufBinWriter() + bw.WriteString(str) + assert.Nil(t, bw.Err) + wrotebin := bw.Bytes() + // +1 byte for length + assert.Equal(t, len(wrotebin), len(str)+1) + br := NewBinReaderFromBuf(wrotebin) + readstr := br.ReadString() + assert.Nil(t, br.Err) + assert.Equal(t, str, readstr) +} + func TestWriteVarUint1(t *testing.T) { var ( val = uint64(1) @@ -15,6 +126,10 @@ func TestWriteVarUint1(t *testing.T) { assert.Nil(t, bw.Err) buf := bw.Bytes() assert.Equal(t, 1, len(buf)) + br := NewBinReaderFromBuf(buf) + res := br.ReadVarUint() + assert.Nil(t, br.Err) + assert.Equal(t, val, res) } func TestWriteVarUint1000(t *testing.T) { From f01354b5bd70e5d9c3d2d80f72790f0ddd076740 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 Sep 2019 12:07:06 +0300 Subject: [PATCH 04/12] core: make TestHeaderEncodeDecode use assert for field comparisons --- pkg/core/header_test.go | 33 +++++++++------------------------ 1 file changed, 9 insertions(+), 24 deletions(-) diff --git a/pkg/core/header_test.go b/pkg/core/header_test.go index ef7dcbec0..dcd83d7c0 100644 --- a/pkg/core/header_test.go +++ b/pkg/core/header_test.go @@ -8,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/util" + "github.com/stretchr/testify/assert" ) func TestHeaderEncodeDecode(t *testing.T) { @@ -34,28 +35,12 @@ func TestHeaderEncodeDecode(t *testing.T) { if err := headerDecode.DecodeBinary(buf); err != nil { t.Fatal(err) } - if header.Version != headerDecode.Version { - t.Fatal("expected both versions to be equal") - } - if !header.PrevHash.Equals(headerDecode.PrevHash) { - t.Fatal("expected both prev hashes to be equal") - } - if !header.MerkleRoot.Equals(headerDecode.MerkleRoot) { - t.Fatal("expected both merkle roots to be equal") - } - if header.Index != headerDecode.Index { - t.Fatal("expected both indexes to be equal") - } - if header.ConsensusData != headerDecode.ConsensusData { - t.Fatal("expected both consensus data fields to be equal") - } - if !header.NextConsensus.Equals(headerDecode.NextConsensus) { - t.Fatalf("expected both next consensus fields to be equal") - } - if !bytes.Equal(header.Script.InvocationScript, headerDecode.Script.InvocationScript) { - t.Fatalf("expected equal invocation scripts %v and %v", header.Script.InvocationScript, headerDecode.Script.InvocationScript) - } - if !bytes.Equal(header.Script.VerificationScript, headerDecode.Script.VerificationScript) { - t.Fatalf("expected equal verification scripts %v and %v", header.Script.VerificationScript, headerDecode.Script.VerificationScript) - } + assert.Equal(t, header.Version, headerDecode.Version, "expected both versions to be equal") + assert.Equal(t, header.PrevHash, headerDecode.PrevHash, "expected both prev hashes to be equal") + assert.Equal(t, header.MerkleRoot, headerDecode.MerkleRoot, "expected both merkle roots to be equal") + assert.Equal(t, header.Index, headerDecode.Index, "expected both indexes to be equal") + assert.Equal(t, header.ConsensusData, headerDecode.ConsensusData, "expected both consensus data fields to be equal") + assert.Equal(t, header.NextConsensus, headerDecode.NextConsensus, "expected both next consensus fields to be equal") + assert.Equal(t, header.Script.InvocationScript, headerDecode.Script.InvocationScript, "expected equal invocation scripts") + assert.Equal(t, header.Script.VerificationScript, headerDecode.Script.VerificationScript, "expected equal verification scripts") } From 5bf00db2c9c8505fe3a84c8852babe6471d82584 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 Sep 2019 12:18:13 +0300 Subject: [PATCH 05/12] 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 } From 0da9fe69461d46e6591cad3c142f33221ca0477f Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 Sep 2019 12:33:53 +0300 Subject: [PATCH 06/12] io: move size calculator there It's mostly used for Serializable and in other cases where one needs to estimate binary-encoded size of the stucture. This also simplifies future removal of the Size() from Serializable. --- pkg/core/blockchain_test.go | 10 +++++----- pkg/core/transaction/attribute.go | 3 +-- pkg/core/transaction/claim.go | 3 +-- pkg/core/transaction/invocation.go | 2 +- pkg/core/transaction/publish.go | 9 ++++----- pkg/core/transaction/register.go | 2 +- pkg/core/transaction/state.go | 3 +-- pkg/core/transaction/state_descriptor.go | 3 +-- pkg/core/transaction/transaction.go | 8 ++++---- pkg/core/transaction/witness.go | 2 +- pkg/{util => io}/size.go | 8 +++----- pkg/{util => io}/size_test.go | 12 ++++++------ pkg/network/payload/version.go | 3 +-- 13 files changed, 30 insertions(+), 38 deletions(-) rename pkg/{util => io}/size.go (94%) rename pkg/{util => io}/size_test.go (91%) diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index 9a1c38562..a2fcc188e 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -6,7 +6,7 @@ import ( "github.com/CityOfZion/neo-go/config" "github.com/CityOfZion/neo-go/pkg/core/storage" - "github.com/CityOfZion/neo-go/pkg/util" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -142,10 +142,10 @@ func TestGetTransaction(t *testing.T) { assert.Equal(t, block.Index, height) assert.Equal(t, block.Transactions[0], tx) assert.Equal(t, 10, tx.Size()) - assert.Equal(t, 1, util.GetVarSize(tx.Attributes)) - assert.Equal(t, 1, util.GetVarSize(tx.Inputs)) - assert.Equal(t, 1, util.GetVarSize(tx.Outputs)) - assert.Equal(t, 1, util.GetVarSize(tx.Scripts)) + assert.Equal(t, 1, io.GetVarSize(tx.Attributes)) + assert.Equal(t, 1, io.GetVarSize(tx.Inputs)) + assert.Equal(t, 1, io.GetVarSize(tx.Outputs)) + assert.Equal(t, 1, io.GetVarSize(tx.Scripts)) } func newTestChain(t *testing.T) *Blockchain { diff --git a/pkg/core/transaction/attribute.go b/pkg/core/transaction/attribute.go index b4e07aee4..3c60d3d5f 100644 --- a/pkg/core/transaction/attribute.go +++ b/pkg/core/transaction/attribute.go @@ -6,7 +6,6 @@ import ( "fmt" "github.com/CityOfZion/neo-go/pkg/io" - "github.com/CityOfZion/neo-go/pkg/util" ) // Attribute represents a Transaction attribute. @@ -87,7 +86,7 @@ func (attr *Attribute) Size() int { case DescriptionURL: sz += 1 + len(attr.Data) default: - sz += util.GetVarSize(attr.Data) + sz += io.GetVarSize(attr.Data) } return sz } diff --git a/pkg/core/transaction/claim.go b/pkg/core/transaction/claim.go index bb864548c..6c1a69eda 100644 --- a/pkg/core/transaction/claim.go +++ b/pkg/core/transaction/claim.go @@ -2,7 +2,6 @@ package transaction import ( "github.com/CityOfZion/neo-go/pkg/io" - "github.com/CityOfZion/neo-go/pkg/util" ) // ClaimTX represents a claim transaction. @@ -42,7 +41,7 @@ func (tx *ClaimTX) EncodeBinary(bw *io.BinWriter) error { // Size returns serialized binary size for this transaction. func (tx *ClaimTX) Size() int { - sz := util.GetVarSize(uint64(len(tx.Claims))) + sz := io.GetVarSize(uint64(len(tx.Claims))) for _, claim := range tx.Claims { sz += claim.Size() } diff --git a/pkg/core/transaction/invocation.go b/pkg/core/transaction/invocation.go index 52a105bcb..bfdf3df66 100644 --- a/pkg/core/transaction/invocation.go +++ b/pkg/core/transaction/invocation.go @@ -53,7 +53,7 @@ func (tx *InvocationTX) EncodeBinary(bw *io.BinWriter) error { // Size returns serialized binary size for this transaction. func (tx *InvocationTX) Size() int { - sz := util.GetVarSize(tx.Script) + sz := io.GetVarSize(tx.Script) if tx.Version >= 1 { sz += tx.Gas.Size() } diff --git a/pkg/core/transaction/publish.go b/pkg/core/transaction/publish.go index c5149bc97..fbf3d11d6 100644 --- a/pkg/core/transaction/publish.go +++ b/pkg/core/transaction/publish.go @@ -3,7 +3,6 @@ package transaction import ( "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/smartcontract" - "github.com/CityOfZion/neo-go/pkg/util" ) // PublishTX represents a publish transaction. @@ -73,14 +72,14 @@ func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) error { // Size returns serialized binary size for this transaction. func (tx *PublishTX) Size() int { - sz := util.GetVarSize(tx.Script) + util.GetVarSize(uint64(len(tx.ParamList))) + sz := io.GetVarSize(tx.Script) + io.GetVarSize(uint64(len(tx.ParamList))) sz += 1 * len(tx.ParamList) sz++ if tx.Version >= 1 { sz++ } - sz += util.GetVarSize(tx.Name) + util.GetVarSize(tx.CodeVersion) - sz += util.GetVarSize(tx.Author) + util.GetVarSize(tx.Email) - sz += util.GetVarSize(tx.Description) + sz += io.GetVarSize(tx.Name) + io.GetVarSize(tx.CodeVersion) + sz += io.GetVarSize(tx.Author) + io.GetVarSize(tx.Email) + sz += io.GetVarSize(tx.Description) return sz } diff --git a/pkg/core/transaction/register.go b/pkg/core/transaction/register.go index 711cb7465..1d45aa23e 100644 --- a/pkg/core/transaction/register.go +++ b/pkg/core/transaction/register.go @@ -62,5 +62,5 @@ func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) error { // Size returns serialized binary size for this transaction. func (tx *RegisterTX) Size() int { - return 1 + util.GetVarSize(tx.Name) + tx.Amount.Size() + 1 + len(tx.Owner.Bytes()) + tx.Admin.Size() + return 1 + io.GetVarSize(tx.Name) + tx.Amount.Size() + 1 + len(tx.Owner.Bytes()) + tx.Admin.Size() } diff --git a/pkg/core/transaction/state.go b/pkg/core/transaction/state.go index 490c8f6a2..be52ef734 100644 --- a/pkg/core/transaction/state.go +++ b/pkg/core/transaction/state.go @@ -2,7 +2,6 @@ package transaction import ( "github.com/CityOfZion/neo-go/pkg/io" - "github.com/CityOfZion/neo-go/pkg/util" ) // StateTX represents a state transaction. @@ -38,7 +37,7 @@ func (tx *StateTX) EncodeBinary(w *io.BinWriter) error { // Size returns serialized binary size for this transaction. func (tx *StateTX) Size() int { - sz := util.GetVarSize(uint64(len(tx.Descriptors))) + sz := io.GetVarSize(uint64(len(tx.Descriptors))) for _, desc := range tx.Descriptors { sz += desc.Size() } diff --git a/pkg/core/transaction/state_descriptor.go b/pkg/core/transaction/state_descriptor.go index c7e82822e..4c794fceb 100644 --- a/pkg/core/transaction/state_descriptor.go +++ b/pkg/core/transaction/state_descriptor.go @@ -2,7 +2,6 @@ package transaction import ( "github.com/CityOfZion/neo-go/pkg/io" - "github.com/CityOfZion/neo-go/pkg/util" ) // DescStateType represents the type of StateDescriptor. @@ -44,5 +43,5 @@ func (s *StateDescriptor) EncodeBinary(w *io.BinWriter) error { // Size returns serialized binary size for state descriptor. func (s *StateDescriptor) Size() int { - return 1 + util.GetVarSize(s.Key) + util.GetVarSize(s.Value) + util.GetVarSize(s.Field) + return 1 + io.GetVarSize(s.Key) + io.GetVarSize(s.Value) + io.GetVarSize(s.Field) } diff --git a/pkg/core/transaction/transaction.go b/pkg/core/transaction/transaction.go index 3bf651317..cd9e3c352 100644 --- a/pkg/core/transaction/transaction.go +++ b/pkg/core/transaction/transaction.go @@ -265,10 +265,10 @@ func (t Transaction) GroupOutputByAssetID() map[util.Uint256][]*Output { // Size returns the size of the transaction in term of bytes func (t *Transaction) Size() int { - attrSize := util.GetVarSize(t.Attributes) - inputSize := util.GetVarSize(t.Inputs) - outputSize := util.GetVarSize(t.Outputs) - witnesSize := util.GetVarSize(t.Scripts) + attrSize := io.GetVarSize(t.Attributes) + inputSize := io.GetVarSize(t.Inputs) + outputSize := io.GetVarSize(t.Outputs) + witnesSize := io.GetVarSize(t.Scripts) // uint8 + uint8 + attrSize + inputSize + outputSize + witnesSize return 2 + attrSize + inputSize + outputSize + witnesSize + t.Data.Size() } diff --git a/pkg/core/transaction/witness.go b/pkg/core/transaction/witness.go index 20c1d8d91..d4da3836a 100644 --- a/pkg/core/transaction/witness.go +++ b/pkg/core/transaction/witness.go @@ -42,7 +42,7 @@ func (w *Witness) MarshalJSON() ([]byte, error) { // Size returns the size in bytes of the Witness. func (w *Witness) Size() int { - return util.GetVarSize(w.InvocationScript) + util.GetVarSize(w.VerificationScript) + return io.GetVarSize(w.InvocationScript) + io.GetVarSize(w.VerificationScript) } // ScriptHash returns the hash of the VerificationScript. diff --git a/pkg/util/size.go b/pkg/io/size.go similarity index 94% rename from pkg/util/size.go rename to pkg/io/size.go index 33b7b60fc..bde30be19 100644 --- a/pkg/util/size.go +++ b/pkg/io/size.go @@ -1,10 +1,8 @@ -package util +package io import ( "fmt" "reflect" - - "github.com/CityOfZion/neo-go/pkg/io" ) var ( @@ -67,9 +65,9 @@ func GetVarSize(value interface{}) int { if valueLength != 0 { switch reflect.ValueOf(value).Index(0).Interface().(type) { - case io.Serializable: + case Serializable: for i := 0; i < valueLength; i++ { - elem := v.Index(i).Interface().(io.Serializable) + elem := v.Index(i).Interface().(Serializable) valueSize += elem.Size() } case uint8, int8: diff --git a/pkg/util/size_test.go b/pkg/io/size_test.go similarity index 91% rename from pkg/util/size_test.go rename to pkg/io/size_test.go index d77ceaebc..e3028accd 100644 --- a/pkg/util/size_test.go +++ b/pkg/io/size_test.go @@ -1,10 +1,10 @@ -package util +package io import ( "fmt" "testing" - "github.com/CityOfZion/neo-go/pkg/io" + "github.com/CityOfZion/neo-go/pkg/util" "github.com/stretchr/testify/assert" ) @@ -12,11 +12,11 @@ import ( type smthSerializable struct { } -func (*smthSerializable) DecodeBinary(*io.BinReader) error { +func (*smthSerializable) DecodeBinary(*BinReader) error { return nil } -func (*smthSerializable) EncodeBinary(*io.BinWriter) error { +func (*smthSerializable) EncodeBinary(*BinWriter) error { return nil } @@ -87,7 +87,7 @@ func TestVarSize(t *testing.T) { }, { // The neo C# implementation doe not allowed this! - Uint160{1, 2, 4, 5, 6}, + util.Uint160{1, 2, 4, 5, 6}, "test_Uint160_1", 21, }, @@ -153,7 +153,7 @@ func TestVarSize(t *testing.T) { 241, }, // The neo C# implementation doe not allowed this! - {Uint256{1, 2, 3, 4, 5, 6}, + {util.Uint256{1, 2, 3, 4, 5, 6}, "test_Uint256_1", 33, }, diff --git a/pkg/network/payload/version.go b/pkg/network/payload/version.go index b9d347d45..de78b1b3b 100644 --- a/pkg/network/payload/version.go +++ b/pkg/network/payload/version.go @@ -4,7 +4,6 @@ import ( "time" "github.com/CityOfZion/neo-go/pkg/io" - "github.com/CityOfZion/neo-go/pkg/util" ) // Size of the payload not counting UserAgent encoding (which is at least 1 byte @@ -83,5 +82,5 @@ func (p *Version) EncodeBinary(br *io.BinWriter) error { // Size implements the payloader interface. func (p *Version) Size() uint32 { - return uint32(minVersionSize + util.GetVarSize(p.UserAgent)) + return uint32(minVersionSize + io.GetVarSize(p.UserAgent)) } From 56c72b5c67a8885d0f273af2dbac49311debf063 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 Sep 2019 15:58:26 +0300 Subject: [PATCH 07/12] io: redo GetVarSize for Serializable things Use writes to a fake io.Writer that counts the bytes. Allows us to kill Size() methods as useless and duplicating lots of functionality. --- pkg/io/size.go | 29 +++++++++++++++++++++++++++-- pkg/io/size_test.go | 4 +++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/pkg/io/size.go b/pkg/io/size.go index bde30be19..ca966740c 100644 --- a/pkg/io/size.go +++ b/pkg/io/size.go @@ -17,6 +17,20 @@ var ( i64 int64 ) +// This structure is used to calculate the wire size of the serializable +// structure. It's an io.Writer that doesn't do any real writes, but instead +// just counts the number of bytes to be written. +type counterWriter struct { + counter int +} + +// Write implements the io.Writer interface +func (cw *counterWriter) Write(p []byte) (int, error) { + n := len(p) + cw.counter += n + return n, nil +} + // GetVarIntSize returns the size in number of bytes of a variable integer // (reference: GetVarSize(int value), https://github.com/neo-project/neo/blob/master/neo/IO/Helper.cs) func GetVarIntSize(value int) int { @@ -59,6 +73,18 @@ func GetVarSize(value interface{}) int { reflect.Uint32, reflect.Uint64: return GetVarIntSize(int(v.Uint())) + case reflect.Ptr: + vser, ok := v.Interface().(Serializable) + if !ok { + panic(fmt.Sprintf("unable to calculate GetVarSize for a non-Serializable pointer")) + } + cw := counterWriter{} + w := NewBinWriterFromIO(&cw) + err := vser.EncodeBinary(w) + if err != nil { + panic(fmt.Sprintf("error serializing %s: %s", reflect.TypeOf(value), err.Error())) + } + return cw.counter case reflect.Slice, reflect.Array: valueLength := v.Len() valueSize := 0 @@ -67,8 +93,7 @@ func GetVarSize(value interface{}) int { switch reflect.ValueOf(value).Index(0).Interface().(type) { case Serializable: for i := 0; i < valueLength; i++ { - elem := v.Index(i).Interface().(Serializable) - valueSize += elem.Size() + valueSize += GetVarSize(v.Index(i).Interface()) } case uint8, int8: valueSize = valueLength diff --git a/pkg/io/size_test.go b/pkg/io/size_test.go index e3028accd..9a5d2de66 100644 --- a/pkg/io/size_test.go +++ b/pkg/io/size_test.go @@ -10,13 +10,15 @@ import ( // Mock structure to test getting size of an array of serializable things type smthSerializable struct { + some [42]byte } func (*smthSerializable) DecodeBinary(*BinReader) error { return nil } -func (*smthSerializable) EncodeBinary(*BinWriter) error { +func (ss *smthSerializable) EncodeBinary(bw *BinWriter) error { + bw.WriteLE(ss.some) return nil } From e299a4498382e694af2a6430b4a07e073b4cc571 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 Sep 2019 16:08:00 +0300 Subject: [PATCH 08/12] io: drop Size() method from Serializable and associated It's no longer needed after the io.GetVarSize() improvement. It's duplicating a lot of EncodeBinary() logic also. --- pkg/core/block_test.go | 2 +- pkg/core/blockchain.go | 6 +++--- pkg/core/blockchain_test.go | 2 +- pkg/core/transaction/attribute.go | 17 ----------------- pkg/core/transaction/claim.go | 9 --------- pkg/core/transaction/contract.go | 5 ----- pkg/core/transaction/enrollment.go | 5 ----- pkg/core/transaction/input.go | 5 ----- pkg/core/transaction/invocation.go | 9 --------- pkg/core/transaction/issue.go | 5 ----- pkg/core/transaction/miner.go | 5 ----- pkg/core/transaction/output.go | 5 ----- pkg/core/transaction/publish.go | 14 -------------- pkg/core/transaction/register.go | 5 ----- pkg/core/transaction/state.go | 9 --------- pkg/core/transaction/state_descriptor.go | 5 ----- pkg/core/transaction/transaction.go | 10 ---------- pkg/core/transaction/txer.go | 1 - pkg/core/transaction/witness.go | 5 ----- pkg/io/serializable.go | 1 - pkg/io/size_test.go | 4 ---- pkg/network/payload/getblocks.go | 3 --- pkg/network/payload/version.go | 5 ----- pkg/network/payload/version_test.go | 2 +- pkg/rpc/wrappers/tx_raw_output.go | 3 ++- pkg/util/fixed8.go | 5 ----- pkg/util/uint160.go | 5 ----- pkg/util/uint256.go | 5 ----- 28 files changed, 8 insertions(+), 149 deletions(-) diff --git a/pkg/core/block_test.go b/pkg/core/block_test.go index ffa159e40..546d1de47 100644 --- a/pkg/core/block_test.go +++ b/pkg/core/block_test.go @@ -225,7 +225,7 @@ func TestBlockSizeCalculation(t *testing.T) { txID := tx.Hash() assert.Equal(t, expected[i].ID, txID.ReverseString()) - assert.Equal(t, expected[i].Size, tx.Size()) + assert.Equal(t, expected[i].Size, io.GetVarSize(tx)) assert.Equal(t, expected[i].Type, tx.Type.String()) assert.Equal(t, expected[i].Version, int(tx.Version)) assert.Equal(t, expected[i].InputsLen, len(tx.Inputs)) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index a31b0b037..08e5b298a 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -628,7 +628,7 @@ func (bc *Blockchain) References(t *transaction.Transaction) map[util.Uint256]*t // FeePerByte returns network fee divided by the size of the transaction func (bc *Blockchain) FeePerByte(t *transaction.Transaction) util.Fixed8 { - return bc.NetworkFee(t).Div(int64(t.Size())) + return bc.NetworkFee(t).Div(int64(io.GetVarSize(t))) } // NetworkFee returns network fee @@ -669,8 +669,8 @@ func (bc *Blockchain) GetMemPool() MemPool { // Verify verifies whether a transaction is bonafide or not. // Golang implementation of Verify method in C# (https://github.com/neo-project/neo/blob/master/neo/Network/P2P/Payloads/Transaction.cs#L270). func (bc *Blockchain) Verify(t *transaction.Transaction) error { - if t.Size() > transaction.MaxTransactionSize { - return errors.Errorf("invalid transaction size = %d. It shoud be less then MaxTransactionSize = %d", t.Size(), transaction.MaxTransactionSize) + if io.GetVarSize(t) > transaction.MaxTransactionSize { + return errors.Errorf("invalid transaction size = %d. It shoud be less then MaxTransactionSize = %d", io.GetVarSize(t), transaction.MaxTransactionSize) } if ok := bc.verifyInputs(t); !ok { return errors.New("invalid transaction's inputs") diff --git a/pkg/core/blockchain_test.go b/pkg/core/blockchain_test.go index a2fcc188e..8f35861c2 100644 --- a/pkg/core/blockchain_test.go +++ b/pkg/core/blockchain_test.go @@ -141,7 +141,7 @@ func TestGetTransaction(t *testing.T) { } assert.Equal(t, block.Index, height) assert.Equal(t, block.Transactions[0], tx) - assert.Equal(t, 10, tx.Size()) + assert.Equal(t, 10, io.GetVarSize(tx)) assert.Equal(t, 1, io.GetVarSize(tx.Attributes)) assert.Equal(t, 1, io.GetVarSize(tx.Inputs)) assert.Equal(t, 1, io.GetVarSize(tx.Outputs)) diff --git a/pkg/core/transaction/attribute.go b/pkg/core/transaction/attribute.go index 3c60d3d5f..425dd72e6 100644 --- a/pkg/core/transaction/attribute.go +++ b/pkg/core/transaction/attribute.go @@ -74,23 +74,6 @@ func (attr *Attribute) EncodeBinary(bw *io.BinWriter) error { return bw.Err } -// Size returns the size in number bytes of the Attribute -func (attr *Attribute) Size() int { - sz := 1 // usage - switch attr.Usage { - case ContractHash, ECDH02, ECDH03, Vote, - Hash1, Hash2, Hash3, Hash4, Hash5, Hash6, Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15: - sz += 32 // uint8 + 32 = size(attrUsage) + 32 - case Script: - sz += 20 // uint8 + 20 = size(attrUsage) + 20 - case DescriptionURL: - sz += 1 + len(attr.Data) - default: - sz += io.GetVarSize(attr.Data) - } - return sz -} - // MarshalJSON implements the json Marschaller interface func (attr *Attribute) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]string{ diff --git a/pkg/core/transaction/claim.go b/pkg/core/transaction/claim.go index 6c1a69eda..61d44614c 100644 --- a/pkg/core/transaction/claim.go +++ b/pkg/core/transaction/claim.go @@ -38,12 +38,3 @@ func (tx *ClaimTX) EncodeBinary(bw *io.BinWriter) error { } return nil } - -// Size returns serialized binary size for this transaction. -func (tx *ClaimTX) Size() int { - sz := io.GetVarSize(uint64(len(tx.Claims))) - for _, claim := range tx.Claims { - sz += claim.Size() - } - return sz -} diff --git a/pkg/core/transaction/contract.go b/pkg/core/transaction/contract.go index c7d91fa12..4c445da21 100644 --- a/pkg/core/transaction/contract.go +++ b/pkg/core/transaction/contract.go @@ -24,8 +24,3 @@ func (tx *ContractTX) DecodeBinary(r *io.BinReader) error { func (tx *ContractTX) EncodeBinary(w *io.BinWriter) error { return nil } - -// Size returns serialized binary size for this transaction. -func (tx *ContractTX) Size() int { - return 0 -} diff --git a/pkg/core/transaction/enrollment.go b/pkg/core/transaction/enrollment.go index 9ef1b4f68..d01b3eedb 100644 --- a/pkg/core/transaction/enrollment.go +++ b/pkg/core/transaction/enrollment.go @@ -25,8 +25,3 @@ func (tx *EnrollmentTX) DecodeBinary(r *io.BinReader) error { func (tx *EnrollmentTX) EncodeBinary(w *io.BinWriter) error { return tx.PublicKey.EncodeBinary(w) } - -// Size returns serialized binary size for this transaction. -func (tx *EnrollmentTX) Size() int { - return len(tx.PublicKey.Bytes()) -} diff --git a/pkg/core/transaction/input.go b/pkg/core/transaction/input.go index cce3db6c3..a5a13411d 100644 --- a/pkg/core/transaction/input.go +++ b/pkg/core/transaction/input.go @@ -27,8 +27,3 @@ func (in *Input) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(in.PrevIndex) return bw.Err } - -// Size returns the size in bytes of the Input -func (in Input) Size() int { - return in.PrevHash.Size() + 2 // 2 = sizeOf uint16 -} diff --git a/pkg/core/transaction/invocation.go b/pkg/core/transaction/invocation.go index bfdf3df66..43a2409ed 100644 --- a/pkg/core/transaction/invocation.go +++ b/pkg/core/transaction/invocation.go @@ -50,12 +50,3 @@ func (tx *InvocationTX) EncodeBinary(bw *io.BinWriter) error { } return bw.Err } - -// Size returns serialized binary size for this transaction. -func (tx *InvocationTX) Size() int { - sz := io.GetVarSize(tx.Script) - if tx.Version >= 1 { - sz += tx.Gas.Size() - } - return sz -} diff --git a/pkg/core/transaction/issue.go b/pkg/core/transaction/issue.go index 7555d267b..9f412e97a 100644 --- a/pkg/core/transaction/issue.go +++ b/pkg/core/transaction/issue.go @@ -17,8 +17,3 @@ func (tx *IssueTX) DecodeBinary(r *io.BinReader) error { func (tx *IssueTX) EncodeBinary(w *io.BinWriter) error { return nil } - -// Size returns serialized binary size for this transaction. -func (tx *IssueTX) Size() int { - return 0 -} diff --git a/pkg/core/transaction/miner.go b/pkg/core/transaction/miner.go index b64fbee9b..923253926 100644 --- a/pkg/core/transaction/miner.go +++ b/pkg/core/transaction/miner.go @@ -21,8 +21,3 @@ func (tx *MinerTX) EncodeBinary(w *io.BinWriter) error { w.WriteLE(tx.Nonce) return w.Err } - -// Size returns serialized binary size for this transaction. -func (tx *MinerTX) Size() int { - return 4 // Nonce -} diff --git a/pkg/core/transaction/output.go b/pkg/core/transaction/output.go index 887bcb18f..a6aacbdca 100644 --- a/pkg/core/transaction/output.go +++ b/pkg/core/transaction/output.go @@ -49,11 +49,6 @@ func (out *Output) EncodeBinary(bw *io.BinWriter) error { return bw.Err } -// Size returns the size in bytes of the Output -func (out *Output) Size() int { - return out.AssetID.Size() + out.Amount.Size() + out.ScriptHash.Size() -} - // MarshalJSON implements the Marshaler interface func (out *Output) MarshalJSON() ([]byte, error) { return json.Marshal(map[string]interface{}{ diff --git a/pkg/core/transaction/publish.go b/pkg/core/transaction/publish.go index fbf3d11d6..6a07fdfce 100644 --- a/pkg/core/transaction/publish.go +++ b/pkg/core/transaction/publish.go @@ -69,17 +69,3 @@ func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) error { bw.WriteString(tx.Description) return bw.Err } - -// Size returns serialized binary size for this transaction. -func (tx *PublishTX) Size() int { - sz := io.GetVarSize(tx.Script) + io.GetVarSize(uint64(len(tx.ParamList))) - sz += 1 * len(tx.ParamList) - sz++ - if tx.Version >= 1 { - sz++ - } - sz += io.GetVarSize(tx.Name) + io.GetVarSize(tx.CodeVersion) - sz += io.GetVarSize(tx.Author) + io.GetVarSize(tx.Email) - sz += io.GetVarSize(tx.Description) - return sz -} diff --git a/pkg/core/transaction/register.go b/pkg/core/transaction/register.go index 1d45aa23e..c3c227165 100644 --- a/pkg/core/transaction/register.go +++ b/pkg/core/transaction/register.go @@ -59,8 +59,3 @@ func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(tx.Admin) return bw.Err } - -// Size returns serialized binary size for this transaction. -func (tx *RegisterTX) Size() int { - return 1 + io.GetVarSize(tx.Name) + tx.Amount.Size() + 1 + len(tx.Owner.Bytes()) + tx.Admin.Size() -} diff --git a/pkg/core/transaction/state.go b/pkg/core/transaction/state.go index be52ef734..8723b972d 100644 --- a/pkg/core/transaction/state.go +++ b/pkg/core/transaction/state.go @@ -34,12 +34,3 @@ func (tx *StateTX) EncodeBinary(w *io.BinWriter) error { } return w.Err } - -// Size returns serialized binary size for this transaction. -func (tx *StateTX) Size() int { - sz := io.GetVarSize(uint64(len(tx.Descriptors))) - for _, desc := range tx.Descriptors { - sz += desc.Size() - } - return sz -} diff --git a/pkg/core/transaction/state_descriptor.go b/pkg/core/transaction/state_descriptor.go index 4c794fceb..40dbbcf14 100644 --- a/pkg/core/transaction/state_descriptor.go +++ b/pkg/core/transaction/state_descriptor.go @@ -40,8 +40,3 @@ func (s *StateDescriptor) EncodeBinary(w *io.BinWriter) error { w.WriteString(s.Field) return w.Err } - -// Size returns serialized binary size for state descriptor. -func (s *StateDescriptor) Size() int { - return 1 + io.GetVarSize(s.Key) + io.GetVarSize(s.Value) + io.GetVarSize(s.Field) -} diff --git a/pkg/core/transaction/transaction.go b/pkg/core/transaction/transaction.go index cd9e3c352..628677f21 100644 --- a/pkg/core/transaction/transaction.go +++ b/pkg/core/transaction/transaction.go @@ -263,16 +263,6 @@ func (t Transaction) GroupOutputByAssetID() map[util.Uint256][]*Output { return m } -// Size returns the size of the transaction in term of bytes -func (t *Transaction) Size() int { - attrSize := io.GetVarSize(t.Attributes) - inputSize := io.GetVarSize(t.Inputs) - outputSize := io.GetVarSize(t.Outputs) - witnesSize := io.GetVarSize(t.Scripts) - // uint8 + uint8 + attrSize + inputSize + outputSize + witnesSize - return 2 + attrSize + inputSize + outputSize + witnesSize + t.Data.Size() -} - // Bytes convert the transaction to []byte func (t *Transaction) Bytes() []byte { buf := io.NewBufBinWriter() diff --git a/pkg/core/transaction/txer.go b/pkg/core/transaction/txer.go index c26c6364c..62558143b 100644 --- a/pkg/core/transaction/txer.go +++ b/pkg/core/transaction/txer.go @@ -7,5 +7,4 @@ import "github.com/CityOfZion/neo-go/pkg/io" type TXer interface { 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 d4da3836a..9256ecc16 100644 --- a/pkg/core/transaction/witness.go +++ b/pkg/core/transaction/witness.go @@ -40,11 +40,6 @@ func (w *Witness) MarshalJSON() ([]byte, error) { return json.Marshal(data) } -// Size returns the size in bytes of the Witness. -func (w *Witness) Size() int { - return io.GetVarSize(w.InvocationScript) + io.GetVarSize(w.VerificationScript) -} - // ScriptHash returns the hash of the VerificationScript. func (w Witness) ScriptHash() util.Uint160 { return hash.Hash160(w.VerificationScript) diff --git a/pkg/io/serializable.go b/pkg/io/serializable.go index 0f49c61d8..2063d2c6d 100644 --- a/pkg/io/serializable.go +++ b/pkg/io/serializable.go @@ -2,7 +2,6 @@ package io // Serializable defines the binary encoding/decoding interface. type Serializable interface { - Size() int DecodeBinary(*BinReader) error EncodeBinary(*BinWriter) error } diff --git a/pkg/io/size_test.go b/pkg/io/size_test.go index 9a5d2de66..85275fe94 100644 --- a/pkg/io/size_test.go +++ b/pkg/io/size_test.go @@ -22,10 +22,6 @@ func (ss *smthSerializable) EncodeBinary(bw *BinWriter) error { return nil } -func (*smthSerializable) Size() int { - return 42 -} - func TestVarSize(t *testing.T) { testCases := []struct { variable interface{} diff --git a/pkg/network/payload/getblocks.go b/pkg/network/payload/getblocks.go index f1e3e1fc1..3298c5b5a 100644 --- a/pkg/network/payload/getblocks.go +++ b/pkg/network/payload/getblocks.go @@ -38,6 +38,3 @@ func (p *GetBlocks) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(p.HashStop) return bw.Err } - -// Size implements the payload interface. -func (p *GetBlocks) Size() uint32 { return 0 } diff --git a/pkg/network/payload/version.go b/pkg/network/payload/version.go index de78b1b3b..2cb79fbe2 100644 --- a/pkg/network/payload/version.go +++ b/pkg/network/payload/version.go @@ -79,8 +79,3 @@ func (p *Version) EncodeBinary(br *io.BinWriter) error { br.WriteLE(&p.Relay) return br.Err } - -// Size implements the payloader interface. -func (p *Version) Size() uint32 { - return uint32(minVersionSize + io.GetVarSize(p.UserAgent)) -} diff --git a/pkg/network/payload/version_test.go b/pkg/network/payload/version_test.go index 559fe94ed..5c4b3b73e 100644 --- a/pkg/network/payload/version_test.go +++ b/pkg/network/payload/version_test.go @@ -20,7 +20,7 @@ func TestVersionEncodeDecode(t *testing.T) { err := version.EncodeBinary(buf.BinWriter) assert.Nil(t, err) b := buf.Bytes() - assert.Equal(t, int(version.Size()), len(b)) + assert.Equal(t, io.GetVarSize(version), len(b)) r := io.NewBinReaderFromBuf(b) versionDecoded := &Version{} diff --git a/pkg/rpc/wrappers/tx_raw_output.go b/pkg/rpc/wrappers/tx_raw_output.go index d3ebbd33a..7a8a6fcf7 100644 --- a/pkg/rpc/wrappers/tx_raw_output.go +++ b/pkg/rpc/wrappers/tx_raw_output.go @@ -3,6 +3,7 @@ package wrappers import ( "github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/core/transaction" + "github.com/CityOfZion/neo-go/pkg/io" "github.com/CityOfZion/neo-go/pkg/util" ) @@ -30,7 +31,7 @@ func NewTransactionOutputRaw(tx *transaction.Transaction, header *core.Header, c return TransactionOutputRaw{ Transaction: tx, TxHash: tx.Hash(), - Size: tx.Size(), + Size: io.GetVarSize(tx), SysFee: chain.SystemFee(tx), NetFee: chain.NetworkFee(tx), Blockhash: header.Hash(), diff --git a/pkg/util/fixed8.go b/pkg/util/fixed8.go index ec7b96d61..1364a0601 100644 --- a/pkg/util/fixed8.go +++ b/pkg/util/fixed8.go @@ -104,11 +104,6 @@ func (f *Fixed8) UnmarshalJSON(data []byte) error { return nil } -// Size returns the size in number of bytes of Fixed8. -func (f *Fixed8) Size() int { - return 8 -} - // MarshalJSON implements the json marshaller interface. func (f Fixed8) MarshalJSON() ([]byte, error) { return []byte(`"` + f.String() + `"`), nil diff --git a/pkg/util/uint160.go b/pkg/util/uint160.go index 996bd9334..8c9202935 100644 --- a/pkg/util/uint160.go +++ b/pkg/util/uint160.go @@ -70,11 +70,6 @@ func (u *Uint160) UnmarshalJSON(data []byte) (err error) { return err } -// Size returns the length of the bytes representation of Uint160 -func (u Uint160) Size() int { - return uint160Size -} - // MarshalJSON implements the json marshaller interface. func (u Uint160) MarshalJSON() ([]byte, error) { return []byte(`"0x` + u.String() + `"`), nil diff --git a/pkg/util/uint256.go b/pkg/util/uint256.go index 0dbad3f89..4de10b135 100644 --- a/pkg/util/uint256.go +++ b/pkg/util/uint256.go @@ -82,11 +82,6 @@ func (u *Uint256) UnmarshalJSON(data []byte) (err error) { return err } -// Size returns the length of the bytes representation of Uint256 -func (u Uint256) Size() int { - return uint256Size -} - // MarshalJSON implements the json marshaller interface. func (u Uint256) MarshalJSON() ([]byte, error) { return []byte(`"0x` + u.ReverseString() + `"`), nil From 0bb8950f890af25e12541c3fcf79512db180a944 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 Sep 2019 16:11:01 +0300 Subject: [PATCH 09/12] make TXer and Payload implement Serializable Both are duplicating Serializable at the moment, but let's keep them for the future. --- pkg/core/transaction/txer.go | 3 +-- pkg/network/payload/payload.go | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/pkg/core/transaction/txer.go b/pkg/core/transaction/txer.go index 62558143b..ca612c7fa 100644 --- a/pkg/core/transaction/txer.go +++ b/pkg/core/transaction/txer.go @@ -5,6 +5,5 @@ 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.BinReader) error - EncodeBinary(*io.BinWriter) error + io.Serializable } diff --git a/pkg/network/payload/payload.go b/pkg/network/payload/payload.go index 870b9972a..72587cef6 100644 --- a/pkg/network/payload/payload.go +++ b/pkg/network/payload/payload.go @@ -4,8 +4,7 @@ import "github.com/CityOfZion/neo-go/pkg/io" // Payload is anything that can be binary encoded/decoded. type Payload interface { - EncodeBinary(*io.BinWriter) error - DecodeBinary(*io.BinReader) error + io.Serializable } // NullPayload is a dummy payload with no fields. From d1a4e43c48b0a1b1ce46866bf7b12d7697d9d6f3 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 Sep 2019 19:31:49 +0300 Subject: [PATCH 10/12] io: redo Serializable to return errors in BinReader/BinWriter Further simplifies error handling. --- pkg/core/account_state.go | 27 +++--- pkg/core/account_state_test.go | 11 +-- pkg/core/asset_state.go | 31 ++----- pkg/core/asset_state_test.go | 7 +- pkg/core/block.go | 59 +++--------- pkg/core/block_base.go | 47 ++++------ pkg/core/block_test.go | 22 ++--- pkg/core/blockchain.go | 20 ++-- pkg/core/header.go | 20 ++-- pkg/core/header_test.go | 11 +-- pkg/core/helper_test.go | 6 +- pkg/core/spent_coin_state.go | 21 +++-- pkg/core/spent_coin_state_test.go | 7 +- pkg/core/transaction/attribute.go | 18 ++-- pkg/core/transaction/claim.go | 24 ++--- pkg/core/transaction/contract.go | 10 +- pkg/core/transaction/contract_test.go | 4 +- pkg/core/transaction/enrollment.go | 12 +-- pkg/core/transaction/enrollment_test.go | 4 +- pkg/core/transaction/helper_test.go | 5 +- pkg/core/transaction/input.go | 10 +- pkg/core/transaction/invocation.go | 10 +- pkg/core/transaction/issue.go | 10 +- pkg/core/transaction/miner.go | 10 +- pkg/core/transaction/miner_test.go | 4 +- pkg/core/transaction/output.go | 10 +- pkg/core/transaction/publish.go | 11 +-- pkg/core/transaction/register.go | 17 +--- pkg/core/transaction/register_test.go | 18 +++- pkg/core/transaction/state.go | 20 ++-- pkg/core/transaction/state_descriptor.go | 11 +-- pkg/core/transaction/state_test.go | 5 +- pkg/core/transaction/transaction.go | 112 +++++++---------------- pkg/core/transaction/transaction_test.go | 21 +++-- pkg/core/transaction/witness.go | 11 +-- pkg/core/unspent_coin_state.go | 21 +++-- pkg/core/unspent_coint_state_test.go | 7 +- pkg/core/util.go | 7 +- pkg/crypto/keys/publickey.go | 35 +++---- pkg/crypto/keys/publickey_test.go | 4 +- pkg/io/serializable.go | 11 ++- pkg/io/size.go | 6 +- pkg/io/size_test.go | 7 +- pkg/network/message.go | 40 +++----- pkg/network/payload/address.go | 34 ++----- pkg/network/payload/address_test.go | 16 ++-- pkg/network/payload/getblocks.go | 10 +- pkg/network/payload/getblocks_test.go | 16 ++-- pkg/network/payload/headers.go | 26 ++---- pkg/network/payload/headers_test.go | 16 ++-- pkg/network/payload/inventory.go | 12 +-- pkg/network/payload/inventory_test.go | 12 +-- pkg/network/payload/merkleblock.go | 15 ++- pkg/network/payload/payload.go | 12 +-- pkg/network/payload/version.go | 10 +- pkg/network/payload/version_test.go | 8 +- pkg/rpc/rpc.go | 5 +- pkg/rpc/server.go | 42 ++++----- pkg/rpc/txBuilder.go | 5 +- 59 files changed, 418 insertions(+), 605 deletions(-) diff --git a/pkg/core/account_state.go b/pkg/core/account_state.go index d5c1f6bbb..87c9771a0 100644 --- a/pkg/core/account_state.go +++ b/pkg/core/account_state.go @@ -20,8 +20,10 @@ 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(io.NewBinReaderFromBuf(b)); err != nil { - return nil, fmt.Errorf("failed to decode (AccountState): %s", err) + r := io.NewBinReaderFromBuf(b) + account.DecodeBinary(r) + if r.Err != nil { + return nil, fmt.Errorf("failed to decode (AccountState): %s", r.Err) } } else { account = NewAccountState(hash) @@ -35,8 +37,9 @@ func (a Accounts) getAndUpdate(s storage.Store, hash util.Uint160) (*AccountStat func (a Accounts) commit(b storage.Batch) error { buf := io.NewBufBinWriter() for hash, state := range a { - if err := state.EncodeBinary(buf.BinWriter); err != nil { - return err + state.EncodeBinary(buf.BinWriter) + if buf.Err != nil { + return buf.Err } key := storage.AppendPrefix(storage.STAccount, hash.Bytes()) b.Put(key, buf.Bytes()) @@ -66,7 +69,7 @@ func NewAccountState(scriptHash util.Uint160) *AccountState { } // DecodeBinary decodes AccountState from the given BinReader. -func (s *AccountState) DecodeBinary(br *io.BinReader) error { +func (s *AccountState) DecodeBinary(br *io.BinReader) { br.ReadLE(&s.Version) br.ReadLE(&s.ScriptHash) br.ReadLE(&s.IsFrozen) @@ -74,9 +77,7 @@ func (s *AccountState) DecodeBinary(br *io.BinReader) 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(br); err != nil { - return err - } + s.Votes[i].DecodeBinary(br) } s.Balances = make(map[util.Uint256]util.Fixed8) @@ -88,20 +89,16 @@ func (s *AccountState) DecodeBinary(br *io.BinReader) error { br.ReadLE(&val) s.Balances[key] = val } - - return br.Err } // EncodeBinary encodes AccountState to the given BinWriter. -func (s *AccountState) EncodeBinary(bw *io.BinWriter) error { +func (s *AccountState) EncodeBinary(bw *io.BinWriter) { 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(bw); err != nil { - return err - } + point.EncodeBinary(bw) } balances := s.nonZeroBalances() @@ -110,8 +107,6 @@ func (s *AccountState) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(k) bw.WriteLE(v) } - - return bw.Err } // Returns only the non-zero balances for the account. diff --git a/pkg/core/account_state_test.go b/pkg/core/account_state_test.go index a6b0a8645..b00225984 100644 --- a/pkg/core/account_state_test.go +++ b/pkg/core/account_state_test.go @@ -31,14 +31,13 @@ func TestDecodeEncodeAccountState(t *testing.T) { } buf := io.NewBufBinWriter() - if err := a.EncodeBinary(buf.BinWriter); err != nil { - t.Fatal(err) - } + a.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) aDecode := &AccountState{} - if err := aDecode.DecodeBinary(io.NewBinReaderFromBuf(buf.Bytes())); err != nil { - t.Fatal(err) - } + r := io.NewBinReaderFromBuf(buf.Bytes()) + aDecode.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, a.Version, aDecode.Version) assert.Equal(t, a.ScriptHash, aDecode.ScriptHash) diff --git a/pkg/core/asset_state.go b/pkg/core/asset_state.go index 712be5bcc..3a553d7ef 100644 --- a/pkg/core/asset_state.go +++ b/pkg/core/asset_state.go @@ -16,8 +16,9 @@ type Assets map[util.Uint256]*AssetState func (a Assets) commit(b storage.Batch) error { buf := io.NewBufBinWriter() for hash, state := range a { - if err := state.EncodeBinary(buf.BinWriter); err != nil { - return err + state.EncodeBinary(buf.BinWriter) + if buf.Err != nil { + return buf.Err } key := storage.AppendPrefix(storage.STAsset, hash.Bytes()) b.Put(key, buf.Bytes()) @@ -43,8 +44,8 @@ type AssetState struct { IsFrozen bool } -// DecodeBinary implements the Payload interface. -func (a *AssetState) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (a *AssetState) DecodeBinary(br *io.BinReader) { br.ReadLE(&a.ID) br.ReadLE(&a.AssetType) @@ -56,23 +57,16 @@ func (a *AssetState) DecodeBinary(br *io.BinReader) error { br.ReadLE(&a.FeeMode) br.ReadLE(&a.FeeAddress) - if br.Err != nil { - return br.Err - } a.Owner = &keys.PublicKey{} - if err := a.Owner.DecodeBinary(br); err != nil { - return err - } + a.Owner.DecodeBinary(br) br.ReadLE(&a.Admin) br.ReadLE(&a.Issuer) br.ReadLE(&a.Expiration) br.ReadLE(&a.IsFrozen) - - return br.Err } -// EncodeBinary implements the Payload interface. -func (a *AssetState) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (a *AssetState) EncodeBinary(bw *io.BinWriter) { bw.WriteLE(a.ID) bw.WriteLE(a.AssetType) bw.WriteString(a.Name) @@ -82,17 +76,12 @@ func (a *AssetState) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(a.FeeMode) bw.WriteLE(a.FeeAddress) - if bw.Err != nil { - return bw.Err - } - if err := a.Owner.EncodeBinary(bw); err != nil { - return err - } + a.Owner.EncodeBinary(bw) + bw.WriteLE(a.Admin) bw.WriteLE(a.Issuer) bw.WriteLE(a.Expiration) bw.WriteLE(a.IsFrozen) - return bw.Err } // GetName returns the asset name based on its type. diff --git a/pkg/core/asset_state_test.go b/pkg/core/asset_state_test.go index cbebd3db2..203897c47 100644 --- a/pkg/core/asset_state_test.go +++ b/pkg/core/asset_state_test.go @@ -27,8 +27,11 @@ func TestEncodeDecodeAssetState(t *testing.T) { } buf := io.NewBufBinWriter() - assert.Nil(t, asset.EncodeBinary(buf.BinWriter)) + asset.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) assetDecode := &AssetState{} - assert.Nil(t, assetDecode.DecodeBinary(io.NewBinReaderFromBuf(buf.Bytes()))) + r := io.NewBinReaderFromBuf(buf.Bytes()) + assetDecode.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, asset, assetDecode) } diff --git a/pkg/core/block.go b/pkg/core/block.go index 19d8cedd7..27ec6b225 100644 --- a/pkg/core/block.go +++ b/pkg/core/block.go @@ -72,20 +72,13 @@ func NewBlockFromTrimmedBytes(b []byte) (*Block, error) { } br := io.NewBinReaderFromBuf(b) - if err := block.decodeHashableFields(br); err != nil { - return block, err - } + block.decodeHashableFields(br) var padding uint8 br.ReadLE(&padding) - if br.Err != nil { - return block, br.Err - } block.Script = &transaction.Witness{} - if err := block.Script.DecodeBinary(br); err != nil { - return block, err - } + block.Script.DecodeBinary(br) lenTX := br.ReadVarUint() block.Transactions = make([]*transaction.Transaction, lenTX) @@ -103,16 +96,9 @@ func NewBlockFromTrimmedBytes(b []byte) (*Block, error) { // Notice that only the hashes of the transactions are stored. func (b *Block) Trim() ([]byte, error) { buf := io.NewBufBinWriter() - if err := b.encodeHashableFields(buf.BinWriter); err != nil { - return nil, err - } + b.encodeHashableFields(buf.BinWriter) buf.WriteLE(uint8(1)) - if buf.Err != nil { - return nil, buf.Err - } - if err := b.Script.EncodeBinary(buf.BinWriter); err != nil { - return nil, err - } + b.Script.EncodeBinary(buf.BinWriter) buf.WriteVarUint(uint64(len(b.Transactions))) for _, tx := range b.Transactions { @@ -124,42 +110,25 @@ func (b *Block) Trim() ([]byte, error) { return buf.Bytes(), nil } -// DecodeBinary decodes the block from the given reader. -func (b *Block) DecodeBinary(br *io.BinReader) error { - if err := b.BlockBase.DecodeBinary(br); err != nil { - return err - } +// DecodeBinary decodes the block from the given BinReader, implementing +// Serializable interface. +func (b *Block) DecodeBinary(br *io.BinReader) { + b.BlockBase.DecodeBinary(br) lentx := br.ReadVarUint() - if br.Err != nil { - return br.Err - } b.Transactions = make([]*transaction.Transaction, lentx) for i := 0; i < int(lentx); i++ { b.Transactions[i] = &transaction.Transaction{} - if err := b.Transactions[i].DecodeBinary(br); err != nil { - return err - } + b.Transactions[i].DecodeBinary(br) } - - return nil } -// EncodeBinary encodes the block to the given writer. -func (b *Block) EncodeBinary(bw *io.BinWriter) error { - err := b.BlockBase.EncodeBinary(bw) - if err != nil { - return err - } +// EncodeBinary encodes the block to the given BinWriter, implementing +// Serializable interface. +func (b *Block) EncodeBinary(bw *io.BinWriter) { + b.BlockBase.EncodeBinary(bw) bw.WriteVarUint(uint64(len(b.Transactions))) - if bw.Err != nil { - return err - } for _, tx := range b.Transactions { - err := tx.EncodeBinary(bw) - if err != nil { - return err - } + tx.EncodeBinary(bw) } - return nil } diff --git a/pkg/core/block_base.go b/pkg/core/block_base.go index 4e063db0e..6b77e1b5b 100644 --- a/pkg/core/block_base.go +++ b/pkg/core/block_base.go @@ -58,35 +58,26 @@ func (b *BlockBase) Hash() util.Uint256 { return b.hash } -// DecodeBinary implements the payload interface. -func (b *BlockBase) DecodeBinary(br *io.BinReader) error { - if err := b.decodeHashableFields(br); err != nil { - return err - } +// DecodeBinary implements Serializable interface. +func (b *BlockBase) DecodeBinary(br *io.BinReader) { + b.decodeHashableFields(br) var padding uint8 br.ReadLE(&padding) - if br.Err != nil { - return br.Err - } if padding != 1 { - return fmt.Errorf("format error: padding must equal 1 got %d", padding) + br.Err = fmt.Errorf("format error: padding must equal 1 got %d", padding) + return } b.Script = &transaction.Witness{} - return b.Script.DecodeBinary(br) + b.Script.DecodeBinary(br) } -// EncodeBinary implements the Payload interface -func (b *BlockBase) EncodeBinary(bw *io.BinWriter) error { - if err := b.encodeHashableFields(bw); err != nil { - return err - } +// EncodeBinary implements Serializable interface +func (b *BlockBase) EncodeBinary(bw *io.BinWriter) { + b.encodeHashableFields(bw) bw.WriteLE(uint8(1)) - if bw.Err != nil { - return bw.Err - } - return b.Script.EncodeBinary(bw) + b.Script.EncodeBinary(bw) } // createHash creates the hash of the block. @@ -97,8 +88,9 @@ func (b *BlockBase) EncodeBinary(bw *io.BinWriter) error { // the modification of transaction will influence the hash value of the block. func (b *BlockBase) createHash() error { buf := io.NewBufBinWriter() - if err := b.encodeHashableFields(buf.BinWriter); err != nil { - return err + b.encodeHashableFields(buf.BinWriter) + if buf.Err != nil { + return buf.Err } b.hash = hash.DoubleSha256(buf.Bytes()) @@ -107,7 +99,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(bw *io.BinWriter) error { +func (b *BlockBase) encodeHashableFields(bw *io.BinWriter) { bw.WriteLE(b.Version) bw.WriteLE(b.PrevHash) bw.WriteLE(b.MerkleRoot) @@ -115,12 +107,11 @@ func (b *BlockBase) encodeHashableFields(bw *io.BinWriter) error { bw.WriteLE(b.Index) bw.WriteLE(b.ConsensusData) bw.WriteLE(b.NextConsensus) - return bw.Err } // decodeHashableFields will only decode the fields used for hashing. // see Hash() for more information about the fields. -func (b *BlockBase) decodeHashableFields(br *io.BinReader) error { +func (b *BlockBase) decodeHashableFields(br *io.BinReader) { br.ReadLE(&b.Version) br.ReadLE(&b.PrevHash) br.ReadLE(&b.MerkleRoot) @@ -129,11 +120,9 @@ func (b *BlockBase) decodeHashableFields(br *io.BinReader) error { br.ReadLE(&b.ConsensusData) br.ReadLE(&b.NextConsensus) - if br.Err != nil { - return br.Err - } - // Make the hash of the block here so we dont need to do this // again. - return b.createHash() + if br.Err == nil { + br.Err = b.createHash() + } } diff --git a/pkg/core/block_test.go b/pkg/core/block_test.go index 546d1de47..a26007d7e 100644 --- a/pkg/core/block_test.go +++ b/pkg/core/block_test.go @@ -24,9 +24,9 @@ func TestDecodeBlock1(t *testing.T) { } block := &Block{} - if err := block.DecodeBinary(io.NewBinReaderFromBuf(b)); err != nil { - t.Fatal(err) - } + r := io.NewBinReaderFromBuf(b) + block.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, uint32(data["index"].(float64)), block.Index) assert.Equal(t, uint32(data["version"].(float64)), block.Version) @@ -110,8 +110,8 @@ func TestBinBlockDecodeEncode(t *testing.T) { b := Block{} r := io.NewBinReaderFromBuf(rawtxBytes) - err := b.DecodeBinary(r) - assert.Nil(t, err) + b.DecodeBinary(r) + assert.Nil(t, r.Err) expected := map[string]bool{ // 18 trans "009f61f481f47eb7478e887871e4e744669d461b13d68e04250035260171d706": false, @@ -167,8 +167,8 @@ func TestBinBlockDecodeEncode(t *testing.T) { buf := io.NewBufBinWriter() - err = b.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + b.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) } @@ -186,8 +186,8 @@ func TestBlockSizeCalculation(t *testing.T) { b := Block{} r := io.NewBinReaderFromBuf(rawBlockBytes) - err := b.DecodeBinary(r) - assert.Nil(t, err) + b.DecodeBinary(r) + assert.Nil(t, r.Err) expected := []struct { ID string @@ -252,8 +252,8 @@ func TestBlockSizeCalculation(t *testing.T) { buf := io.NewBufBinWriter() - err = b.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + b.EncodeBinary(buf.BinWriter) + assert.Nil(t, r.Err) benc := buf.Bytes() // test size of the block assert.Equal(t, 7360, len(benc)) diff --git a/pkg/core/blockchain.go b/pkg/core/blockchain.go index 08e5b298a..21ca332a4 100644 --- a/pkg/core/blockchain.go +++ b/pkg/core/blockchain.go @@ -254,8 +254,9 @@ func (bc *Blockchain) processHeader(h *Header, batch storage.Batch, headerList * } buf.Reset() - if err := h.EncodeBinary(buf.BinWriter); err != nil { - return err + h.EncodeBinary(buf.BinWriter) + if buf.Err != nil { + return buf.Err } key := storage.AppendPrefix(storage.DataBlock, h.Hash().BytesReverse()) @@ -470,14 +471,13 @@ func (bc *Blockchain) GetTransaction(hash util.Uint256) (*transaction.Transactio var height uint32 r.ReadLE(&height) + + tx := &transaction.Transaction{} + tx.DecodeBinary(r) if r.Err != nil { return nil, 0, r.Err } - tx := &transaction.Transaction{} - if err := tx.DecodeBinary(r); err != nil { - return nil, 0, err - } return tx, height, nil } @@ -578,7 +578,9 @@ 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(io.NewBinReaderFromBuf(v)); err == nil && a.ID == assetID { + r := io.NewBinReaderFromBuf(v) + a.DecodeBinary(r) + if r.Err == nil && a.ID == assetID { as = &a } }) @@ -591,7 +593,9 @@ 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(io.NewBinReaderFromBuf(v)); err == nil && a.ScriptHash == scriptHash { + r := io.NewBinReaderFromBuf(v) + a.DecodeBinary(r) + if r.Err == nil && a.ScriptHash == scriptHash { as = &a } }) diff --git a/pkg/core/header.go b/pkg/core/header.go index 659270cc5..0ce253ddb 100644 --- a/pkg/core/header.go +++ b/pkg/core/header.go @@ -14,28 +14,20 @@ type Header struct { _ uint8 } -// DecodeBinary implements the Payload interface. -func (h *Header) DecodeBinary(r *io.BinReader) error { - if err := h.BlockBase.DecodeBinary(r); err != nil { - return err - } +// DecodeBinary implements Serializable interface. +func (h *Header) DecodeBinary(r *io.BinReader) { + h.BlockBase.DecodeBinary(r) var padding uint8 r.ReadLE(&padding) - if r.Err != nil { - return r.Err - } if padding != 0 { - return fmt.Errorf("format error: padding must equal 0 got %d", padding) + r.Err = fmt.Errorf("format error: padding must equal 0 got %d", padding) } - - return nil } -// EncodeBinary implements the Payload interface. -func (h *Header) EncodeBinary(w *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (h *Header) EncodeBinary(w *io.BinWriter) { h.BlockBase.EncodeBinary(w) w.WriteLE(uint8(0)) - return w.Err } diff --git a/pkg/core/header_test.go b/pkg/core/header_test.go index 8b7bcf19f..81cd2a242 100644 --- a/pkg/core/header_test.go +++ b/pkg/core/header_test.go @@ -27,14 +27,13 @@ func TestHeaderEncodeDecode(t *testing.T) { }} buf := io.NewBufBinWriter() - if err := header.EncodeBinary(buf.BinWriter); err != nil { - t.Fatal(err) - } + header.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) headerDecode := &Header{} - if err := headerDecode.DecodeBinary(io.NewBinReaderFromBuf(buf.Bytes())); err != nil { - t.Fatal(err) - } + r := io.NewBinReaderFromBuf(buf.Bytes()) + headerDecode.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, header.Version, headerDecode.Version, "expected both versions to be equal") assert.Equal(t, header.PrevHash, headerDecode.PrevHash, "expected both prev hashes to be equal") assert.Equal(t, header.MerkleRoot, headerDecode.MerkleRoot, "expected both merkle roots to be equal") diff --git a/pkg/core/helper_test.go b/pkg/core/helper_test.go index 1ab25d3e9..65c44a8c0 100644 --- a/pkg/core/helper_test.go +++ b/pkg/core/helper_test.go @@ -63,8 +63,10 @@ func getDecodedBlock(t *testing.T, i int) *Block { } block := &Block{} - if err := block.DecodeBinary(io.NewBinReaderFromBuf(b)); err != nil { - t.Fatal(err) + r := io.NewBinReaderFromBuf(b) + block.DecodeBinary(r) + if r.Err != nil { + t.Fatal(r.Err) } return block diff --git a/pkg/core/spent_coin_state.go b/pkg/core/spent_coin_state.go index 21db15fb9..978ff2a02 100644 --- a/pkg/core/spent_coin_state.go +++ b/pkg/core/spent_coin_state.go @@ -20,8 +20,10 @@ 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(io.NewBinReaderFromBuf(b)); err != nil { - return nil, fmt.Errorf("failed to decode (UnspentCoinState): %s", err) + r := io.NewBinReaderFromBuf(b) + spent.DecodeBinary(r) + if r.Err != nil { + return nil, fmt.Errorf("failed to decode (UnspentCoinState): %s", r.Err) } } else { spent = &SpentCoinState{ @@ -36,8 +38,9 @@ func (s SpentCoins) getAndUpdate(store storage.Store, hash util.Uint256) (*Spent func (s SpentCoins) commit(b storage.Batch) error { buf := io.NewBufBinWriter() for hash, state := range s { - if err := state.EncodeBinary(buf.BinWriter); err != nil { - return err + state.EncodeBinary(buf.BinWriter) + if buf.Err != nil { + return buf.Err } key := storage.AppendPrefix(storage.STSpentCoin, hash.BytesReverse()) b.Put(key, buf.Bytes()) @@ -64,8 +67,8 @@ func NewSpentCoinState(hash util.Uint256, height uint32) *SpentCoinState { } } -// DecodeBinary implements the Payload interface. -func (s *SpentCoinState) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (s *SpentCoinState) DecodeBinary(br *io.BinReader) { br.ReadLE(&s.txHash) br.ReadLE(&s.txHeight) @@ -80,11 +83,10 @@ func (s *SpentCoinState) DecodeBinary(br *io.BinReader) error { br.ReadLE(&value) s.items[key] = value } - return br.Err } -// EncodeBinary implements the Payload interface. -func (s *SpentCoinState) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (s *SpentCoinState) EncodeBinary(bw *io.BinWriter) { bw.WriteLE(s.txHash) bw.WriteLE(s.txHeight) bw.WriteVarUint(uint64(len(s.items))) @@ -92,5 +94,4 @@ func (s *SpentCoinState) EncodeBinary(bw *io.BinWriter) error { bw.WriteLE(k) bw.WriteLE(v) } - return bw.Err } diff --git a/pkg/core/spent_coin_state_test.go b/pkg/core/spent_coin_state_test.go index dde497e3d..0736196ed 100644 --- a/pkg/core/spent_coin_state_test.go +++ b/pkg/core/spent_coin_state_test.go @@ -21,9 +21,12 @@ func TestEncodeDecodeSpentCoinState(t *testing.T) { } buf := io.NewBufBinWriter() - assert.Nil(t, spent.EncodeBinary(buf.BinWriter)) + spent.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) spentDecode := new(SpentCoinState) - assert.Nil(t, spentDecode.DecodeBinary(io.NewBinReaderFromBuf(buf.Bytes()))) + r := io.NewBinReaderFromBuf(buf.Bytes()) + spentDecode.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, spent, spentDecode) } diff --git a/pkg/core/transaction/attribute.go b/pkg/core/transaction/attribute.go index 425dd72e6..40b4ff7fb 100644 --- a/pkg/core/transaction/attribute.go +++ b/pkg/core/transaction/attribute.go @@ -14,8 +14,8 @@ type Attribute struct { Data []byte } -// DecodeBinary implements the Payload interface. -func (attr *Attribute) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (attr *Attribute) DecodeBinary(br *io.BinReader) { br.ReadLE(&attr.Usage) // very special case @@ -23,7 +23,7 @@ func (attr *Attribute) DecodeBinary(br *io.BinReader) error { attr.Data = make([]byte, 33) attr.Data[0] = byte(attr.Usage) br.ReadLE(attr.Data[1:]) - return br.Err + return } var datasize uint64 switch attr.Usage { @@ -43,15 +43,15 @@ func (attr *Attribute) DecodeBinary(br *io.BinReader) error { Remark12, Remark13, Remark14, Remark15: datasize = br.ReadVarUint() default: - return fmt.Errorf("failed decoding TX attribute usage: 0x%2x", int(attr.Usage)) + br.Err = fmt.Errorf("failed decoding TX attribute usage: 0x%2x", int(attr.Usage)) + return } attr.Data = make([]byte, datasize) br.ReadLE(attr.Data) - return br.Err } -// EncodeBinary implements the Payload interface. -func (attr *Attribute) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (attr *Attribute) EncodeBinary(bw *io.BinWriter) { bw.WriteLE(&attr.Usage) switch attr.Usage { case ECDH02, ECDH03: @@ -68,10 +68,8 @@ func (attr *Attribute) EncodeBinary(bw *io.BinWriter) error { Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15: bw.WriteLE(attr.Data) default: - return fmt.Errorf("failed encoding TX attribute usage: 0x%2x", attr.Usage) + bw.Err = fmt.Errorf("failed encoding TX attribute usage: 0x%2x", attr.Usage) } - - return bw.Err } // MarshalJSON implements the json Marschaller interface diff --git a/pkg/core/transaction/claim.go b/pkg/core/transaction/claim.go index 61d44614c..7140f6aad 100644 --- a/pkg/core/transaction/claim.go +++ b/pkg/core/transaction/claim.go @@ -9,32 +9,20 @@ type ClaimTX struct { Claims []*Input } -// DecodeBinary implements the Payload interface. -func (tx *ClaimTX) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (tx *ClaimTX) DecodeBinary(br *io.BinReader) { lenClaims := br.ReadVarUint() - if br.Err != nil { - return br.Err - } tx.Claims = make([]*Input, lenClaims) for i := 0; i < int(lenClaims); i++ { tx.Claims[i] = &Input{} - if err := tx.Claims[i].DecodeBinary(br); err != nil { - return err - } + tx.Claims[i].DecodeBinary(br) } - return nil } -// EncodeBinary implements the Payload interface. -func (tx *ClaimTX) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (tx *ClaimTX) EncodeBinary(bw *io.BinWriter) { bw.WriteVarUint(uint64(len(tx.Claims))) - if bw.Err != nil { - return bw.Err - } for _, claim := range tx.Claims { - if err := claim.EncodeBinary(bw); err != nil { - return err - } + claim.EncodeBinary(bw) } - return nil } diff --git a/pkg/core/transaction/contract.go b/pkg/core/transaction/contract.go index 4c445da21..32e66388f 100644 --- a/pkg/core/transaction/contract.go +++ b/pkg/core/transaction/contract.go @@ -15,12 +15,10 @@ func NewContractTX() *Transaction { } } -// DecodeBinary implements the Payload interface. -func (tx *ContractTX) DecodeBinary(r *io.BinReader) error { - return nil +// DecodeBinary implements Serializable interface. +func (tx *ContractTX) DecodeBinary(r *io.BinReader) { } -// EncodeBinary implements the Payload interface. -func (tx *ContractTX) EncodeBinary(w *io.BinWriter) error { - return nil +// EncodeBinary implements Serializable interface. +func (tx *ContractTX) EncodeBinary(w *io.BinWriter) { } diff --git a/pkg/core/transaction/contract_test.go b/pkg/core/transaction/contract_test.go index 43e7d19b2..6d6ed4ef0 100644 --- a/pkg/core/transaction/contract_test.go +++ b/pkg/core/transaction/contract_test.go @@ -31,7 +31,7 @@ func TestEncodeDecodeContract(t *testing.T) { // Encode buf := io.NewBufBinWriter() - err := tx.EncodeBinary(buf.BinWriter) - assert.Equal(t, nil, err) + tx.EncodeBinary(buf.BinWriter) + assert.Equal(t, nil, buf.Err) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) } diff --git a/pkg/core/transaction/enrollment.go b/pkg/core/transaction/enrollment.go index d01b3eedb..79e3c3b2e 100644 --- a/pkg/core/transaction/enrollment.go +++ b/pkg/core/transaction/enrollment.go @@ -15,13 +15,13 @@ type EnrollmentTX struct { PublicKey *keys.PublicKey } -// DecodeBinary implements the Payload interface. -func (tx *EnrollmentTX) DecodeBinary(r *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (tx *EnrollmentTX) DecodeBinary(r *io.BinReader) { tx.PublicKey = &keys.PublicKey{} - return tx.PublicKey.DecodeBinary(r) + tx.PublicKey.DecodeBinary(r) } -// EncodeBinary implements the Payload interface. -func (tx *EnrollmentTX) EncodeBinary(w *io.BinWriter) error { - return tx.PublicKey.EncodeBinary(w) +// EncodeBinary implements Serializable interface. +func (tx *EnrollmentTX) EncodeBinary(w *io.BinWriter) { + tx.PublicKey.EncodeBinary(w) } diff --git a/pkg/core/transaction/enrollment_test.go b/pkg/core/transaction/enrollment_test.go index fa669fc0e..beb4f46f9 100644 --- a/pkg/core/transaction/enrollment_test.go +++ b/pkg/core/transaction/enrollment_test.go @@ -17,8 +17,8 @@ func TestEncodeDecodeEnrollment(t *testing.T) { assert.Equal(t, 0, int(tx.Version)) buf := io.NewBufBinWriter() - err := tx.EncodeBinary(buf.BinWriter) + tx.EncodeBinary(buf.BinWriter) - assert.Equal(t, nil, err) + assert.Equal(t, nil, buf.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 2cc7cc121..beca5cf6a 100644 --- a/pkg/core/transaction/helper_test.go +++ b/pkg/core/transaction/helper_test.go @@ -21,7 +21,8 @@ func decodeTransaction(rawTX string, t *testing.T) *Transaction { b, err1 := hex.DecodeString(rawTX) assert.Nil(t, err1) tx := &Transaction{} - err2 := tx.DecodeBinary(io.NewBinReaderFromBuf(b)) - assert.Nil(t, err2) + r := io.NewBinReaderFromBuf(b) + tx.DecodeBinary(r) + assert.Nil(t, r.Err) return tx } diff --git a/pkg/core/transaction/input.go b/pkg/core/transaction/input.go index a5a13411d..f5e25dcc7 100644 --- a/pkg/core/transaction/input.go +++ b/pkg/core/transaction/input.go @@ -14,16 +14,14 @@ type Input struct { PrevIndex uint16 `json:"vout"` } -// DecodeBinary implements the Payload interface. -func (in *Input) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (in *Input) DecodeBinary(br *io.BinReader) { br.ReadLE(&in.PrevHash) br.ReadLE(&in.PrevIndex) - return br.Err } -// EncodeBinary implements the Payload interface. -func (in *Input) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (in *Input) EncodeBinary(bw *io.BinWriter) { 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 43a2409ed..2ac3550e0 100644 --- a/pkg/core/transaction/invocation.go +++ b/pkg/core/transaction/invocation.go @@ -31,22 +31,20 @@ func NewInvocationTX(script []byte) *Transaction { } } -// DecodeBinary implements the Payload interface. -func (tx *InvocationTX) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (tx *InvocationTX) DecodeBinary(br *io.BinReader) { tx.Script = br.ReadBytes() if tx.Version >= 1 { br.ReadLE(&tx.Gas) } else { tx.Gas = util.Fixed8FromInt64(0) } - return br.Err } -// EncodeBinary implements the Payload interface. -func (tx *InvocationTX) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (tx *InvocationTX) EncodeBinary(bw *io.BinWriter) { bw.WriteBytes(tx.Script) if tx.Version >= 1 { bw.WriteLE(tx.Gas) } - return bw.Err } diff --git a/pkg/core/transaction/issue.go b/pkg/core/transaction/issue.go index 9f412e97a..5e09bb171 100644 --- a/pkg/core/transaction/issue.go +++ b/pkg/core/transaction/issue.go @@ -8,12 +8,10 @@ import ( // This TX has not special attributes. type IssueTX struct{} -// DecodeBinary implements the Payload interface. -func (tx *IssueTX) DecodeBinary(r *io.BinReader) error { - return nil +// DecodeBinary implements Serializable interface. +func (tx *IssueTX) DecodeBinary(r *io.BinReader) { } -// EncodeBinary implements the Payload interface. -func (tx *IssueTX) EncodeBinary(w *io.BinWriter) error { - return nil +// EncodeBinary implements Serializable interface. +func (tx *IssueTX) EncodeBinary(w *io.BinWriter) { } diff --git a/pkg/core/transaction/miner.go b/pkg/core/transaction/miner.go index 923253926..1e1ab3753 100644 --- a/pkg/core/transaction/miner.go +++ b/pkg/core/transaction/miner.go @@ -10,14 +10,12 @@ type MinerTX struct { Nonce uint32 } -// DecodeBinary implements the Payload interface. -func (tx *MinerTX) DecodeBinary(r *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (tx *MinerTX) DecodeBinary(r *io.BinReader) { r.ReadLE(&tx.Nonce) - return r.Err } -// EncodeBinary implements the Payload interface. -func (tx *MinerTX) EncodeBinary(w *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (tx *MinerTX) EncodeBinary(w *io.BinWriter) { w.WriteLE(tx.Nonce) - return w.Err } diff --git a/pkg/core/transaction/miner_test.go b/pkg/core/transaction/miner_test.go index c5c7a77ee..4ef3e2334 100644 --- a/pkg/core/transaction/miner_test.go +++ b/pkg/core/transaction/miner_test.go @@ -23,8 +23,8 @@ func TestEncodeDecodeMiner(t *testing.T) { // Encode buf := io.NewBufBinWriter() - err := tx.EncodeBinary(buf.BinWriter) - assert.Equal(t, nil, err) + tx.EncodeBinary(buf.BinWriter) + assert.Equal(t, nil, buf.Err) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) } diff --git a/pkg/core/transaction/output.go b/pkg/core/transaction/output.go index a6aacbdca..489059839 100644 --- a/pkg/core/transaction/output.go +++ b/pkg/core/transaction/output.go @@ -33,20 +33,18 @@ func NewOutput(assetID util.Uint256, amount util.Fixed8, scriptHash util.Uint160 } } -// DecodeBinary implements the Payload interface. -func (out *Output) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (out *Output) DecodeBinary(br *io.BinReader) { br.ReadLE(&out.AssetID) br.ReadLE(&out.Amount) br.ReadLE(&out.ScriptHash) - return br.Err } -// EncodeBinary implements the Payload interface. -func (out *Output) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (out *Output) EncodeBinary(bw *io.BinWriter) { bw.WriteLE(out.AssetID) bw.WriteLE(out.Amount) bw.WriteLE(out.ScriptHash) - return bw.Err } // MarshalJSON implements the Marshaler interface diff --git a/pkg/core/transaction/publish.go b/pkg/core/transaction/publish.go index 6a07fdfce..e46ce6a56 100644 --- a/pkg/core/transaction/publish.go +++ b/pkg/core/transaction/publish.go @@ -20,8 +20,8 @@ type PublishTX struct { Version uint8 // Version of the parent struct Transaction. Used in reading NeedStorage flag. } -// DecodeBinary implements the Payload interface. -func (tx *PublishTX) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (tx *PublishTX) DecodeBinary(br *io.BinReader) { tx.Script = br.ReadBytes() lenParams := br.ReadVarUint() @@ -47,12 +47,10 @@ func (tx *PublishTX) DecodeBinary(br *io.BinReader) error { tx.Author = br.ReadString() tx.Email = br.ReadString() tx.Description = br.ReadString() - - return br.Err } -// EncodeBinary implements the Payload interface. -func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) { bw.WriteBytes(tx.Script) bw.WriteVarUint(uint64(len(tx.ParamList))) for _, param := range tx.ParamList { @@ -67,5 +65,4 @@ func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) error { bw.WriteString(tx.Author) bw.WriteString(tx.Email) bw.WriteString(tx.Description) - return bw.Err } diff --git a/pkg/core/transaction/register.go b/pkg/core/transaction/register.go index c3c227165..fde7687ef 100644 --- a/pkg/core/transaction/register.go +++ b/pkg/core/transaction/register.go @@ -28,34 +28,27 @@ type RegisterTX struct { Admin util.Uint160 } -// DecodeBinary implements the Payload interface. -func (tx *RegisterTX) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (tx *RegisterTX) DecodeBinary(br *io.BinReader) { br.ReadLE(&tx.AssetType) tx.Name = br.ReadString() br.ReadLE(&tx.Amount) br.ReadLE(&tx.Precision) - if br.Err != nil { - return br.Err - } tx.Owner = &keys.PublicKey{} - if err := tx.Owner.DecodeBinary(br); err != nil { - return err - } + tx.Owner.DecodeBinary(br) br.ReadLE(&tx.Admin) - return br.Err } -// EncodeBinary implements the Payload interface. -func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) { bw.WriteLE(tx.AssetType) bw.WriteString(tx.Name) bw.WriteLE(tx.Amount) bw.WriteLE(tx.Precision) bw.WriteLE(tx.Owner.Bytes()) bw.WriteLE(tx.Admin) - return bw.Err } diff --git a/pkg/core/transaction/register_test.go b/pkg/core/transaction/register_test.go index c8a9419d7..77ee583ac 100644 --- a/pkg/core/transaction/register_test.go +++ b/pkg/core/transaction/register_test.go @@ -27,11 +27,14 @@ func TestRegisterTX(t *testing.T) { } buf := io.NewBufBinWriter() - assert.Nil(t, tx.EncodeBinary(buf.BinWriter)) + tx.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) b := buf.Bytes() txDecode := &Transaction{} - assert.Nil(t, txDecode.DecodeBinary(io.NewBinReaderFromBuf(b))) + r := io.NewBinReaderFromBuf(b) + txDecode.DecodeBinary(r) + assert.Nil(t, r.Err) txData := tx.Data.(*RegisterTX) txDecodeData := txDecode.Data.(*RegisterTX) assert.Equal(t, txData, txDecodeData) @@ -46,7 +49,9 @@ func TestDecodeRegisterTXFromRawString(t *testing.T) { } tx := &Transaction{} - assert.Nil(t, tx.DecodeBinary(io.NewBinReaderFromBuf(b))) + r := io.NewBinReaderFromBuf(b) + tx.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, RegisterType, tx.Type) txData := tx.Data.(*RegisterTX) assert.Equal(t, GoverningToken, txData.AssetType) @@ -58,10 +63,13 @@ func TestDecodeRegisterTXFromRawString(t *testing.T) { assert.Equal(t, "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", tx.Hash().ReverseString()) buf := io.NewBufBinWriter() - assert.Nil(t, tx.EncodeBinary(buf.BinWriter)) + tx.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) benc := buf.Bytes() txDecode := &Transaction{} - assert.Nil(t, txDecode.DecodeBinary(io.NewBinReaderFromBuf(benc))) + encreader := io.NewBinReaderFromBuf(benc) + txDecode.DecodeBinary(encreader) + assert.Nil(t, encreader.Err) assert.Equal(t, tx, txDecode) } diff --git a/pkg/core/transaction/state.go b/pkg/core/transaction/state.go index 8723b972d..22a214e99 100644 --- a/pkg/core/transaction/state.go +++ b/pkg/core/transaction/state.go @@ -9,28 +9,20 @@ type StateTX struct { Descriptors []*StateDescriptor } -// DecodeBinary implements the Payload interface. -func (tx *StateTX) DecodeBinary(r *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (tx *StateTX) DecodeBinary(r *io.BinReader) { lenDesc := r.ReadVarUint() tx.Descriptors = make([]*StateDescriptor, lenDesc) for i := 0; i < int(lenDesc); i++ { tx.Descriptors[i] = &StateDescriptor{} - err := tx.Descriptors[i].DecodeBinary(r) - if err != nil { - return err - } + tx.Descriptors[i].DecodeBinary(r) } - return r.Err } -// EncodeBinary implements the Payload interface. -func (tx *StateTX) EncodeBinary(w *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (tx *StateTX) EncodeBinary(w *io.BinWriter) { w.WriteVarUint(uint64(len(tx.Descriptors))) for _, desc := range tx.Descriptors { - err := desc.EncodeBinary(w) - if err != nil { - return err - } + desc.EncodeBinary(w) } - return w.Err } diff --git a/pkg/core/transaction/state_descriptor.go b/pkg/core/transaction/state_descriptor.go index 40dbbcf14..087ea5baf 100644 --- a/pkg/core/transaction/state_descriptor.go +++ b/pkg/core/transaction/state_descriptor.go @@ -21,22 +21,19 @@ type StateDescriptor struct { Field string } -// DecodeBinary implements the Payload interface. -func (s *StateDescriptor) DecodeBinary(r *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (s *StateDescriptor) DecodeBinary(r *io.BinReader) { r.ReadLE(&s.Type) s.Key = r.ReadBytes() s.Value = r.ReadBytes() s.Field = r.ReadString() - - return r.Err } -// EncodeBinary implements the Payload interface. -func (s *StateDescriptor) EncodeBinary(w *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (s *StateDescriptor) EncodeBinary(w *io.BinWriter) { w.WriteLE(s.Type) w.WriteBytes(s.Key) w.WriteBytes(s.Value) w.WriteString(s.Field) - return w.Err } diff --git a/pkg/core/transaction/state_test.go b/pkg/core/transaction/state_test.go index eb425b42e..290bfe744 100644 --- a/pkg/core/transaction/state_test.go +++ b/pkg/core/transaction/state_test.go @@ -31,9 +31,8 @@ func TestEncodeDecodeState(t *testing.T) { // Encode buf := io.NewBufBinWriter() + tx.EncodeBinary(buf.BinWriter) - err := tx.EncodeBinary(buf.BinWriter) - - assert.Equal(t, nil, err) + assert.Equal(t, nil, buf.Err) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) } diff --git a/pkg/core/transaction/transaction.go b/pkg/core/transaction/transaction.go index 628677f21..13bdca753 100644 --- a/pkg/core/transaction/transaction.go +++ b/pkg/core/transaction/transaction.go @@ -74,170 +74,126 @@ func (t *Transaction) AddInput(in *Input) { t.Inputs = append(t.Inputs, in) } -// DecodeBinary implements the payload interface. -func (t *Transaction) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (t *Transaction) DecodeBinary(br *io.BinReader) { br.ReadLE(&t.Type) br.ReadLE(&t.Version) - if br.Err != nil { - return br.Err - } - if err := t.decodeData(br); err != nil { - return err - } + t.decodeData(br) lenAttrs := br.ReadVarUint() t.Attributes = make([]*Attribute, lenAttrs) for i := 0; i < int(lenAttrs); i++ { t.Attributes[i] = &Attribute{} - if err := t.Attributes[i].DecodeBinary(br); err != nil { - log.Warnf("failed to decode TX %s", t.hash) - return err - } + t.Attributes[i].DecodeBinary(br) } lenInputs := br.ReadVarUint() t.Inputs = make([]*Input, lenInputs) for i := 0; i < int(lenInputs); i++ { t.Inputs[i] = &Input{} - if err := t.Inputs[i].DecodeBinary(br); err != nil { - return err - } + t.Inputs[i].DecodeBinary(br) } lenOutputs := br.ReadVarUint() t.Outputs = make([]*Output, lenOutputs) for i := 0; i < int(lenOutputs); i++ { t.Outputs[i] = &Output{} - if err := t.Outputs[i].DecodeBinary(br); err != nil { - return err - } + t.Outputs[i].DecodeBinary(br) } lenScripts := br.ReadVarUint() t.Scripts = make([]*Witness, lenScripts) for i := 0; i < int(lenScripts); i++ { t.Scripts[i] = &Witness{} - if err := t.Scripts[i].DecodeBinary(br); err != nil { - return err - } + t.Scripts[i].DecodeBinary(br) } - if br.Err != nil { - return br.Err - } // Create the hash of the transaction at decode, so we dont need // to do it anymore. - return t.createHash() + if br.Err == nil { + br.Err = t.createHash() + } } -func (t *Transaction) decodeData(r *io.BinReader) error { +func (t *Transaction) decodeData(r *io.BinReader) { switch t.Type { case InvocationType: t.Data = &InvocationTX{Version: t.Version} - return t.Data.(*InvocationTX).DecodeBinary(r) + t.Data.(*InvocationTX).DecodeBinary(r) case MinerType: t.Data = &MinerTX{} - return t.Data.(*MinerTX).DecodeBinary(r) + t.Data.(*MinerTX).DecodeBinary(r) case ClaimType: t.Data = &ClaimTX{} - return t.Data.(*ClaimTX).DecodeBinary(r) + t.Data.(*ClaimTX).DecodeBinary(r) case ContractType: t.Data = &ContractTX{} - return t.Data.(*ContractTX).DecodeBinary(r) + t.Data.(*ContractTX).DecodeBinary(r) case RegisterType: t.Data = &RegisterTX{} - return t.Data.(*RegisterTX).DecodeBinary(r) + t.Data.(*RegisterTX).DecodeBinary(r) case IssueType: t.Data = &IssueTX{} - return t.Data.(*IssueTX).DecodeBinary(r) + t.Data.(*IssueTX).DecodeBinary(r) case EnrollmentType: t.Data = &EnrollmentTX{} - return t.Data.(*EnrollmentTX).DecodeBinary(r) + t.Data.(*EnrollmentTX).DecodeBinary(r) case PublishType: t.Data = &PublishTX{Version: t.Version} - return t.Data.(*PublishTX).DecodeBinary(r) + t.Data.(*PublishTX).DecodeBinary(r) case StateType: t.Data = &StateTX{} - return t.Data.(*StateTX).DecodeBinary(r) + t.Data.(*StateTX).DecodeBinary(r) default: log.Warnf("invalid TX type %s", t.Type) } - return nil } -// EncodeBinary implements the payload interface. -func (t *Transaction) EncodeBinary(bw *io.BinWriter) error { - if err := t.encodeHashableFields(bw); err != nil { - return err - } +// EncodeBinary implements Serializable interface. +func (t *Transaction) EncodeBinary(bw *io.BinWriter) { + t.encodeHashableFields(bw) bw.WriteVarUint(uint64(len(t.Scripts))) - if bw.Err != nil { - return bw.Err - } for _, s := range t.Scripts { - if err := s.EncodeBinary(bw); err != nil { - return err - } + s.EncodeBinary(bw) } - return nil } // 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(bw *io.BinWriter) error { +func (t *Transaction) encodeHashableFields(bw *io.BinWriter) { bw.WriteLE(t.Type) bw.WriteLE(t.Version) - if bw.Err != nil { - return bw.Err - } // Underlying TXer. if t.Data != nil { - if err := t.Data.EncodeBinary(bw); err != nil { - return err - } + t.Data.EncodeBinary(bw) } // Attributes bw.WriteVarUint(uint64(len(t.Attributes))) - if bw.Err != nil { - return bw.Err - } for _, attr := range t.Attributes { - if err := attr.EncodeBinary(bw); err != nil { - return err - } + attr.EncodeBinary(bw) } // Inputs bw.WriteVarUint(uint64(len(t.Inputs))) - if bw.Err != nil { - return bw.Err - } for _, in := range t.Inputs { - if err := in.EncodeBinary(bw); err != nil { - return err - } + in.EncodeBinary(bw) } // Outputs bw.WriteVarUint(uint64(len(t.Outputs))) - if bw.Err != nil { - return bw.Err - } for _, out := range t.Outputs { - if err := out.EncodeBinary(bw); err != nil { - return err - } + out.EncodeBinary(bw) } - return nil } // createHash creates the hash of the transaction. func (t *Transaction) createHash() error { buf := io.NewBufBinWriter() - if err := t.encodeHashableFields(buf.BinWriter); err != nil { - return err + t.encodeHashableFields(buf.BinWriter) + if buf.Err != nil { + return buf.Err } t.hash = hash.DoubleSha256(buf.Bytes()) @@ -266,9 +222,9 @@ func (t Transaction) GroupOutputByAssetID() map[util.Uint256][]*Output { // Bytes convert the transaction to []byte func (t *Transaction) Bytes() []byte { buf := io.NewBufBinWriter() - if err := t.EncodeBinary(buf.BinWriter); err != nil { + t.EncodeBinary(buf.BinWriter) + if buf.Err != nil { return nil } return buf.Bytes() - } diff --git a/pkg/core/transaction/transaction_test.go b/pkg/core/transaction/transaction_test.go index a5387bb5f..2c416c570 100644 --- a/pkg/core/transaction/transaction_test.go +++ b/pkg/core/transaction/transaction_test.go @@ -28,13 +28,14 @@ func TestWitnessEncodeDecode(t *testing.T) { } buf := io.NewBufBinWriter() - err = wit.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + wit.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) benc := buf.Bytes() witDecode := &Witness{} - err = witDecode.DecodeBinary(io.NewBinReaderFromBuf(benc)) - assert.Nil(t, err) + encreader := io.NewBinReaderFromBuf(benc) + witDecode.DecodeBinary(encreader) + assert.Nil(t, encreader.Err) t.Log(len(witDecode.VerificationScript)) t.Log(len(witDecode.InvocationScript)) @@ -61,8 +62,8 @@ func TestDecodeEncodeClaimTX(t *testing.T) { assert.Equal(t, verif, hex.EncodeToString(tx.Scripts[0].VerificationScript)) buf := io.NewBufBinWriter() - err := tx.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + tx.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) assert.Equal(t, rawClaimTX, hex.EncodeToString(buf.Bytes())) hash := "2c6a45547b3898318e400e541628990a07acb00f3b9a15a8e966ae49525304da" @@ -89,8 +90,8 @@ func TestDecodeEncodeInvocationTX(t *testing.T) { assert.Equal(t, verif, hex.EncodeToString(tx.Scripts[0].VerificationScript)) buf := io.NewBufBinWriter() - err := tx.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + tx.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) assert.Equal(t, rawInvocationTX, hex.EncodeToString(buf.Bytes())) } @@ -144,7 +145,7 @@ func TestDecodePublishTX(t *testing.T) { assert.Equal(t, expectedTX.Version, actualTX.Version) buf := io.NewBufBinWriter() - err := actualTX.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + actualTX.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) assert.Equal(t, rawPublishTX, hex.EncodeToString(buf.Bytes())) } diff --git a/pkg/core/transaction/witness.go b/pkg/core/transaction/witness.go index 9256ecc16..8640dca74 100644 --- a/pkg/core/transaction/witness.go +++ b/pkg/core/transaction/witness.go @@ -15,19 +15,16 @@ type Witness struct { VerificationScript []byte } -// DecodeBinary implements the payload interface. -func (w *Witness) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (w *Witness) DecodeBinary(br *io.BinReader) { w.InvocationScript = br.ReadBytes() w.VerificationScript = br.ReadBytes() - return br.Err } -// EncodeBinary implements the payload interface. -func (w *Witness) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (w *Witness) EncodeBinary(bw *io.BinWriter) { bw.WriteBytes(w.InvocationScript) bw.WriteBytes(w.VerificationScript) - - return bw.Err } // MarshalJSON implements the json marshaller interface. diff --git a/pkg/core/unspent_coin_state.go b/pkg/core/unspent_coin_state.go index 504dc68dd..9f8026578 100644 --- a/pkg/core/unspent_coin_state.go +++ b/pkg/core/unspent_coin_state.go @@ -21,8 +21,10 @@ 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(io.NewBinReaderFromBuf(b)); err != nil { - return nil, fmt.Errorf("failed to decode (UnspentCoinState): %s", err) + r := io.NewBinReaderFromBuf(b) + unspent.DecodeBinary(r) + if r.Err != nil { + return nil, fmt.Errorf("failed to decode (UnspentCoinState): %s", r.Err) } } else { unspent = &UnspentCoinState{ @@ -54,8 +56,9 @@ func NewUnspentCoinState(n int) *UnspentCoinState { func (u UnspentCoins) commit(b storage.Batch) error { buf := io.NewBufBinWriter() for hash, state := range u { - if err := state.EncodeBinary(buf.BinWriter); err != nil { - return err + state.EncodeBinary(buf.BinWriter) + if buf.Err != nil { + return buf.Err } key := storage.AppendPrefix(storage.STCoin, hash.BytesReverse()) b.Put(key, buf.Bytes()) @@ -65,16 +68,15 @@ func (u UnspentCoins) commit(b storage.Batch) error { } // EncodeBinary encodes UnspentCoinState to the given BinWriter. -func (s *UnspentCoinState) EncodeBinary(bw *io.BinWriter) error { +func (s *UnspentCoinState) EncodeBinary(bw *io.BinWriter) { bw.WriteVarUint(uint64(len(s.states))) for _, state := range s.states { bw.WriteLE(byte(state)) } - return bw.Err } // DecodeBinary decodes UnspentCoinState from the given BinReader. -func (s *UnspentCoinState) DecodeBinary(br *io.BinReader) error { +func (s *UnspentCoinState) DecodeBinary(br *io.BinReader) { lenStates := br.ReadVarUint() s.states = make([]CoinState, lenStates) for i := 0; i < int(lenStates); i++ { @@ -82,7 +84,6 @@ func (s *UnspentCoinState) DecodeBinary(br *io.BinReader) error { br.ReadLE(&state) s.states[i] = CoinState(state) } - return br.Err } // IsDoubleSpend verifies that the input transactions are not double spent. @@ -95,7 +96,9 @@ 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(io.NewBinReaderFromBuf(b)); err != nil { + r := io.NewBinReaderFromBuf(b) + unspent.DecodeBinary(r) + if r.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 8fb649f19..658233ebc 100644 --- a/pkg/core/unspent_coint_state_test.go +++ b/pkg/core/unspent_coint_state_test.go @@ -20,9 +20,12 @@ func TestDecodeEncodeUnspentCoinState(t *testing.T) { } buf := io.NewBufBinWriter() - assert.Nil(t, unspent.EncodeBinary(buf.BinWriter)) + unspent.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) unspentDecode := &UnspentCoinState{} - assert.Nil(t, unspentDecode.DecodeBinary(io.NewBinReaderFromBuf(buf.Bytes()))) + r := io.NewBinReaderFromBuf(buf.Bytes()) + unspentDecode.DecodeBinary(r) + assert.Nil(t, r.Err) } func TestCommitUnspentCoins(t *testing.T) { diff --git a/pkg/core/util.go b/pkg/core/util.go index b092a2da4..05a189d26 100644 --- a/pkg/core/util.go +++ b/pkg/core/util.go @@ -211,11 +211,10 @@ func storeAsTransaction(batch storage.Batch, tx *transaction.Transaction, index key := storage.AppendPrefix(storage.DataTransaction, tx.Hash().BytesReverse()) buf := io.NewBufBinWriter() buf.WriteLE(index) - if err := tx.EncodeBinary(buf.BinWriter); err != nil { - return err + tx.EncodeBinary(buf.BinWriter) + if buf.Err != nil { + return buf.Err } - batch.Put(key, buf.Bytes()) - return nil } diff --git a/pkg/crypto/keys/publickey.go b/pkg/crypto/keys/publickey.go index 2a30c2626..bcb6cf68a 100644 --- a/pkg/crypto/keys/publickey.go +++ b/pkg/crypto/keys/publickey.go @@ -50,8 +50,10 @@ func NewPublicKeyFromString(s string) (*PublicKey, error) { } pubKey := new(PublicKey) - if err := pubKey.DecodeBinary(io.NewBinReaderFromBuf(b)); err != nil { - return nil, err + r := io.NewBinReaderFromBuf(b) + pubKey.DecodeBinary(r) + if r.Err != nil { + return nil, r.Err } return pubKey, nil @@ -122,37 +124,38 @@ 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 { b := io.NewBinReaderFromBuf(data) - return p.DecodeBinary(b) + p.DecodeBinary(b) + return b.Err } // DecodeBinary decodes a PublicKey from the given BinReader. -func (p *PublicKey) DecodeBinary(r *io.BinReader) error { +func (p *PublicKey) DecodeBinary(r *io.BinReader) { var prefix uint8 var x, y *big.Int var err error r.ReadLE(&prefix) if r.Err != nil { - return r.Err + return } // Infinity switch prefix { case 0x00: // noop, initialized to nil - return nil + return case 0x02, 0x03: // Compressed public keys xbytes := make([]byte, 32) r.ReadLE(xbytes) if r.Err != nil { - return r.Err + return } x = new(big.Int).SetBytes(xbytes) ylsb := uint(prefix & 0x1) y, err = decodeCompressedY(x, ylsb) if err != nil { - return err + return } case 0x04: xbytes := make([]byte, 32) @@ -160,30 +163,30 @@ func (p *PublicKey) DecodeBinary(r *io.BinReader) error { r.ReadLE(xbytes) r.ReadLE(ybytes) if r.Err != nil { - return r.Err + return } x = new(big.Int).SetBytes(xbytes) y = new(big.Int).SetBytes(ybytes) default: - return errors.Errorf("invalid prefix %d", prefix) + r.Err = errors.Errorf("invalid prefix %d", prefix) + return } c := elliptic.P256() cp := c.Params() if !c.IsOnCurve(x, y) { - return errors.New("enccoded point is not on the P256 curve") + r.Err = errors.New("enccoded point is not on the P256 curve") + return } if x.Cmp(cp.P) >= 0 || y.Cmp(cp.P) >= 0 { - return errors.New("enccoded point is not correct (X or Y is bigger than P") + r.Err = errors.New("enccoded point is not correct (X or Y is bigger than P") + return } p.X, p.Y = x, y - - return nil } // EncodeBinary encodes a PublicKey to the given BinWriter. -func (p *PublicKey) EncodeBinary(w *io.BinWriter) error { +func (p *PublicKey) EncodeBinary(w *io.BinWriter) { 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 71e73f5ef..199577d6e 100644 --- a/pkg/crypto/keys/publickey_test.go +++ b/pkg/crypto/keys/publickey_test.go @@ -11,7 +11,7 @@ import ( func TestEncodeDecodeInfinity(t *testing.T) { key := &PublicKey{} buf := io.NewBufBinWriter() - assert.Nil(t, key.EncodeBinary(buf.BinWriter)) + key.EncodeBinary(buf.BinWriter) assert.Nil(t, buf.Err) b := buf.Bytes() assert.Equal(t, 1, len(b)) @@ -27,7 +27,7 @@ func TestEncodeDecodePublicKey(t *testing.T) { assert.Nil(t, err) p := k.PublicKey() buf := io.NewBufBinWriter() - assert.Nil(t, p.EncodeBinary(buf.BinWriter)) + p.EncodeBinary(buf.BinWriter) assert.Nil(t, buf.Err) b := buf.Bytes() diff --git a/pkg/io/serializable.go b/pkg/io/serializable.go index 2063d2c6d..8e132b86b 100644 --- a/pkg/io/serializable.go +++ b/pkg/io/serializable.go @@ -1,7 +1,12 @@ package io -// Serializable defines the binary encoding/decoding interface. +// Serializable defines the binary encoding/decoding interface. Errors are +// returned via BinReader/BinWriter Err field. These functions must have safe +// behavior when passed BinReader/BinWriter with Err already set. Invocations +// to these functions tend to be nested, with this mechanism only the top-level +// caller should handle the error once and all the other code should just not +// panic in presence of error. type Serializable interface { - DecodeBinary(*BinReader) error - EncodeBinary(*BinWriter) error + DecodeBinary(*BinReader) + EncodeBinary(*BinWriter) } diff --git a/pkg/io/size.go b/pkg/io/size.go index ca966740c..ea8bcc562 100644 --- a/pkg/io/size.go +++ b/pkg/io/size.go @@ -80,9 +80,9 @@ func GetVarSize(value interface{}) int { } cw := counterWriter{} w := NewBinWriterFromIO(&cw) - err := vser.EncodeBinary(w) - if err != nil { - panic(fmt.Sprintf("error serializing %s: %s", reflect.TypeOf(value), err.Error())) + vser.EncodeBinary(w) + if w.Err != nil { + panic(fmt.Sprintf("error serializing %s: %s", reflect.TypeOf(value), w.Err.Error())) } return cw.counter case reflect.Slice, reflect.Array: diff --git a/pkg/io/size_test.go b/pkg/io/size_test.go index 85275fe94..d3a5ad561 100644 --- a/pkg/io/size_test.go +++ b/pkg/io/size_test.go @@ -13,13 +13,10 @@ type smthSerializable struct { some [42]byte } -func (*smthSerializable) DecodeBinary(*BinReader) error { - return nil -} +func (*smthSerializable) DecodeBinary(*BinReader) {} -func (ss *smthSerializable) EncodeBinary(bw *BinWriter) error { +func (ss *smthSerializable) EncodeBinary(bw *BinWriter) { bw.WriteLE(ss.some) - return nil } func TestVarSize(t *testing.T) { diff --git a/pkg/network/message.go b/pkg/network/message.go index 69fe8b2d8..1f702fc9f 100644 --- a/pkg/network/message.go +++ b/pkg/network/message.go @@ -78,8 +78,9 @@ func NewMessage(magic config.NetMode, cmd CommandType, p payload.Payload) *Messa if p != nil { buf := io.NewBufBinWriter() - if err := p.EncodeBinary(buf.BinWriter); err != nil { - panic(err) + p.EncodeBinary(buf.BinWriter) + if buf.Err != nil { + panic(buf.Err) } b := buf.Bytes() size = uint32(len(b)) @@ -176,46 +177,26 @@ func (m *Message) decodePayload(br *io.BinReader) error { switch m.CommandType() { case CMDVersion: p = &payload.Version{} - if err := p.DecodeBinary(r); err != nil { - return err - } case CMDInv, CMDGetData: p = &payload.Inventory{} - if err := p.DecodeBinary(r); err != nil { - return err - } case CMDAddr: p = &payload.AddressList{} - if err := p.DecodeBinary(r); err != nil { - return err - } case CMDBlock: p = &core.Block{} - if err := p.DecodeBinary(r); err != nil { - return err - } case CMDGetBlocks: fallthrough case CMDGetHeaders: p = &payload.GetBlocks{} - if err := p.DecodeBinary(r); err != nil { - return err - } case CMDHeaders: p = &payload.Headers{} - if err := p.DecodeBinary(r); err != nil { - return err - } case CMDTX: p = &transaction.Transaction{} - if err := p.DecodeBinary(r); err != nil { - return err - } case CMDMerkleBlock: p = &payload.MerkleBlock{} - if err := p.DecodeBinary(r); err != nil { - return err - } + } + p.DecodeBinary(r) + if r.Err != nil { + return r.Err } m.Payload = p @@ -229,12 +210,13 @@ func (m *Message) Encode(br *io.BinWriter) error { br.WriteLE(m.Command) br.WriteLE(m.Length) br.WriteLE(m.Checksum) + if m.Payload != nil { + m.Payload.EncodeBinary(br) + + } if br.Err != nil { return br.Err } - if m.Payload != nil { - return m.Payload.EncodeBinary(br) - } return nil } diff --git a/pkg/network/payload/address.go b/pkg/network/payload/address.go index e562f0b21..eae7bc670 100644 --- a/pkg/network/payload/address.go +++ b/pkg/network/payload/address.go @@ -27,22 +27,20 @@ func NewAddressAndTime(e *net.TCPAddr, t time.Time) *AddressAndTime { return &aat } -// DecodeBinary implements the Payload interface. -func (p *AddressAndTime) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (p *AddressAndTime) DecodeBinary(br *io.BinReader) { br.ReadLE(&p.Timestamp) br.ReadLE(&p.Services) br.ReadBE(&p.IP) br.ReadBE(&p.Port) - return br.Err } -// EncodeBinary implements the Payload interface. -func (p *AddressAndTime) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (p *AddressAndTime) EncodeBinary(bw *io.BinWriter) { bw.WriteLE(p.Timestamp) bw.WriteLE(p.Services) bw.WriteBE(p.IP) bw.WriteBE(p.Port) - return bw.Err } // IPPortString makes a string from IP and port specified. @@ -67,33 +65,21 @@ func NewAddressList(n int) *AddressList { return &alist } -// DecodeBinary implements the Payload interface. -func (p *AddressList) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (p *AddressList) DecodeBinary(br *io.BinReader) { listLen := br.ReadVarUint() - if br.Err != nil { - return br.Err - } p.Addrs = make([]*AddressAndTime, listLen) for i := 0; i < int(listLen); i++ { p.Addrs[i] = &AddressAndTime{} - if err := p.Addrs[i].DecodeBinary(br); err != nil { - return err - } + p.Addrs[i].DecodeBinary(br) } - return nil } -// EncodeBinary implements the Payload interface. -func (p *AddressList) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (p *AddressList) EncodeBinary(bw *io.BinWriter) { bw.WriteVarUint(uint64(len(p.Addrs))) - if bw.Err != nil { - return bw.Err - } for _, addr := range p.Addrs { - if err := addr.EncodeBinary(bw); err != nil { - return err - } + addr.EncodeBinary(bw) } - return nil } diff --git a/pkg/network/payload/address_test.go b/pkg/network/payload/address_test.go index dbe5db885..bfd2f2ded 100644 --- a/pkg/network/payload/address_test.go +++ b/pkg/network/payload/address_test.go @@ -23,14 +23,14 @@ 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.BinWriter) - assert.Nil(t, err) + addr.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) b := buf.Bytes() r := io.NewBinReaderFromBuf(b) addrDecode := &AddressAndTime{} - err = addrDecode.DecodeBinary(r) - assert.Nil(t, err) + addrDecode.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, addr, addrDecode) } @@ -44,14 +44,14 @@ func TestEncodeDecodeAddressList(t *testing.T) { } buf := io.NewBufBinWriter() - err := addrList.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + addrList.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) b := buf.Bytes() r := io.NewBinReaderFromBuf(b) addrListDecode := &AddressList{} - err = addrListDecode.DecodeBinary(r) - assert.Nil(t, err) + addrListDecode.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, addrList, addrListDecode) } diff --git a/pkg/network/payload/getblocks.go b/pkg/network/payload/getblocks.go index 3298c5b5a..0029cb26c 100644 --- a/pkg/network/payload/getblocks.go +++ b/pkg/network/payload/getblocks.go @@ -21,20 +21,18 @@ func NewGetBlocks(start []util.Uint256, stop util.Uint256) *GetBlocks { } } -// DecodeBinary implements the payload interface. -func (p *GetBlocks) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (p *GetBlocks) DecodeBinary(br *io.BinReader) { lenStart := br.ReadVarUint() p.HashStart = make([]util.Uint256, lenStart) br.ReadLE(&p.HashStart) br.ReadLE(&p.HashStop) - return br.Err } -// EncodeBinary implements the payload interface. -func (p *GetBlocks) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (p *GetBlocks) EncodeBinary(bw *io.BinWriter) { bw.WriteVarUint(uint64(len(p.HashStart))) bw.WriteLE(p.HashStart) bw.WriteLE(p.HashStop) - return bw.Err } diff --git a/pkg/network/payload/getblocks_test.go b/pkg/network/payload/getblocks_test.go index 5844c9bbd..dfa35bef0 100644 --- a/pkg/network/payload/getblocks_test.go +++ b/pkg/network/payload/getblocks_test.go @@ -19,14 +19,14 @@ func TestGetBlockEncodeDecode(t *testing.T) { p := NewGetBlocks(start, util.Uint256{}) buf := io.NewBufBinWriter() - err := p.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + p.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) b := buf.Bytes() r := io.NewBinReaderFromBuf(b) pDecode := &GetBlocks{} - err = pDecode.DecodeBinary(r) - assert.Nil(t, err) + pDecode.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, p, pDecode) } @@ -42,13 +42,13 @@ func TestGetBlockEncodeDecodeWithHashStop(t *testing.T) { ) p := NewGetBlocks(start, stop) buf := io.NewBufBinWriter() - err := p.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + p.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) b := buf.Bytes() r := io.NewBinReaderFromBuf(b) pDecode := &GetBlocks{} - err = pDecode.DecodeBinary(r) - assert.Nil(t, err) + pDecode.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, p, pDecode) } diff --git a/pkg/network/payload/headers.go b/pkg/network/payload/headers.go index 66771fb5e..c85ecab2e 100644 --- a/pkg/network/payload/headers.go +++ b/pkg/network/payload/headers.go @@ -16,12 +16,10 @@ const ( maxHeadersAllowed = 2000 ) -// DecodeBinary implements the Payload interface. -func (p *Headers) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (p *Headers) DecodeBinary(br *io.BinReader) { lenHeaders := br.ReadVarUint() - if br.Err != nil { - return br.Err - } + // C# node does it silently if lenHeaders > maxHeadersAllowed { log.Warnf("received %d headers, capping to %d", lenHeaders, maxHeadersAllowed) @@ -32,26 +30,16 @@ func (p *Headers) DecodeBinary(br *io.BinReader) error { for i := 0; i < int(lenHeaders); i++ { header := &core.Header{} - if err := header.DecodeBinary(br); err != nil { - return err - } + header.DecodeBinary(br) p.Hdrs[i] = header } - - return nil } -// EncodeBinary implements the Payload interface. -func (p *Headers) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (p *Headers) EncodeBinary(bw *io.BinWriter) { bw.WriteVarUint(uint64(len(p.Hdrs))) - if bw.Err != nil { - return bw.Err - } for _, header := range p.Hdrs { - if err := header.EncodeBinary(bw); err != nil { - return err - } + header.EncodeBinary(bw) } - return nil } diff --git a/pkg/network/payload/headers_test.go b/pkg/network/payload/headers_test.go index 2ee849f27..3c421077b 100644 --- a/pkg/network/payload/headers_test.go +++ b/pkg/network/payload/headers_test.go @@ -42,14 +42,14 @@ func TestHeadersEncodeDecode(t *testing.T) { }} buf := io.NewBufBinWriter() - err := headers.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + headers.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) b := buf.Bytes() r := io.NewBinReaderFromBuf(b) headersDecode := &Headers{} - err = headersDecode.DecodeBinary(r) - assert.Nil(t, err) + headersDecode.DecodeBinary(r) + assert.Nil(t, r.Err) for i := 0; i < len(headers.Hdrs); i++ { assert.Equal(t, headers.Hdrs[i].Version, headersDecode.Hdrs[i].Version) @@ -67,8 +67,8 @@ func TestBinEncodeDecode(t *testing.T) { r := io.NewBinReaderFromBuf(rawBlockBytes) - err := headerMsg.DecodeBinary(r) - assert.Nil(t, err) + headerMsg.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, 1, len(headerMsg.Hdrs)) header := headerMsg.Hdrs[0] @@ -78,7 +78,7 @@ func TestBinEncodeDecode(t *testing.T) { buf := io.NewBufBinWriter() - err = headerMsg.EncodeBinary(buf.BinWriter) - assert.Equal(t, nil, err) + headerMsg.EncodeBinary(buf.BinWriter) + assert.Equal(t, nil, buf.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 ade25c9c8..4ce9ca939 100644 --- a/pkg/network/payload/inventory.go +++ b/pkg/network/payload/inventory.go @@ -54,8 +54,8 @@ func NewInventory(typ InventoryType, hashes []util.Uint256) *Inventory { } } -// DecodeBinary implements the Payload interface. -func (p *Inventory) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (p *Inventory) DecodeBinary(br *io.BinReader) { br.ReadLE(&p.Type) listLen := br.ReadVarUint() @@ -63,12 +63,10 @@ func (p *Inventory) DecodeBinary(br *io.BinReader) error { for i := 0; i < int(listLen); i++ { br.ReadLE(&p.Hashes[i]) } - - return br.Err } -// EncodeBinary implements the Payload interface. -func (p *Inventory) EncodeBinary(bw *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (p *Inventory) EncodeBinary(bw *io.BinWriter) { bw.WriteLE(p.Type) listLen := len(p.Hashes) @@ -76,6 +74,4 @@ func (p *Inventory) EncodeBinary(bw *io.BinWriter) error { for i := 0; i < listLen; i++ { bw.WriteLE(p.Hashes[i]) } - - return bw.Err } diff --git a/pkg/network/payload/inventory_test.go b/pkg/network/payload/inventory_test.go index acbe7c7c2..5e1d8ea92 100644 --- a/pkg/network/payload/inventory_test.go +++ b/pkg/network/payload/inventory_test.go @@ -17,14 +17,14 @@ func TestInventoryEncodeDecode(t *testing.T) { inv := NewInventory(BlockType, hashes) buf := io.NewBufBinWriter() - err := inv.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + inv.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) b := buf.Bytes() r := io.NewBinReaderFromBuf(b) invDecode := &Inventory{} - err = invDecode.DecodeBinary(r) - assert.Nil(t, err) + invDecode.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, inv, invDecode) } @@ -32,8 +32,8 @@ func TestEmptyInv(t *testing.T) { msgInv := NewInventory(TXType, []Uint256{}) buf := io.NewBufBinWriter() - err := msgInv.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + msgInv.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.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 2c9cf979c..59f733754 100644 --- a/pkg/network/payload/merkleblock.go +++ b/pkg/network/payload/merkleblock.go @@ -14,12 +14,10 @@ type MerkleBlock struct { Flags []byte } -// DecodeBinary implements the Payload interface. -func (m *MerkleBlock) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (m *MerkleBlock) DecodeBinary(br *io.BinReader) { m.BlockBase = &core.BlockBase{} - if err := m.BlockBase.DecodeBinary(br); err != nil { - return err - } + m.BlockBase.DecodeBinary(br) m.TxCount = int(br.ReadVarUint()) n := br.ReadVarUint() @@ -28,10 +26,9 @@ func (m *MerkleBlock) DecodeBinary(br *io.BinReader) error { br.ReadLE(&m.Hashes[i]) } m.Flags = br.ReadBytes() - return br.Err } -// EncodeBinary implements the Payload interface. -func (m *MerkleBlock) EncodeBinary(bw *io.BinWriter) error { - return nil +// EncodeBinary implements Serializable interface. +func (m *MerkleBlock) EncodeBinary(bw *io.BinWriter) { + return } diff --git a/pkg/network/payload/payload.go b/pkg/network/payload/payload.go index 72587cef6..112008ffd 100644 --- a/pkg/network/payload/payload.go +++ b/pkg/network/payload/payload.go @@ -16,12 +16,8 @@ func NewNullPayload() *NullPayload { return &NullPayload{} } -// DecodeBinary implements the Payload interface. -func (p *NullPayload) DecodeBinary(r io.Reader) error { - return nil -} +// DecodeBinary implements Serializable interface. +func (p *NullPayload) DecodeBinary(r *io.BinReader) {} -// EncodeBinary implements the Payload interface. -func (p *NullPayload) EncodeBinary(r io.Writer) error { - return nil -} +// EncodeBinary implements Serializable interface. +func (p *NullPayload) EncodeBinary(w *io.BinWriter) {} diff --git a/pkg/network/payload/version.go b/pkg/network/payload/version.go index 2cb79fbe2..1343298b2 100644 --- a/pkg/network/payload/version.go +++ b/pkg/network/payload/version.go @@ -53,8 +53,8 @@ func NewVersion(id uint32, p uint16, ua string, h uint32, r bool) *Version { } } -// DecodeBinary implements the Payload interface. -func (p *Version) DecodeBinary(br *io.BinReader) error { +// DecodeBinary implements Serializable interface. +func (p *Version) DecodeBinary(br *io.BinReader) { br.ReadLE(&p.Version) br.ReadLE(&p.Services) br.ReadLE(&p.Timestamp) @@ -63,11 +63,10 @@ func (p *Version) DecodeBinary(br *io.BinReader) error { p.UserAgent = br.ReadBytes() br.ReadLE(&p.StartHeight) br.ReadLE(&p.Relay) - return br.Err } -// EncodeBinary implements the Payload interface. -func (p *Version) EncodeBinary(br *io.BinWriter) error { +// EncodeBinary implements Serializable interface. +func (p *Version) EncodeBinary(br *io.BinWriter) { br.WriteLE(p.Version) br.WriteLE(p.Services) br.WriteLE(p.Timestamp) @@ -77,5 +76,4 @@ func (p *Version) EncodeBinary(br *io.BinWriter) error { br.WriteBytes(p.UserAgent) br.WriteLE(p.StartHeight) br.WriteLE(&p.Relay) - return br.Err } diff --git a/pkg/network/payload/version_test.go b/pkg/network/payload/version_test.go index 5c4b3b73e..4af2e2425 100644 --- a/pkg/network/payload/version_test.go +++ b/pkg/network/payload/version_test.go @@ -17,15 +17,15 @@ func TestVersionEncodeDecode(t *testing.T) { version := NewVersion(id, port, useragent, height, relay) buf := io.NewBufBinWriter() - err := version.EncodeBinary(buf.BinWriter) - assert.Nil(t, err) + version.EncodeBinary(buf.BinWriter) + assert.Nil(t, buf.Err) b := buf.Bytes() assert.Equal(t, io.GetVarSize(version), len(b)) r := io.NewBinReaderFromBuf(b) versionDecoded := &Version{} - err = versionDecoded.DecodeBinary(r) - assert.Nil(t, err) + versionDecoded.DecodeBinary(r) + assert.Nil(t, r.Err) assert.Equal(t, versionDecoded.Nonce, id) assert.Equal(t, versionDecoded.Port, port) assert.Equal(t, versionDecoded.UserAgent, []byte(useragent)) diff --git a/pkg/rpc/rpc.go b/pkg/rpc/rpc.go index 09684d114..fae42b549 100644 --- a/pkg/rpc/rpc.go +++ b/pkg/rpc/rpc.go @@ -130,8 +130,9 @@ 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.BinWriter); err != nil { - return nil, errors.Wrap(err, "failed to encode raw transaction to binary for `sendtoaddress`") + rawTx.EncodeBinary(buf.BinWriter) + if buf.Err != nil { + return nil, errors.Wrap(buf.Err, "failed to encode raw transaction to binary for `sendtoaddress`") } rawTxStr = hex.EncodeToString(buf.Bytes()) if resp, err = c.sendRawTransaction(rawTxStr); err != nil { diff --git a/pkg/rpc/server.go b/pkg/rpc/server.go index db73d2ae1..9d5070e61 100644 --- a/pkg/rpc/server.go +++ b/pkg/rpc/server.go @@ -296,27 +296,27 @@ func (s *Server) sendrawtransaction(reqParams Params) (interface{}, error) { } else { r := io.NewBinReaderFromBuf(byteTx) tx := &transaction.Transaction{} - err = tx.DecodeBinary(r) - if err != nil { - err = errors.Wrap(err, "transaction DecodeBinary failed") - } - relayReason := s.coreServer.RelayTxn(tx) - switch relayReason { - case network.RelaySucceed: - results = true - case network.RelayAlreadyExists: - err = errors.New("block or transaction already exists and cannot be sent repeatedly") - case network.RelayOutOfMemory: - err = errors.New("the memory pool is full and no more transactions can be sent") - case network.RelayUnableToVerify: - err = errors.New("the block cannot be validated") - case network.RelayInvalid: - err = errors.New("block or transaction validation failed") - case network.RelayPolicyFail: - err = errors.New("one of the Policy filters failed") - default: - err = errors.New("unknown error") - + tx.DecodeBinary(r) + if r.Err != nil { + err = errors.Wrap(r.Err, "transaction DecodeBinary failed") + } else { + relayReason := s.coreServer.RelayTxn(tx) + switch relayReason { + case network.RelaySucceed: + results = true + case network.RelayAlreadyExists: + err = errors.New("block or transaction already exists and cannot be sent repeatedly") + case network.RelayOutOfMemory: + err = errors.New("the memory pool is full and no more transactions can be sent") + case network.RelayUnableToVerify: + err = errors.New("the block cannot be validated") + case network.RelayInvalid: + err = errors.New("block or transaction validation failed") + case network.RelayPolicyFail: + err = errors.New("one of the Policy filters failed") + default: + err = errors.New("unknown error") + } } if err != nil { resultsErr = NewInternalServerError(err.Error(), err) diff --git a/pkg/rpc/txBuilder.go b/pkg/rpc/txBuilder.go index d68f3b12a..72a2298af 100644 --- a/pkg/rpc/txBuilder.go +++ b/pkg/rpc/txBuilder.go @@ -73,8 +73,9 @@ func GetInvocationScript(tx *transaction.Transaction, wif keys.WIF) ([]byte, err buf = io.NewBufBinWriter() signature []byte ) - if err = tx.EncodeBinary(buf.BinWriter); err != nil { - return nil, errs.Wrap(err, "Failed to encode transaction to binary") + tx.EncodeBinary(buf.BinWriter) + if buf.Err != nil { + return nil, errs.Wrap(buf.Err, "Failed to encode transaction to binary") } data := buf.Bytes() signature, err = wif.PrivateKey.Sign(data[:(len(data) - 1)]) From 96618015cd1143aa8d17c2b1224c9ed513bc441f Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Mon, 16 Sep 2019 19:49:48 +0300 Subject: [PATCH 11/12] network: implement EncodeBinary() for MerkleBlock --- pkg/network/payload/merkleblock.go | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/pkg/network/payload/merkleblock.go b/pkg/network/payload/merkleblock.go index 59f733754..996f32431 100644 --- a/pkg/network/payload/merkleblock.go +++ b/pkg/network/payload/merkleblock.go @@ -30,5 +30,13 @@ func (m *MerkleBlock) DecodeBinary(br *io.BinReader) { // EncodeBinary implements Serializable interface. func (m *MerkleBlock) EncodeBinary(bw *io.BinWriter) { - return + m.BlockBase = &core.BlockBase{} + m.BlockBase.EncodeBinary(bw) + + bw.WriteVarUint(uint64(m.TxCount)) + bw.WriteVarUint(uint64(len(m.Hashes))) + for i := 0; i < len(m.Hashes); i++ { + bw.WriteLE(m.Hashes[i]) + } + bw.WriteBytes(m.Flags) } From 5bca4d2313e743acfb101907a4f6e595b8c6d518 Mon Sep 17 00:00:00 2001 From: Roman Khimov Date: Tue, 17 Sep 2019 13:20:38 +0300 Subject: [PATCH 12/12] io: expand panic tests to reach 100% coverage --- pkg/io/size_test.go | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/pkg/io/size_test.go b/pkg/io/size_test.go index d3a5ad561..dddce59ad 100644 --- a/pkg/io/size_test.go +++ b/pkg/io/size_test.go @@ -19,6 +19,15 @@ func (ss *smthSerializable) EncodeBinary(bw *BinWriter) { bw.WriteLE(ss.some) } +// Mock structure that gives error in EncodeBinary(). +type smthNotReallySerializable struct{} + +func (*smthNotReallySerializable) DecodeBinary(*BinReader) {} + +func (*smthNotReallySerializable) EncodeBinary(bw *BinWriter) { + bw.Err = fmt.Errorf("smth bad happened in smthNotReallySerializable") +} + func TestVarSize(t *testing.T) { testCases := []struct { variable interface{} @@ -179,11 +188,19 @@ func TestVarSize(t *testing.T) { } } -func TestVarSizePanic(t *testing.T) { +func panicVarSize(t *testing.T, v interface{}) { defer func() { r := recover() assert.NotNil(t, r) }() - _ = GetVarSize(t) + _ = GetVarSize(v) + // this should never execute + assert.Nil(t, t) +} + +func TestVarSizePanic(t *testing.T) { + panicVarSize(t, t) + panicVarSize(t, struct{}{}) + panicVarSize(t, &smthNotReallySerializable{}) }