Merge pull request #400 from nspcc-dev/move-rw-to-io

Move BinReader/BinWriter to io and simplify things

BinReader and BinWriter don't belong to util, actually util shouldn't
exist at all. Moving them to io and using them for all encoding/decoding
purposes allows to simplify a lot of code, especially in the error
handling space. These interfaces are designed to absorb errors until
someone can do something meaningful with them (usually that's the top
caller of encode/decode functions) and our current use of them is
inconsistent.

This patchset moves BinReader/BinWriter and size calculations (that
are mostly about Serializable things) to io package and makes all the
other code use them for encoding/decoding purposes.
This commit is contained in:
Roman Khimov 2019-09-17 15:08:15 +03:00 committed by GitHub
commit 39a024eb03
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
75 changed files with 981 additions and 1189 deletions

View file

@ -1,12 +1,11 @@
package core package core
import ( import (
"bytes"
"fmt" "fmt"
"io"
"github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/storage"
"github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -21,8 +20,10 @@ func (a Accounts) getAndUpdate(s storage.Store, hash util.Uint160) (*AccountStat
account := &AccountState{} account := &AccountState{}
key := storage.AppendPrefix(storage.STAccount, hash.Bytes()) key := storage.AppendPrefix(storage.STAccount, hash.Bytes())
if b, err := s.Get(key); err == nil { if b, err := s.Get(key); err == nil {
if err := account.DecodeBinary(bytes.NewReader(b)); err != nil { r := io.NewBinReaderFromBuf(b)
return nil, fmt.Errorf("failed to decode (AccountState): %s", err) account.DecodeBinary(r)
if r.Err != nil {
return nil, fmt.Errorf("failed to decode (AccountState): %s", r.Err)
} }
} else { } else {
account = NewAccountState(hash) account = NewAccountState(hash)
@ -34,10 +35,11 @@ func (a Accounts) getAndUpdate(s storage.Store, hash util.Uint160) (*AccountStat
// commit writes all account states to the given Batch. // commit writes all account states to the given Batch.
func (a Accounts) commit(b storage.Batch) error { func (a Accounts) commit(b storage.Batch) error {
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
for hash, state := range a { for hash, state := range a {
if err := state.EncodeBinary(buf); err != nil { state.EncodeBinary(buf.BinWriter)
return err if buf.Err != nil {
return buf.Err
} }
key := storage.AppendPrefix(storage.STAccount, hash.Bytes()) key := storage.AppendPrefix(storage.STAccount, hash.Bytes())
b.Put(key, buf.Bytes()) b.Put(key, buf.Bytes())
@ -66,9 +68,8 @@ func NewAccountState(scriptHash util.Uint160) *AccountState {
} }
} }
// DecodeBinary decodes AccountState from the given io.Reader. // DecodeBinary decodes AccountState from the given BinReader.
func (s *AccountState) DecodeBinary(r io.Reader) error { func (s *AccountState) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&s.Version) br.ReadLE(&s.Version)
br.ReadLE(&s.ScriptHash) br.ReadLE(&s.ScriptHash)
br.ReadLE(&s.IsFrozen) br.ReadLE(&s.IsFrozen)
@ -76,9 +77,7 @@ func (s *AccountState) DecodeBinary(r io.Reader) error {
s.Votes = make([]*keys.PublicKey, lenVotes) s.Votes = make([]*keys.PublicKey, lenVotes)
for i := 0; i < int(lenVotes); i++ { for i := 0; i < int(lenVotes); i++ {
s.Votes[i] = &keys.PublicKey{} s.Votes[i] = &keys.PublicKey{}
if err := s.Votes[i].DecodeBinary(r); err != nil { s.Votes[i].DecodeBinary(br)
return err
}
} }
s.Balances = make(map[util.Uint256]util.Fixed8) s.Balances = make(map[util.Uint256]util.Fixed8)
@ -90,21 +89,16 @@ func (s *AccountState) DecodeBinary(r io.Reader) error {
br.ReadLE(&val) br.ReadLE(&val)
s.Balances[key] = val s.Balances[key] = val
} }
return br.Err
} }
// EncodeBinary encode AccountState to the given io.Writer. // EncodeBinary encodes AccountState to the given BinWriter.
func (s *AccountState) EncodeBinary(w io.Writer) error { func (s *AccountState) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteLE(s.Version) bw.WriteLE(s.Version)
bw.WriteLE(s.ScriptHash) bw.WriteLE(s.ScriptHash)
bw.WriteLE(s.IsFrozen) bw.WriteLE(s.IsFrozen)
bw.WriteVarUint(uint64(len(s.Votes))) bw.WriteVarUint(uint64(len(s.Votes)))
for _, point := range s.Votes { for _, point := range s.Votes {
if err := point.EncodeBinary(w); err != nil { point.EncodeBinary(bw)
return err
}
} }
balances := s.nonZeroBalances() balances := s.nonZeroBalances()
@ -113,8 +107,6 @@ func (s *AccountState) EncodeBinary(w io.Writer) error {
bw.WriteLE(k) bw.WriteLE(k)
bw.WriteLE(v) bw.WriteLE(v)
} }
return bw.Err
} }
// Returns only the non-zero balances for the account. // Returns only the non-zero balances for the account.

View file

@ -1,10 +1,10 @@
package core package core
import ( import (
"bytes"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -30,15 +30,14 @@ func TestDecodeEncodeAccountState(t *testing.T) {
Balances: balances, Balances: balances,
} }
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
if err := a.EncodeBinary(buf); err != nil { a.EncodeBinary(buf.BinWriter)
t.Fatal(err) assert.Nil(t, buf.Err)
}
aDecode := &AccountState{} aDecode := &AccountState{}
if err := aDecode.DecodeBinary(buf); err != nil { r := io.NewBinReaderFromBuf(buf.Bytes())
t.Fatal(err) aDecode.DecodeBinary(r)
} assert.Nil(t, r.Err)
assert.Equal(t, a.Version, aDecode.Version) assert.Equal(t, a.Version, aDecode.Version)
assert.Equal(t, a.ScriptHash, aDecode.ScriptHash) assert.Equal(t, a.ScriptHash, aDecode.ScriptHash)

View file

@ -1,12 +1,10 @@
package core package core
import ( import (
"bytes"
"io"
"github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/storage"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -16,10 +14,11 @@ const feeMode = 0x0
type Assets map[util.Uint256]*AssetState type Assets map[util.Uint256]*AssetState
func (a Assets) commit(b storage.Batch) error { func (a Assets) commit(b storage.Batch) error {
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
for hash, state := range a { for hash, state := range a {
if err := state.EncodeBinary(buf); err != nil { state.EncodeBinary(buf.BinWriter)
return err if buf.Err != nil {
return buf.Err
} }
key := storage.AppendPrefix(storage.STAsset, hash.Bytes()) key := storage.AppendPrefix(storage.STAsset, hash.Bytes())
b.Put(key, buf.Bytes()) b.Put(key, buf.Bytes())
@ -45,9 +44,8 @@ type AssetState struct {
IsFrozen bool IsFrozen bool
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (a *AssetState) DecodeBinary(r io.Reader) error { func (a *AssetState) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&a.ID) br.ReadLE(&a.ID)
br.ReadLE(&a.AssetType) br.ReadLE(&a.AssetType)
@ -59,24 +57,16 @@ func (a *AssetState) DecodeBinary(r io.Reader) error {
br.ReadLE(&a.FeeMode) br.ReadLE(&a.FeeMode)
br.ReadLE(&a.FeeAddress) br.ReadLE(&a.FeeAddress)
if br.Err != nil {
return br.Err
}
a.Owner = &keys.PublicKey{} a.Owner = &keys.PublicKey{}
if err := a.Owner.DecodeBinary(r); err != nil { a.Owner.DecodeBinary(br)
return err
}
br.ReadLE(&a.Admin) br.ReadLE(&a.Admin)
br.ReadLE(&a.Issuer) br.ReadLE(&a.Issuer)
br.ReadLE(&a.Expiration) br.ReadLE(&a.Expiration)
br.ReadLE(&a.IsFrozen) br.ReadLE(&a.IsFrozen)
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (a *AssetState) EncodeBinary(w io.Writer) error { func (a *AssetState) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteLE(a.ID) bw.WriteLE(a.ID)
bw.WriteLE(a.AssetType) bw.WriteLE(a.AssetType)
bw.WriteString(a.Name) bw.WriteString(a.Name)
@ -86,17 +76,12 @@ func (a *AssetState) EncodeBinary(w io.Writer) error {
bw.WriteLE(a.FeeMode) bw.WriteLE(a.FeeMode)
bw.WriteLE(a.FeeAddress) bw.WriteLE(a.FeeAddress)
if bw.Err != nil { a.Owner.EncodeBinary(bw)
return bw.Err
}
if err := a.Owner.EncodeBinary(w); err != nil {
return err
}
bw.WriteLE(a.Admin) bw.WriteLE(a.Admin)
bw.WriteLE(a.Issuer) bw.WriteLE(a.Issuer)
bw.WriteLE(a.Expiration) bw.WriteLE(a.Expiration)
bw.WriteLE(a.IsFrozen) bw.WriteLE(a.IsFrozen)
return bw.Err
} }
// GetName returns the asset name based on its type. // GetName returns the asset name based on its type.

View file

@ -1,11 +1,11 @@
package core package core
import ( import (
"bytes"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -26,9 +26,12 @@ func TestEncodeDecodeAssetState(t *testing.T) {
IsFrozen: false, IsFrozen: false,
} }
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
assert.Nil(t, asset.EncodeBinary(buf)) asset.EncodeBinary(buf.BinWriter)
assert.Nil(t, buf.Err)
assetDecode := &AssetState{} assetDecode := &AssetState{}
assert.Nil(t, assetDecode.DecodeBinary(buf)) r := io.NewBinReaderFromBuf(buf.Bytes())
assetDecode.DecodeBinary(r)
assert.Nil(t, r.Err)
assert.Equal(t, asset, assetDecode) assert.Equal(t, asset, assetDecode)
} }

View file

@ -1,11 +1,9 @@
package core package core
import ( import (
"bytes"
"io"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto" "github.com/CityOfZion/neo-go/pkg/crypto"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -73,22 +71,14 @@ func NewBlockFromTrimmedBytes(b []byte) (*Block, error) {
Trimmed: true, Trimmed: true,
} }
r := bytes.NewReader(b) br := io.NewBinReaderFromBuf(b)
if err := block.decodeHashableFields(r); err != nil { block.decodeHashableFields(br)
return block, err
}
br := util.BinReader{R: r}
var padding uint8 var padding uint8
br.ReadLE(&padding) br.ReadLE(&padding)
if br.Err != nil {
return block, br.Err
}
block.Script = &transaction.Witness{} block.Script = &transaction.Witness{}
if err := block.Script.DecodeBinary(r); err != nil { block.Script.DecodeBinary(br)
return block, err
}
lenTX := br.ReadVarUint() lenTX := br.ReadVarUint()
block.Transactions = make([]*transaction.Transaction, lenTX) block.Transactions = make([]*transaction.Transaction, lenTX)
@ -105,67 +95,40 @@ func NewBlockFromTrimmedBytes(b []byte) (*Block, error) {
// in storage. // in storage.
// Notice that only the hashes of the transactions are stored. // Notice that only the hashes of the transactions are stored.
func (b *Block) Trim() ([]byte, error) { func (b *Block) Trim() ([]byte, error) {
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
if err := b.encodeHashableFields(buf); err != nil { b.encodeHashableFields(buf.BinWriter)
return nil, err buf.WriteLE(uint8(1))
} b.Script.EncodeBinary(buf.BinWriter)
bw := util.BinWriter{W: buf}
bw.WriteLE(uint8(1))
if bw.Err != nil {
return nil, bw.Err
}
if err := b.Script.EncodeBinary(buf); err != nil {
return nil, err
}
bw.WriteVarUint(uint64(len(b.Transactions))) buf.WriteVarUint(uint64(len(b.Transactions)))
for _, tx := range b.Transactions { for _, tx := range b.Transactions {
bw.WriteLE(tx.Hash()) buf.WriteLE(tx.Hash())
} }
if bw.Err != nil { if buf.Err != nil {
return nil, bw.Err return nil, buf.Err
} }
return buf.Bytes(), nil return buf.Bytes(), nil
} }
// DecodeBinary decodes the block from the given reader. // DecodeBinary decodes the block from the given BinReader, implementing
func (b *Block) DecodeBinary(r io.Reader) error { // Serializable interface.
if err := b.BlockBase.DecodeBinary(r); err != nil { func (b *Block) DecodeBinary(br *io.BinReader) {
return err b.BlockBase.DecodeBinary(br)
}
br := util.BinReader{R: r}
lentx := br.ReadVarUint() lentx := br.ReadVarUint()
if br.Err != nil {
return br.Err
}
b.Transactions = make([]*transaction.Transaction, lentx) b.Transactions = make([]*transaction.Transaction, lentx)
for i := 0; i < int(lentx); i++ { for i := 0; i < int(lentx); i++ {
b.Transactions[i] = &transaction.Transaction{} b.Transactions[i] = &transaction.Transaction{}
if err := b.Transactions[i].DecodeBinary(r); err != nil { b.Transactions[i].DecodeBinary(br)
return err
}
} }
return nil
} }
// EncodeBinary encodes the block to the given writer. // EncodeBinary encodes the block to the given BinWriter, implementing
func (b *Block) EncodeBinary(w io.Writer) error { // Serializable interface.
err := b.BlockBase.EncodeBinary(w) func (b *Block) EncodeBinary(bw *io.BinWriter) {
if err != nil { b.BlockBase.EncodeBinary(bw)
return err
}
bw := util.BinWriter{W: w}
bw.WriteVarUint(uint64(len(b.Transactions))) bw.WriteVarUint(uint64(len(b.Transactions)))
if bw.Err != nil {
return err
}
for _, tx := range b.Transactions { for _, tx := range b.Transactions {
err := tx.EncodeBinary(w) tx.EncodeBinary(bw)
if err != nil {
return err
}
} }
return nil
} }

View file

@ -1,12 +1,11 @@
package core package core
import ( import (
"bytes"
"fmt" "fmt"
"io"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -59,37 +58,26 @@ func (b *BlockBase) Hash() util.Uint256 {
return b.hash return b.hash
} }
// DecodeBinary implements the payload interface. // DecodeBinary implements Serializable interface.
func (b *BlockBase) DecodeBinary(r io.Reader) error { func (b *BlockBase) DecodeBinary(br *io.BinReader) {
if err := b.decodeHashableFields(r); err != nil { b.decodeHashableFields(br)
return err
}
var padding uint8 var padding uint8
br := util.BinReader{R: r}
br.ReadLE(&padding) br.ReadLE(&padding)
if br.Err != nil {
return br.Err
}
if padding != 1 { 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{} b.Script = &transaction.Witness{}
return b.Script.DecodeBinary(r) b.Script.DecodeBinary(br)
} }
// EncodeBinary implements the Payload interface // EncodeBinary implements Serializable interface
func (b *BlockBase) EncodeBinary(w io.Writer) error { func (b *BlockBase) EncodeBinary(bw *io.BinWriter) {
if err := b.encodeHashableFields(w); err != nil { b.encodeHashableFields(bw)
return err
}
bw := util.BinWriter{W: w}
bw.WriteLE(uint8(1)) bw.WriteLE(uint8(1))
if bw.Err != nil { b.Script.EncodeBinary(bw)
return bw.Err
}
return b.Script.EncodeBinary(w)
} }
// createHash creates the hash of the block. // createHash creates the hash of the block.
@ -99,9 +87,10 @@ func (b *BlockBase) EncodeBinary(w io.Writer) error {
// Since MerkleRoot already contains the hash value of all transactions, // Since MerkleRoot already contains the hash value of all transactions,
// the modification of transaction will influence the hash value of the block. // the modification of transaction will influence the hash value of the block.
func (b *BlockBase) createHash() error { func (b *BlockBase) createHash() error {
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
if err := b.encodeHashableFields(buf); err != nil { b.encodeHashableFields(buf.BinWriter)
return err if buf.Err != nil {
return buf.Err
} }
b.hash = hash.DoubleSha256(buf.Bytes()) b.hash = hash.DoubleSha256(buf.Bytes())
@ -110,8 +99,7 @@ func (b *BlockBase) createHash() error {
// encodeHashableFields will only encode the fields used for hashing. // encodeHashableFields will only encode the fields used for hashing.
// see Hash() for more information about the fields. // see Hash() for more information about the fields.
func (b *BlockBase) encodeHashableFields(w io.Writer) error { func (b *BlockBase) encodeHashableFields(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteLE(b.Version) bw.WriteLE(b.Version)
bw.WriteLE(b.PrevHash) bw.WriteLE(b.PrevHash)
bw.WriteLE(b.MerkleRoot) bw.WriteLE(b.MerkleRoot)
@ -119,13 +107,11 @@ func (b *BlockBase) encodeHashableFields(w io.Writer) error {
bw.WriteLE(b.Index) bw.WriteLE(b.Index)
bw.WriteLE(b.ConsensusData) bw.WriteLE(b.ConsensusData)
bw.WriteLE(b.NextConsensus) bw.WriteLE(b.NextConsensus)
return bw.Err
} }
// decodeHashableFields will only decode the fields used for hashing. // decodeHashableFields will only decode the fields used for hashing.
// see Hash() for more information about the fields. // see Hash() for more information about the fields.
func (b *BlockBase) decodeHashableFields(r io.Reader) error { func (b *BlockBase) decodeHashableFields(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&b.Version) br.ReadLE(&b.Version)
br.ReadLE(&b.PrevHash) br.ReadLE(&b.PrevHash)
br.ReadLE(&b.MerkleRoot) br.ReadLE(&b.MerkleRoot)
@ -134,11 +120,9 @@ func (b *BlockBase) decodeHashableFields(r io.Reader) error {
br.ReadLE(&b.ConsensusData) br.ReadLE(&b.ConsensusData)
br.ReadLE(&b.NextConsensus) 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 // Make the hash of the block here so we dont need to do this
// again. // again.
return b.createHash() if br.Err == nil {
br.Err = b.createHash()
}
} }

View file

@ -1,12 +1,12 @@
package core package core
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto" "github.com/CityOfZion/neo-go/pkg/crypto"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -24,9 +24,9 @@ func TestDecodeBlock1(t *testing.T) {
} }
block := &Block{} block := &Block{}
if err := block.DecodeBinary(bytes.NewReader(b)); err != nil { r := io.NewBinReaderFromBuf(b)
t.Fatal(err) block.DecodeBinary(r)
} assert.Nil(t, r.Err)
assert.Equal(t, uint32(data["index"].(float64)), block.Index) assert.Equal(t, uint32(data["index"].(float64)), block.Index)
assert.Equal(t, uint32(data["version"].(float64)), block.Version) assert.Equal(t, uint32(data["version"].(float64)), block.Version)
@ -109,9 +109,9 @@ func TestBinBlockDecodeEncode(t *testing.T) {
b := Block{} b := Block{}
r := bytes.NewReader(rawtxBytes) r := io.NewBinReaderFromBuf(rawtxBytes)
err := b.DecodeBinary(r) b.DecodeBinary(r)
assert.Nil(t, err) assert.Nil(t, r.Err)
expected := map[string]bool{ // 18 trans expected := map[string]bool{ // 18 trans
"009f61f481f47eb7478e887871e4e744669d461b13d68e04250035260171d706": false, "009f61f481f47eb7478e887871e4e744669d461b13d68e04250035260171d706": false,
@ -165,10 +165,10 @@ func TestBinBlockDecodeEncode(t *testing.T) {
} }
assert.Equal(t, true, val) assert.Equal(t, true, val)
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err = b.EncodeBinary(buf) b.EncodeBinary(buf.BinWriter)
assert.Nil(t, err) assert.Nil(t, buf.Err)
assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes()))
} }
@ -185,9 +185,9 @@ func TestBlockSizeCalculation(t *testing.T) {
b := Block{} b := Block{}
r := bytes.NewReader(rawBlockBytes) r := io.NewBinReaderFromBuf(rawBlockBytes)
err := b.DecodeBinary(r) b.DecodeBinary(r)
assert.Nil(t, err) assert.Nil(t, r.Err)
expected := []struct { expected := []struct {
ID string ID string
@ -225,7 +225,7 @@ func TestBlockSizeCalculation(t *testing.T) {
txID := tx.Hash() txID := tx.Hash()
assert.Equal(t, expected[i].ID, txID.ReverseString()) 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].Type, tx.Type.String())
assert.Equal(t, expected[i].Version, int(tx.Version)) assert.Equal(t, expected[i].Version, int(tx.Version))
assert.Equal(t, expected[i].InputsLen, len(tx.Inputs)) assert.Equal(t, expected[i].InputsLen, len(tx.Inputs))
@ -250,11 +250,12 @@ func TestBlockSizeCalculation(t *testing.T) {
assert.Equal(t, "552102486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a7021024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d2102aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e2103b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c2103b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a2102ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba5542102df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e89509357ae", hex.EncodeToString(b.Script.VerificationScript)) assert.Equal(t, "552102486fd15702c4490a26703112a5cc1d0923fd697a33406bd5a1c00e0013b09a7021024c7b7fb6c310fccf1ba33b082519d82964ea93868d676662d4a59ad548df0e7d2102aaec38470f6aad0042c6e877cfd8087d2676b0f516fddd362801b9bd3936399e2103b209fd4f53a7170ea4444e0cb0a6bb6a53c2bd016926989cf85f9b0fba17a70c2103b8d9d5771d8f513aa0869b9cc8d50986403b78c6da36890638c3d46a5adce04a2102ca0e27697b9c248f6f16e085fd0061e26f44da85b58ee835c110caa5ec3ba5542102df48f60e8f3e01c48ff40b9b7f1310d7a8b2a193188befe1c2e3df740e89509357ae", hex.EncodeToString(b.Script.VerificationScript))
assert.Equal(t, "0006d3ff96e269f599eb1b5c5a527c218439e498dcc65b63794591bbcdc0516b", b.Hash().ReverseString()) assert.Equal(t, "0006d3ff96e269f599eb1b5c5a527c218439e498dcc65b63794591bbcdc0516b", b.Hash().ReverseString())
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err = b.EncodeBinary(buf) b.EncodeBinary(buf.BinWriter)
assert.Nil(t, err) assert.Nil(t, r.Err)
benc := buf.Bytes()
// test size of the block // test size of the block
assert.Equal(t, 7360, buf.Len()) assert.Equal(t, 7360, len(benc))
assert.Equal(t, rawBlock, hex.EncodeToString(buf.Bytes())) assert.Equal(t, rawBlock, hex.EncodeToString(benc))
} }

View file

@ -1,9 +1,7 @@
package core package core
import ( import (
"bytes"
"context" "context"
"encoding/binary"
"fmt" "fmt"
"math" "math"
"sync/atomic" "sync/atomic"
@ -12,6 +10,7 @@ import (
"github.com/CityOfZion/neo-go/config" "github.com/CityOfZion/neo-go/config"
"github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/storage"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/pkg/errors" "github.com/pkg/errors"
log "github.com/sirupsen/logrus" 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 { func (bc *Blockchain) processHeader(h *Header, batch storage.Batch, headerList *HeaderHashList) error {
headerList.Add(h.Hash()) headerList.Add(h.Hash())
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
for int(h.Index)-headerBatchCount >= int(bc.storedHeaderCount) { 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 return err
} }
key := storage.AppendPrefixInt(storage.IXHeaderHashList, int(bc.storedHeaderCount)) key := storage.AppendPrefixInt(storage.IXHeaderHashList, int(bc.storedHeaderCount))
@ -255,8 +254,9 @@ func (bc *Blockchain) processHeader(h *Header, batch storage.Batch, headerList *
} }
buf.Reset() buf.Reset()
if err := h.EncodeBinary(buf); err != nil { h.EncodeBinary(buf.BinWriter)
return err if buf.Err != nil {
return buf.Err
} }
key := storage.AppendPrefix(storage.DataBlock, h.Hash().BytesReverse()) key := storage.AppendPrefix(storage.DataBlock, h.Hash().BytesReverse())
@ -467,17 +467,17 @@ func (bc *Blockchain) GetTransaction(hash util.Uint256) (*transaction.Transactio
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
} }
r := bytes.NewReader(b) r := io.NewBinReaderFromBuf(b)
var height uint32 var height uint32
if err := binary.Read(r, binary.LittleEndian, &height); err != nil { r.ReadLE(&height)
return nil, 0, err
}
tx := &transaction.Transaction{} tx := &transaction.Transaction{}
if err := tx.DecodeBinary(r); err != nil { tx.DecodeBinary(r)
return nil, 0, err if r.Err != nil {
return nil, 0, r.Err
} }
return tx, height, nil return tx, height, nil
} }
@ -578,7 +578,9 @@ func (bc *Blockchain) GetAssetState(assetID util.Uint256) *AssetState {
var as *AssetState var as *AssetState
bc.Store.Seek(storage.STAsset.Bytes(), func(k, v []byte) { bc.Store.Seek(storage.STAsset.Bytes(), func(k, v []byte) {
var a AssetState var a AssetState
if err := a.DecodeBinary(bytes.NewReader(v)); err == nil && a.ID == assetID { r := io.NewBinReaderFromBuf(v)
a.DecodeBinary(r)
if r.Err == nil && a.ID == assetID {
as = &a as = &a
} }
}) })
@ -591,7 +593,9 @@ func (bc *Blockchain) GetAccountState(scriptHash util.Uint160) *AccountState {
var as *AccountState var as *AccountState
bc.Store.Seek(storage.STAccount.Bytes(), func(k, v []byte) { bc.Store.Seek(storage.STAccount.Bytes(), func(k, v []byte) {
var a AccountState var a AccountState
if err := a.DecodeBinary(bytes.NewReader(v)); err == nil && a.ScriptHash == scriptHash { r := io.NewBinReaderFromBuf(v)
a.DecodeBinary(r)
if r.Err == nil && a.ScriptHash == scriptHash {
as = &a as = &a
} }
}) })
@ -628,7 +632,7 @@ func (bc *Blockchain) References(t *transaction.Transaction) map[util.Uint256]*t
// FeePerByte returns network fee divided by the size of the transaction // FeePerByte returns network fee divided by the size of the transaction
func (bc *Blockchain) FeePerByte(t *transaction.Transaction) util.Fixed8 { 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 // NetworkFee returns network fee
@ -669,8 +673,8 @@ func (bc *Blockchain) GetMemPool() MemPool {
// Verify verifies whether a transaction is bonafide or not. // 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). // 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 { func (bc *Blockchain) Verify(t *transaction.Transaction) error {
if t.Size() > transaction.MaxTransactionSize { if io.GetVarSize(t) > transaction.MaxTransactionSize {
return errors.Errorf("invalid transaction size = %d. It shoud be less then MaxTransactionSize = %d", t.Size(), 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 { if ok := bc.verifyInputs(t); !ok {
return errors.New("invalid transaction's inputs") return errors.New("invalid transaction's inputs")
@ -921,9 +925,10 @@ func (bc *Blockchain) VerifyWitnesses(t *transaction.Transaction) error {
} }
func hashAndIndexToBytes(h util.Uint256, index uint32) []byte { func hashAndIndexToBytes(h util.Uint256, index uint32) []byte {
buf := make([]byte, 4) buf := io.NewBufBinWriter()
binary.LittleEndian.PutUint32(buf, index) buf.WriteLE(h.BytesReverse())
return append(h.BytesReverse(), buf...) buf.WriteLE(index)
return buf.Bytes()
} }
func (bc *Blockchain) secondsPerBlock() int { func (bc *Blockchain) secondsPerBlock() int {

View file

@ -6,7 +6,7 @@ import (
"github.com/CityOfZion/neo-go/config" "github.com/CityOfZion/neo-go/config"
"github.com/CityOfZion/neo-go/pkg/core/storage" "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/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@ -141,11 +141,11 @@ func TestGetTransaction(t *testing.T) {
} }
assert.Equal(t, block.Index, height) assert.Equal(t, block.Index, height)
assert.Equal(t, block.Transactions[0], tx) assert.Equal(t, block.Transactions[0], tx)
assert.Equal(t, 10, tx.Size()) assert.Equal(t, 10, io.GetVarSize(tx))
assert.Equal(t, 1, util.GetVarSize(tx.Attributes)) assert.Equal(t, 1, io.GetVarSize(tx.Attributes))
assert.Equal(t, 1, util.GetVarSize(tx.Inputs)) assert.Equal(t, 1, io.GetVarSize(tx.Inputs))
assert.Equal(t, 1, util.GetVarSize(tx.Outputs)) assert.Equal(t, 1, io.GetVarSize(tx.Outputs))
assert.Equal(t, 1, util.GetVarSize(tx.Scripts)) assert.Equal(t, 1, io.GetVarSize(tx.Scripts))
} }
func newTestChain(t *testing.T) *Blockchain { func newTestChain(t *testing.T) *Blockchain {

View file

@ -1,9 +1,9 @@
package core package core
import ( import (
"encoding/binary"
"fmt" "fmt"
"io"
"github.com/CityOfZion/neo-go/pkg/io"
) )
// Header holds the head info of a block. // Header holds the head info of a block.
@ -14,28 +14,20 @@ type Header struct {
_ uint8 _ uint8
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (h *Header) DecodeBinary(r io.Reader) error { func (h *Header) DecodeBinary(r *io.BinReader) {
if err := h.BlockBase.DecodeBinary(r); err != nil { h.BlockBase.DecodeBinary(r)
return err
}
var padding uint8 var padding uint8
if err := binary.Read(r, binary.LittleEndian, &padding); err != nil { r.ReadLE(&padding)
return err
}
if padding != 0 { 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. // EncodeBinary implements Serializable interface.
func (h *Header) EncodeBinary(w io.Writer) error { func (h *Header) EncodeBinary(w *io.BinWriter) {
if err := h.BlockBase.EncodeBinary(w); err != nil { h.BlockBase.EncodeBinary(w)
return err w.WriteLE(uint8(0))
}
return binary.Write(w, binary.LittleEndian, uint8(0))
} }

View file

@ -1,8 +1,7 @@
package core package core
import ( import (
"io" "github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "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] 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. // starting from start.
func (l *HeaderHashList) Write(w io.Writer, start, n int) error { func (l *HeaderHashList) Write(bw *io.BinWriter, start, n int) error {
bw := util.BinWriter{W: w}
bw.WriteVarUint(uint64(n)) bw.WriteVarUint(uint64(n))
hashes := l.Slice(start, start+n) hashes := l.Slice(start, start+n)
for _, hash := range hashes { for _, hash := range hashes {

View file

@ -1,13 +1,14 @@
package core package core
import ( import (
"bytes"
"testing" "testing"
"time" "time"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/stretchr/testify/assert"
) )
func TestHeaderEncodeDecode(t *testing.T) { func TestHeaderEncodeDecode(t *testing.T) {
@ -25,37 +26,20 @@ func TestHeaderEncodeDecode(t *testing.T) {
}, },
}} }}
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
if err := header.EncodeBinary(buf); err != nil { header.EncodeBinary(buf.BinWriter)
t.Fatal(err) assert.Nil(t, buf.Err)
}
headerDecode := &Header{} headerDecode := &Header{}
if err := headerDecode.DecodeBinary(buf); err != nil { r := io.NewBinReaderFromBuf(buf.Bytes())
t.Fatal(err) headerDecode.DecodeBinary(r)
} assert.Nil(t, r.Err)
if header.Version != headerDecode.Version { assert.Equal(t, header.Version, headerDecode.Version, "expected both versions to be equal")
t.Fatal("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")
if !header.PrevHash.Equals(headerDecode.PrevHash) { assert.Equal(t, header.Index, headerDecode.Index, "expected both indexes to be equal")
t.Fatal("expected both prev hashes 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")
if !header.MerkleRoot.Equals(headerDecode.MerkleRoot) { assert.Equal(t, header.Script.InvocationScript, headerDecode.Script.InvocationScript, "expected equal invocation scripts")
t.Fatal("expected both merkle roots to be equal") assert.Equal(t, header.Script.VerificationScript, headerDecode.Script.VerificationScript, "expected equal verification scripts")
}
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)
}
} }

View file

@ -1,7 +1,6 @@
package core package core
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
@ -11,6 +10,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -63,8 +63,10 @@ func getDecodedBlock(t *testing.T, i int) *Block {
} }
block := &Block{} block := &Block{}
if err := block.DecodeBinary(bytes.NewReader(b)); err != nil { r := io.NewBinReaderFromBuf(b)
t.Fatal(err) block.DecodeBinary(r)
if r.Err != nil {
t.Fatal(r.Err)
} }
return block return block

View file

@ -1,11 +1,10 @@
package core package core
import ( import (
"bytes"
"fmt" "fmt"
"io"
"github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/storage"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -21,8 +20,10 @@ func (s SpentCoins) getAndUpdate(store storage.Store, hash util.Uint256) (*Spent
spent := &SpentCoinState{} spent := &SpentCoinState{}
key := storage.AppendPrefix(storage.STSpentCoin, hash.BytesReverse()) key := storage.AppendPrefix(storage.STSpentCoin, hash.BytesReverse())
if b, err := store.Get(key); err == nil { if b, err := store.Get(key); err == nil {
if err := spent.DecodeBinary(bytes.NewReader(b)); err != nil { r := io.NewBinReaderFromBuf(b)
return nil, fmt.Errorf("failed to decode (UnspentCoinState): %s", err) spent.DecodeBinary(r)
if r.Err != nil {
return nil, fmt.Errorf("failed to decode (UnspentCoinState): %s", r.Err)
} }
} else { } else {
spent = &SpentCoinState{ spent = &SpentCoinState{
@ -35,10 +36,11 @@ func (s SpentCoins) getAndUpdate(store storage.Store, hash util.Uint256) (*Spent
} }
func (s SpentCoins) commit(b storage.Batch) error { func (s SpentCoins) commit(b storage.Batch) error {
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
for hash, state := range s { for hash, state := range s {
if err := state.EncodeBinary(buf); err != nil { state.EncodeBinary(buf.BinWriter)
return err if buf.Err != nil {
return buf.Err
} }
key := storage.AppendPrefix(storage.STSpentCoin, hash.BytesReverse()) key := storage.AppendPrefix(storage.STSpentCoin, hash.BytesReverse())
b.Put(key, buf.Bytes()) b.Put(key, buf.Bytes())
@ -65,9 +67,8 @@ func NewSpentCoinState(hash util.Uint256, height uint32) *SpentCoinState {
} }
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (s *SpentCoinState) DecodeBinary(r io.Reader) error { func (s *SpentCoinState) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&s.txHash) br.ReadLE(&s.txHash)
br.ReadLE(&s.txHeight) br.ReadLE(&s.txHeight)
@ -82,12 +83,10 @@ func (s *SpentCoinState) DecodeBinary(r io.Reader) error {
br.ReadLE(&value) br.ReadLE(&value)
s.items[key] = value s.items[key] = value
} }
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (s *SpentCoinState) EncodeBinary(w io.Writer) error { func (s *SpentCoinState) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteLE(s.txHash) bw.WriteLE(s.txHash)
bw.WriteLE(s.txHeight) bw.WriteLE(s.txHeight)
bw.WriteVarUint(uint64(len(s.items))) bw.WriteVarUint(uint64(len(s.items)))
@ -95,5 +94,4 @@ func (s *SpentCoinState) EncodeBinary(w io.Writer) error {
bw.WriteLE(k) bw.WriteLE(k)
bw.WriteLE(v) bw.WriteLE(v)
} }
return bw.Err
} }

View file

@ -1,10 +1,10 @@
package core package core
import ( import (
"bytes"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/storage"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -20,10 +20,13 @@ func TestEncodeDecodeSpentCoinState(t *testing.T) {
}, },
} }
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
assert.Nil(t, spent.EncodeBinary(buf)) spent.EncodeBinary(buf.BinWriter)
assert.Nil(t, buf.Err)
spentDecode := new(SpentCoinState) spentDecode := new(SpentCoinState)
assert.Nil(t, spentDecode.DecodeBinary(buf)) r := io.NewBinReaderFromBuf(buf.Bytes())
spentDecode.DecodeBinary(r)
assert.Nil(t, r.Err)
assert.Equal(t, spent, spentDecode) assert.Equal(t, spent, spentDecode)
} }

View file

@ -5,6 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"sort" "sort"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -84,7 +85,7 @@ func HeaderHashes(s Store) ([]util.Uint256, error) {
// the given byte array. // the given byte array.
func read2000Uint256Hashes(b []byte) ([]util.Uint256, error) { func read2000Uint256Hashes(b []byte) ([]util.Uint256, error) {
r := bytes.NewReader(b) r := bytes.NewReader(b)
br := util.BinReader{R: r} br := io.NewBinReaderFromIO(r)
lenHashes := br.ReadVarUint() lenHashes := br.ReadVarUint()
hashes := make([]util.Uint256, lenHashes) hashes := make([]util.Uint256, lenHashes)
br.ReadLE(hashes) br.ReadLE(hashes)

View file

@ -4,9 +4,8 @@ import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/io"
) )
// Attribute represents a Transaction attribute. // Attribute represents a Transaction attribute.
@ -15,9 +14,8 @@ type Attribute struct {
Data []byte Data []byte
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (attr *Attribute) DecodeBinary(r io.Reader) error { func (attr *Attribute) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&attr.Usage) br.ReadLE(&attr.Usage)
// very special case // very special case
@ -25,7 +23,7 @@ func (attr *Attribute) DecodeBinary(r io.Reader) error {
attr.Data = make([]byte, 33) attr.Data = make([]byte, 33)
attr.Data[0] = byte(attr.Usage) attr.Data[0] = byte(attr.Usage)
br.ReadLE(attr.Data[1:]) br.ReadLE(attr.Data[1:])
return br.Err return
} }
var datasize uint64 var datasize uint64
switch attr.Usage { switch attr.Usage {
@ -45,16 +43,15 @@ func (attr *Attribute) DecodeBinary(r io.Reader) error {
Remark12, Remark13, Remark14, Remark15: Remark12, Remark13, Remark14, Remark15:
datasize = br.ReadVarUint() datasize = br.ReadVarUint()
default: 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) attr.Data = make([]byte, datasize)
br.ReadLE(attr.Data) br.ReadLE(attr.Data)
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (attr *Attribute) EncodeBinary(w io.Writer) error { func (attr *Attribute) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteLE(&attr.Usage) bw.WriteLE(&attr.Usage)
switch attr.Usage { switch attr.Usage {
case ECDH02, ECDH03: case ECDH02, ECDH03:
@ -71,27 +68,8 @@ func (attr *Attribute) EncodeBinary(w io.Writer) error {
Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15: Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15:
bw.WriteLE(attr.Data) bw.WriteLE(attr.Data)
default: 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
}
// 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 += util.GetVarSize(attr.Data)
}
return sz
} }
// MarshalJSON implements the json Marschaller interface // MarshalJSON implements the json Marschaller interface

View file

@ -1,9 +1,7 @@
package transaction package transaction
import ( import (
"io" "github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util"
) )
// ClaimTX represents a claim transaction. // ClaimTX represents a claim transaction.
@ -11,43 +9,20 @@ type ClaimTX struct {
Claims []*Input Claims []*Input
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (tx *ClaimTX) DecodeBinary(r io.Reader) error { func (tx *ClaimTX) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
lenClaims := br.ReadVarUint() lenClaims := br.ReadVarUint()
if br.Err != nil {
return br.Err
}
tx.Claims = make([]*Input, lenClaims) tx.Claims = make([]*Input, lenClaims)
for i := 0; i < int(lenClaims); i++ { for i := 0; i < int(lenClaims); i++ {
tx.Claims[i] = &Input{} tx.Claims[i] = &Input{}
if err := tx.Claims[i].DecodeBinary(r); err != nil { tx.Claims[i].DecodeBinary(br)
return err
}
} }
return nil
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (tx *ClaimTX) EncodeBinary(w io.Writer) error { func (tx *ClaimTX) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteVarUint(uint64(len(tx.Claims))) bw.WriteVarUint(uint64(len(tx.Claims)))
if bw.Err != nil {
return bw.Err
}
for _, claim := range tx.Claims { for _, claim := range tx.Claims {
if err := claim.EncodeBinary(w); err != nil { claim.EncodeBinary(bw)
return err
}
} }
return nil
}
// Size returns serialized binary size for this transaction.
func (tx *ClaimTX) Size() int {
sz := util.GetVarSize(uint64(len(tx.Claims)))
for _, claim := range tx.Claims {
sz += claim.Size()
}
return sz
} }

View file

@ -1,7 +1,7 @@
package transaction package transaction
import ( import (
"io" "github.com/CityOfZion/neo-go/pkg/io"
) )
// ContractTX represents a contract transaction. // ContractTX represents a contract transaction.
@ -15,17 +15,10 @@ func NewContractTX() *Transaction {
} }
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (tx *ContractTX) DecodeBinary(r io.Reader) error { func (tx *ContractTX) DecodeBinary(r *io.BinReader) {
return nil
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (tx *ContractTX) EncodeBinary(w io.Writer) error { func (tx *ContractTX) EncodeBinary(w *io.BinWriter) {
return nil
}
// Size returns serialized binary size for this transaction.
func (tx *ContractTX) Size() int {
return 0
} }

View file

@ -1,10 +1,10 @@
package transaction package transaction
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -29,9 +29,9 @@ func TestEncodeDecodeContract(t *testing.T) {
assert.Equal(t, "bdf6cc3b9af12a7565bda80933a75ee8cef1bc771d0d58effc08e4c8b436da79", tx.Hash().ReverseString()) assert.Equal(t, "bdf6cc3b9af12a7565bda80933a75ee8cef1bc771d0d58effc08e4c8b436da79", tx.Hash().ReverseString())
// Encode // Encode
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err := tx.EncodeBinary(buf) tx.EncodeBinary(buf.BinWriter)
assert.Equal(t, nil, err) assert.Equal(t, nil, buf.Err)
assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes()))
} }

View file

@ -1,9 +1,8 @@
package transaction package transaction
import ( import (
"io"
"github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/io"
) )
// EnrollmentTX transaction represents an enrollment form, which indicates // EnrollmentTX transaction represents an enrollment form, which indicates
@ -16,18 +15,13 @@ type EnrollmentTX struct {
PublicKey *keys.PublicKey PublicKey *keys.PublicKey
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (tx *EnrollmentTX) DecodeBinary(r io.Reader) error { func (tx *EnrollmentTX) DecodeBinary(r *io.BinReader) {
tx.PublicKey = &keys.PublicKey{} tx.PublicKey = &keys.PublicKey{}
return tx.PublicKey.DecodeBinary(r) tx.PublicKey.DecodeBinary(r)
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (tx *EnrollmentTX) EncodeBinary(w io.Writer) error { func (tx *EnrollmentTX) EncodeBinary(w *io.BinWriter) {
return tx.PublicKey.EncodeBinary(w) tx.PublicKey.EncodeBinary(w)
}
// Size returns serialized binary size for this transaction.
func (tx *EnrollmentTX) Size() int {
return len(tx.PublicKey.Bytes())
} }

View file

@ -1,10 +1,10 @@
package transaction package transaction
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -16,9 +16,9 @@ func TestEncodeDecodeEnrollment(t *testing.T) {
assert.IsType(t, tx.Data, &EnrollmentTX{}) assert.IsType(t, tx.Data, &EnrollmentTX{})
assert.Equal(t, 0, int(tx.Version)) assert.Equal(t, 0, int(tx.Version))
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err := tx.EncodeBinary(buf) tx.EncodeBinary(buf.BinWriter)
assert.Equal(t, nil, err) assert.Equal(t, nil, buf.Err)
assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes()))
} }

View file

@ -1,10 +1,10 @@
package transaction package transaction
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -21,7 +21,8 @@ func decodeTransaction(rawTX string, t *testing.T) *Transaction {
b, err1 := hex.DecodeString(rawTX) b, err1 := hex.DecodeString(rawTX)
assert.Nil(t, err1) assert.Nil(t, err1)
tx := &Transaction{} tx := &Transaction{}
err2 := tx.DecodeBinary(bytes.NewReader(b)) r := io.NewBinReaderFromBuf(b)
assert.Nil(t, err2) tx.DecodeBinary(r)
assert.Nil(t, r.Err)
return tx return tx
} }

View file

@ -1,8 +1,7 @@
package transaction package transaction
import ( import (
"io" "github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -15,23 +14,14 @@ type Input struct {
PrevIndex uint16 `json:"vout"` PrevIndex uint16 `json:"vout"`
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (in *Input) DecodeBinary(r io.Reader) error { func (in *Input) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&in.PrevHash) br.ReadLE(&in.PrevHash)
br.ReadLE(&in.PrevIndex) br.ReadLE(&in.PrevIndex)
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (in *Input) EncodeBinary(w io.Writer) error { func (in *Input) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteLE(in.PrevHash) bw.WriteLE(in.PrevHash)
bw.WriteLE(in.PrevIndex) 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
} }

View file

@ -1,8 +1,7 @@
package transaction package transaction
import ( import (
"io" "github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -32,33 +31,20 @@ func NewInvocationTX(script []byte) *Transaction {
} }
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (tx *InvocationTX) DecodeBinary(r io.Reader) error { func (tx *InvocationTX) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
tx.Script = br.ReadBytes() tx.Script = br.ReadBytes()
if tx.Version >= 1 { if tx.Version >= 1 {
br.ReadLE(&tx.Gas) br.ReadLE(&tx.Gas)
} else { } else {
tx.Gas = util.Fixed8FromInt64(0) tx.Gas = util.Fixed8FromInt64(0)
} }
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (tx *InvocationTX) EncodeBinary(w io.Writer) error { func (tx *InvocationTX) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteBytes(tx.Script) bw.WriteBytes(tx.Script)
if tx.Version >= 1 { if tx.Version >= 1 {
bw.WriteLE(tx.Gas) bw.WriteLE(tx.Gas)
} }
return bw.Err
}
// Size returns serialized binary size for this transaction.
func (tx *InvocationTX) Size() int {
sz := util.GetVarSize(tx.Script)
if tx.Version >= 1 {
sz += tx.Gas.Size()
}
return sz
} }

View file

@ -1,24 +1,17 @@
package transaction package transaction
import ( import (
"io" "github.com/CityOfZion/neo-go/pkg/io"
) )
// IssueTX represents a issue transaction. // IssueTX represents a issue transaction.
// This TX has not special attributes. // This TX has not special attributes.
type IssueTX struct{} type IssueTX struct{}
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (tx *IssueTX) DecodeBinary(r io.Reader) error { func (tx *IssueTX) DecodeBinary(r *io.BinReader) {
return nil
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (tx *IssueTX) EncodeBinary(w io.Writer) error { func (tx *IssueTX) EncodeBinary(w *io.BinWriter) {
return nil
}
// Size returns serialized binary size for this transaction.
func (tx *IssueTX) Size() int {
return 0
} }

View file

@ -1,8 +1,7 @@
package transaction package transaction
import ( import (
"encoding/binary" "github.com/CityOfZion/neo-go/pkg/io"
"io"
) )
// MinerTX represents a miner transaction. // MinerTX represents a miner transaction.
@ -11,17 +10,12 @@ type MinerTX struct {
Nonce uint32 Nonce uint32
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (tx *MinerTX) DecodeBinary(r io.Reader) error { func (tx *MinerTX) DecodeBinary(r *io.BinReader) {
return binary.Read(r, binary.LittleEndian, &tx.Nonce) r.ReadLE(&tx.Nonce)
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (tx *MinerTX) EncodeBinary(w io.Writer) error { func (tx *MinerTX) EncodeBinary(w *io.BinWriter) {
return binary.Write(w, binary.LittleEndian, tx.Nonce) w.WriteLE(tx.Nonce)
}
// Size returns serialized binary size for this transaction.
func (tx *MinerTX) Size() int {
return 4 // Nonce
} }

View file

@ -1,10 +1,10 @@
package transaction package transaction
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -21,10 +21,10 @@ func TestEncodeDecodeMiner(t *testing.T) {
assert.Equal(t, "a1f219dc6be4c35eca172e65e02d4591045220221b1543f1a4b67b9e9442c264", tx.Hash().ReverseString()) assert.Equal(t, "a1f219dc6be4c35eca172e65e02d4591045220221b1543f1a4b67b9e9442c264", tx.Hash().ReverseString())
// Encode // Encode
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err := tx.EncodeBinary(buf) tx.EncodeBinary(buf.BinWriter)
assert.Equal(t, nil, err) assert.Equal(t, nil, buf.Err)
assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes()))
} }

View file

@ -2,9 +2,9 @@ package transaction
import ( import (
"encoding/json" "encoding/json"
"io"
"github.com/CityOfZion/neo-go/pkg/crypto" "github.com/CityOfZion/neo-go/pkg/crypto"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -33,27 +33,18 @@ func NewOutput(assetID util.Uint256, amount util.Fixed8, scriptHash util.Uint160
} }
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (out *Output) DecodeBinary(r io.Reader) error { func (out *Output) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&out.AssetID) br.ReadLE(&out.AssetID)
br.ReadLE(&out.Amount) br.ReadLE(&out.Amount)
br.ReadLE(&out.ScriptHash) br.ReadLE(&out.ScriptHash)
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (out *Output) EncodeBinary(w io.Writer) error { func (out *Output) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteLE(out.AssetID) bw.WriteLE(out.AssetID)
bw.WriteLE(out.Amount) bw.WriteLE(out.Amount)
bw.WriteLE(out.ScriptHash) bw.WriteLE(out.ScriptHash)
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 // MarshalJSON implements the Marshaler interface

View file

@ -1,10 +1,8 @@
package transaction package transaction
import ( import (
"io" "github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/smartcontract" "github.com/CityOfZion/neo-go/pkg/smartcontract"
"github.com/CityOfZion/neo-go/pkg/util"
) )
// PublishTX represents a publish transaction. // PublishTX represents a publish transaction.
@ -22,9 +20,8 @@ type PublishTX struct {
Version uint8 // Version of the parent struct Transaction. Used in reading NeedStorage flag. Version uint8 // Version of the parent struct Transaction. Used in reading NeedStorage flag.
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (tx *PublishTX) DecodeBinary(r io.Reader) error { func (tx *PublishTX) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
tx.Script = br.ReadBytes() tx.Script = br.ReadBytes()
lenParams := br.ReadVarUint() lenParams := br.ReadVarUint()
@ -50,13 +47,10 @@ func (tx *PublishTX) DecodeBinary(r io.Reader) error {
tx.Author = br.ReadString() tx.Author = br.ReadString()
tx.Email = br.ReadString() tx.Email = br.ReadString()
tx.Description = br.ReadString() tx.Description = br.ReadString()
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (tx *PublishTX) EncodeBinary(w io.Writer) error { func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteBytes(tx.Script) bw.WriteBytes(tx.Script)
bw.WriteVarUint(uint64(len(tx.ParamList))) bw.WriteVarUint(uint64(len(tx.ParamList)))
for _, param := range tx.ParamList { for _, param := range tx.ParamList {
@ -71,19 +65,4 @@ func (tx *PublishTX) EncodeBinary(w io.Writer) error {
bw.WriteString(tx.Author) bw.WriteString(tx.Author)
bw.WriteString(tx.Email) bw.WriteString(tx.Email)
bw.WriteString(tx.Description) bw.WriteString(tx.Description)
return bw.Err
}
// 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 += 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)
return sz
} }

View file

@ -1,9 +1,8 @@
package transaction package transaction
import ( import (
"io"
"github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -29,41 +28,27 @@ type RegisterTX struct {
Admin util.Uint160 Admin util.Uint160
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (tx *RegisterTX) DecodeBinary(r io.Reader) error { func (tx *RegisterTX) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&tx.AssetType) br.ReadLE(&tx.AssetType)
tx.Name = br.ReadString() tx.Name = br.ReadString()
br.ReadLE(&tx.Amount) br.ReadLE(&tx.Amount)
br.ReadLE(&tx.Precision) br.ReadLE(&tx.Precision)
if br.Err != nil {
return br.Err
}
tx.Owner = &keys.PublicKey{} tx.Owner = &keys.PublicKey{}
if err := tx.Owner.DecodeBinary(r); err != nil { tx.Owner.DecodeBinary(br)
return err
}
br.ReadLE(&tx.Admin) br.ReadLE(&tx.Admin)
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (tx *RegisterTX) EncodeBinary(w io.Writer) error { func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteLE(tx.AssetType) bw.WriteLE(tx.AssetType)
bw.WriteString(tx.Name) bw.WriteString(tx.Name)
bw.WriteLE(tx.Amount) bw.WriteLE(tx.Amount)
bw.WriteLE(tx.Precision) bw.WriteLE(tx.Precision)
bw.WriteLE(tx.Owner.Bytes()) bw.WriteLE(tx.Owner.Bytes())
bw.WriteLE(tx.Admin) bw.WriteLE(tx.Admin)
return bw.Err
}
// 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()
} }

View file

@ -1,12 +1,12 @@
package transaction package transaction
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/crypto" "github.com/CityOfZion/neo-go/pkg/crypto"
"github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -26,11 +26,15 @@ func TestRegisterTX(t *testing.T) {
}, },
} }
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
assert.Nil(t, tx.EncodeBinary(buf)) tx.EncodeBinary(buf.BinWriter)
assert.Nil(t, buf.Err)
b := buf.Bytes()
txDecode := &Transaction{} txDecode := &Transaction{}
assert.Nil(t, txDecode.DecodeBinary(buf)) r := io.NewBinReaderFromBuf(b)
txDecode.DecodeBinary(r)
assert.Nil(t, r.Err)
txData := tx.Data.(*RegisterTX) txData := tx.Data.(*RegisterTX)
txDecodeData := txDecode.Data.(*RegisterTX) txDecodeData := txDecode.Data.(*RegisterTX)
assert.Equal(t, txData, txDecodeData) assert.Equal(t, txData, txDecodeData)
@ -45,7 +49,9 @@ func TestDecodeRegisterTXFromRawString(t *testing.T) {
} }
tx := &Transaction{} tx := &Transaction{}
assert.Nil(t, tx.DecodeBinary(bytes.NewReader(b))) r := io.NewBinReaderFromBuf(b)
tx.DecodeBinary(r)
assert.Nil(t, r.Err)
assert.Equal(t, RegisterType, tx.Type) assert.Equal(t, RegisterType, tx.Type)
txData := tx.Data.(*RegisterTX) txData := tx.Data.(*RegisterTX)
assert.Equal(t, GoverningToken, txData.AssetType) assert.Equal(t, GoverningToken, txData.AssetType)
@ -56,10 +62,14 @@ func TestDecodeRegisterTXFromRawString(t *testing.T) {
assert.Equal(t, "Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt", crypto.AddressFromUint160(txData.Admin)) assert.Equal(t, "Abf2qMs1pzQb8kYk9RuxtUb9jtRKJVuBJt", crypto.AddressFromUint160(txData.Admin))
assert.Equal(t, "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", tx.Hash().ReverseString()) assert.Equal(t, "c56f33fc6ecfcd0c225c4ab356fee59390af8560be0e930faebe74a6daff7c9b", tx.Hash().ReverseString())
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
assert.Nil(t, tx.EncodeBinary(buf)) tx.EncodeBinary(buf.BinWriter)
assert.Nil(t, buf.Err)
benc := buf.Bytes()
txDecode := &Transaction{} txDecode := &Transaction{}
assert.Nil(t, txDecode.DecodeBinary(buf)) encreader := io.NewBinReaderFromBuf(benc)
txDecode.DecodeBinary(encreader)
assert.Nil(t, encreader.Err)
assert.Equal(t, tx, txDecode) assert.Equal(t, tx, txDecode)
} }

View file

@ -1,9 +1,7 @@
package transaction package transaction
import ( import (
"io" "github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util"
) )
// StateTX represents a state transaction. // StateTX represents a state transaction.
@ -11,44 +9,20 @@ type StateTX struct {
Descriptors []*StateDescriptor Descriptors []*StateDescriptor
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (tx *StateTX) DecodeBinary(r io.Reader) error { func (tx *StateTX) DecodeBinary(r *io.BinReader) {
br := util.BinReader{R: r} lenDesc := r.ReadVarUint()
lenDesc := br.ReadVarUint()
if br.Err != nil {
return br.Err
}
tx.Descriptors = make([]*StateDescriptor, lenDesc) tx.Descriptors = make([]*StateDescriptor, lenDesc)
for i := 0; i < int(lenDesc); i++ { for i := 0; i < int(lenDesc); i++ {
tx.Descriptors[i] = &StateDescriptor{} tx.Descriptors[i] = &StateDescriptor{}
if err := tx.Descriptors[i].DecodeBinary(r); err != nil { tx.Descriptors[i].DecodeBinary(r)
return err
}
} }
return nil
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (tx *StateTX) EncodeBinary(w io.Writer) error { func (tx *StateTX) EncodeBinary(w *io.BinWriter) {
bw := util.BinWriter{W: w} w.WriteVarUint(uint64(len(tx.Descriptors)))
bw.WriteVarUint(uint64(len(tx.Descriptors)))
if bw.Err != nil {
return bw.Err
}
for _, desc := range tx.Descriptors { for _, desc := range tx.Descriptors {
err := desc.EncodeBinary(w) desc.EncodeBinary(w)
if err != nil {
return err
}
} }
return nil
}
// Size returns serialized binary size for this transaction.
func (tx *StateTX) Size() int {
sz := util.GetVarSize(uint64(len(tx.Descriptors)))
for _, desc := range tx.Descriptors {
sz += desc.Size()
}
return sz
} }

View file

@ -1,9 +1,7 @@
package transaction package transaction
import ( import (
"io" "github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util"
) )
// DescStateType represents the type of StateDescriptor. // DescStateType represents the type of StateDescriptor.
@ -23,29 +21,19 @@ type StateDescriptor struct {
Field string Field string
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (s *StateDescriptor) DecodeBinary(r io.Reader) error { func (s *StateDescriptor) DecodeBinary(r *io.BinReader) {
br := util.BinReader{R: r} r.ReadLE(&s.Type)
br.ReadLE(&s.Type)
s.Key = br.ReadBytes() s.Key = r.ReadBytes()
s.Value = br.ReadBytes() s.Value = r.ReadBytes()
s.Field = br.ReadString() s.Field = r.ReadString()
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (s *StateDescriptor) EncodeBinary(w io.Writer) error { func (s *StateDescriptor) EncodeBinary(w *io.BinWriter) {
bw := util.BinWriter{W: w} w.WriteLE(s.Type)
bw.WriteLE(s.Type) w.WriteBytes(s.Key)
bw.WriteBytes(s.Key) w.WriteBytes(s.Value)
bw.WriteBytes(s.Value) w.WriteString(s.Field)
bw.WriteString(s.Field)
return bw.Err
}
// 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)
} }

View file

@ -1,10 +1,10 @@
package transaction package transaction
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -30,11 +30,9 @@ func TestEncodeDecodeState(t *testing.T) {
assert.Equal(t, Validator, descriptor.Type) assert.Equal(t, Validator, descriptor.Type)
// Encode // Encode
buf := io.NewBufBinWriter()
tx.EncodeBinary(buf.BinWriter)
buf := new(bytes.Buffer) assert.Equal(t, nil, buf.Err)
err := tx.EncodeBinary(buf)
assert.Equal(t, nil, err)
assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes())) assert.Equal(t, rawtx, hex.EncodeToString(buf.Bytes()))
} }

View file

@ -1,10 +1,8 @@
package transaction package transaction
import ( import (
"bytes"
"io"
"github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -76,174 +74,126 @@ func (t *Transaction) AddInput(in *Input) {
t.Inputs = append(t.Inputs, in) t.Inputs = append(t.Inputs, in)
} }
// DecodeBinary implements the payload interface. // DecodeBinary implements Serializable interface.
func (t *Transaction) DecodeBinary(r io.Reader) error { func (t *Transaction) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&t.Type) br.ReadLE(&t.Type)
br.ReadLE(&t.Version) br.ReadLE(&t.Version)
if br.Err != nil { t.decodeData(br)
return br.Err
}
if err := t.decodeData(r); err != nil {
return err
}
lenAttrs := br.ReadVarUint() lenAttrs := br.ReadVarUint()
t.Attributes = make([]*Attribute, lenAttrs) t.Attributes = make([]*Attribute, lenAttrs)
for i := 0; i < int(lenAttrs); i++ { for i := 0; i < int(lenAttrs); i++ {
t.Attributes[i] = &Attribute{} t.Attributes[i] = &Attribute{}
if err := t.Attributes[i].DecodeBinary(r); err != nil { t.Attributes[i].DecodeBinary(br)
log.Warnf("failed to decode TX %s", t.hash)
return err
}
} }
lenInputs := br.ReadVarUint() lenInputs := br.ReadVarUint()
t.Inputs = make([]*Input, lenInputs) t.Inputs = make([]*Input, lenInputs)
for i := 0; i < int(lenInputs); i++ { for i := 0; i < int(lenInputs); i++ {
t.Inputs[i] = &Input{} t.Inputs[i] = &Input{}
if err := t.Inputs[i].DecodeBinary(r); err != nil { t.Inputs[i].DecodeBinary(br)
return err
}
} }
lenOutputs := br.ReadVarUint() lenOutputs := br.ReadVarUint()
t.Outputs = make([]*Output, lenOutputs) t.Outputs = make([]*Output, lenOutputs)
for i := 0; i < int(lenOutputs); i++ { for i := 0; i < int(lenOutputs); i++ {
t.Outputs[i] = &Output{} t.Outputs[i] = &Output{}
if err := t.Outputs[i].DecodeBinary(r); err != nil { t.Outputs[i].DecodeBinary(br)
return err
}
} }
lenScripts := br.ReadVarUint() lenScripts := br.ReadVarUint()
t.Scripts = make([]*Witness, lenScripts) t.Scripts = make([]*Witness, lenScripts)
for i := 0; i < int(lenScripts); i++ { for i := 0; i < int(lenScripts); i++ {
t.Scripts[i] = &Witness{} t.Scripts[i] = &Witness{}
if err := t.Scripts[i].DecodeBinary(r); err != nil { t.Scripts[i].DecodeBinary(br)
return err
}
} }
if br.Err != nil {
return br.Err
}
// Create the hash of the transaction at decode, so we dont need // Create the hash of the transaction at decode, so we dont need
// to do it anymore. // to do it anymore.
return t.createHash() if br.Err == nil {
br.Err = t.createHash()
}
} }
func (t *Transaction) decodeData(r io.Reader) error { func (t *Transaction) decodeData(r *io.BinReader) {
switch t.Type { switch t.Type {
case InvocationType: case InvocationType:
t.Data = &InvocationTX{Version: t.Version} t.Data = &InvocationTX{Version: t.Version}
return t.Data.(*InvocationTX).DecodeBinary(r) t.Data.(*InvocationTX).DecodeBinary(r)
case MinerType: case MinerType:
t.Data = &MinerTX{} t.Data = &MinerTX{}
return t.Data.(*MinerTX).DecodeBinary(r) t.Data.(*MinerTX).DecodeBinary(r)
case ClaimType: case ClaimType:
t.Data = &ClaimTX{} t.Data = &ClaimTX{}
return t.Data.(*ClaimTX).DecodeBinary(r) t.Data.(*ClaimTX).DecodeBinary(r)
case ContractType: case ContractType:
t.Data = &ContractTX{} t.Data = &ContractTX{}
return t.Data.(*ContractTX).DecodeBinary(r) t.Data.(*ContractTX).DecodeBinary(r)
case RegisterType: case RegisterType:
t.Data = &RegisterTX{} t.Data = &RegisterTX{}
return t.Data.(*RegisterTX).DecodeBinary(r) t.Data.(*RegisterTX).DecodeBinary(r)
case IssueType: case IssueType:
t.Data = &IssueTX{} t.Data = &IssueTX{}
return t.Data.(*IssueTX).DecodeBinary(r) t.Data.(*IssueTX).DecodeBinary(r)
case EnrollmentType: case EnrollmentType:
t.Data = &EnrollmentTX{} t.Data = &EnrollmentTX{}
return t.Data.(*EnrollmentTX).DecodeBinary(r) t.Data.(*EnrollmentTX).DecodeBinary(r)
case PublishType: case PublishType:
t.Data = &PublishTX{Version: t.Version} t.Data = &PublishTX{Version: t.Version}
return t.Data.(*PublishTX).DecodeBinary(r) t.Data.(*PublishTX).DecodeBinary(r)
case StateType: case StateType:
t.Data = &StateTX{} t.Data = &StateTX{}
return t.Data.(*StateTX).DecodeBinary(r) t.Data.(*StateTX).DecodeBinary(r)
default: default:
log.Warnf("invalid TX type %s", t.Type) log.Warnf("invalid TX type %s", t.Type)
} }
return nil
} }
// EncodeBinary implements the payload interface. // EncodeBinary implements Serializable interface.
func (t *Transaction) EncodeBinary(w io.Writer) error { func (t *Transaction) EncodeBinary(bw *io.BinWriter) {
if err := t.encodeHashableFields(w); err != nil { t.encodeHashableFields(bw)
return err
}
bw := util.BinWriter{W: w}
bw.WriteVarUint(uint64(len(t.Scripts))) bw.WriteVarUint(uint64(len(t.Scripts)))
if bw.Err != nil {
return bw.Err
}
for _, s := range t.Scripts { for _, s := range t.Scripts {
if err := s.EncodeBinary(w); err != nil { s.EncodeBinary(bw)
return err
}
} }
return nil
} }
// encodeHashableFields will only encode the fields that are not used for // encodeHashableFields will only encode the fields that are not used for
// signing the transaction, which are all fields except the scripts. // signing the transaction, which are all fields except the scripts.
func (t *Transaction) encodeHashableFields(w io.Writer) error { func (t *Transaction) encodeHashableFields(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteLE(t.Type) bw.WriteLE(t.Type)
bw.WriteLE(t.Version) bw.WriteLE(t.Version)
if bw.Err != nil {
return bw.Err
}
// Underlying TXer. // Underlying TXer.
if t.Data != nil { if t.Data != nil {
if err := t.Data.EncodeBinary(w); err != nil { t.Data.EncodeBinary(bw)
return err
}
} }
// Attributes // Attributes
bw.WriteVarUint(uint64(len(t.Attributes))) bw.WriteVarUint(uint64(len(t.Attributes)))
if bw.Err != nil {
return bw.Err
}
for _, attr := range t.Attributes { for _, attr := range t.Attributes {
if err := attr.EncodeBinary(w); err != nil { attr.EncodeBinary(bw)
return err
}
} }
// Inputs // Inputs
bw.WriteVarUint(uint64(len(t.Inputs))) bw.WriteVarUint(uint64(len(t.Inputs)))
if bw.Err != nil {
return bw.Err
}
for _, in := range t.Inputs { for _, in := range t.Inputs {
if err := in.EncodeBinary(w); err != nil { in.EncodeBinary(bw)
return err
}
} }
// Outputs // Outputs
bw.WriteVarUint(uint64(len(t.Outputs))) bw.WriteVarUint(uint64(len(t.Outputs)))
if bw.Err != nil {
return bw.Err
}
for _, out := range t.Outputs { for _, out := range t.Outputs {
if err := out.EncodeBinary(w); err != nil { out.EncodeBinary(bw)
return err
}
} }
return nil
} }
// createHash creates the hash of the transaction. // createHash creates the hash of the transaction.
func (t *Transaction) createHash() error { func (t *Transaction) createHash() error {
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
if err := t.encodeHashableFields(buf); err != nil { t.encodeHashableFields(buf.BinWriter)
return err if buf.Err != nil {
return buf.Err
} }
t.hash = hash.DoubleSha256(buf.Bytes()) t.hash = hash.DoubleSha256(buf.Bytes())
@ -269,22 +219,12 @@ func (t Transaction) GroupOutputByAssetID() map[util.Uint256][]*Output {
return m return m
} }
// 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)
// uint8 + uint8 + attrSize + inputSize + outputSize + witnesSize
return 2 + attrSize + inputSize + outputSize + witnesSize + t.Data.Size()
}
// Bytes convert the transaction to []byte // Bytes convert the transaction to []byte
func (t *Transaction) Bytes() []byte { func (t *Transaction) Bytes() []byte {
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
if err := t.EncodeBinary(buf); err != nil { t.EncodeBinary(buf.BinWriter)
if buf.Err != nil {
return nil return nil
} }
return buf.Bytes() return buf.Bytes()
} }

View file

@ -1,11 +1,11 @@
package transaction package transaction
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/crypto" "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/smartcontract"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
@ -27,15 +27,15 @@ func TestWitnessEncodeDecode(t *testing.T) {
VerificationScript: verif, VerificationScript: verif,
} }
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
if err := wit.EncodeBinary(buf); err != nil { wit.EncodeBinary(buf.BinWriter)
t.Fatal(err) assert.Nil(t, buf.Err)
}
benc := buf.Bytes()
witDecode := &Witness{} witDecode := &Witness{}
if err := witDecode.DecodeBinary(buf); err != nil { encreader := io.NewBinReaderFromBuf(benc)
t.Fatal(err) witDecode.DecodeBinary(encreader)
} assert.Nil(t, encreader.Err)
t.Log(len(witDecode.VerificationScript)) t.Log(len(witDecode.VerificationScript))
t.Log(len(witDecode.InvocationScript)) t.Log(len(witDecode.InvocationScript))
@ -61,10 +61,9 @@ func TestDecodeEncodeClaimTX(t *testing.T) {
assert.Equal(t, invoc, hex.EncodeToString(tx.Scripts[0].InvocationScript)) assert.Equal(t, invoc, hex.EncodeToString(tx.Scripts[0].InvocationScript))
assert.Equal(t, verif, hex.EncodeToString(tx.Scripts[0].VerificationScript)) assert.Equal(t, verif, hex.EncodeToString(tx.Scripts[0].VerificationScript))
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
if err := tx.EncodeBinary(buf); err != nil { tx.EncodeBinary(buf.BinWriter)
t.Fatal(err) assert.Nil(t, buf.Err)
}
assert.Equal(t, rawClaimTX, hex.EncodeToString(buf.Bytes())) assert.Equal(t, rawClaimTX, hex.EncodeToString(buf.Bytes()))
hash := "2c6a45547b3898318e400e541628990a07acb00f3b9a15a8e966ae49525304da" hash := "2c6a45547b3898318e400e541628990a07acb00f3b9a15a8e966ae49525304da"
@ -90,10 +89,10 @@ func TestDecodeEncodeInvocationTX(t *testing.T) {
assert.Equal(t, invoc, hex.EncodeToString(tx.Scripts[0].InvocationScript)) assert.Equal(t, invoc, hex.EncodeToString(tx.Scripts[0].InvocationScript))
assert.Equal(t, verif, hex.EncodeToString(tx.Scripts[0].VerificationScript)) assert.Equal(t, verif, hex.EncodeToString(tx.Scripts[0].VerificationScript))
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
if err := tx.EncodeBinary(buf); err != nil { tx.EncodeBinary(buf.BinWriter)
t.Fatal(err) assert.Nil(t, buf.Err)
}
assert.Equal(t, rawInvocationTX, hex.EncodeToString(buf.Bytes())) assert.Equal(t, rawInvocationTX, hex.EncodeToString(buf.Bytes()))
} }
@ -145,8 +144,8 @@ func TestDecodePublishTX(t *testing.T) {
assert.Equal(t, expectedTX.Type, actualTX.Type) assert.Equal(t, expectedTX.Type, actualTX.Type)
assert.Equal(t, expectedTX.Version, actualTX.Version) assert.Equal(t, expectedTX.Version, actualTX.Version)
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err := actualTX.EncodeBinary(buf) actualTX.EncodeBinary(buf.BinWriter)
assert.Nil(t, err) assert.Nil(t, buf.Err)
assert.Equal(t, rawPublishTX, hex.EncodeToString(buf.Bytes())) assert.Equal(t, rawPublishTX, hex.EncodeToString(buf.Bytes()))
} }

View file

@ -1,11 +1,9 @@
package transaction package transaction
import "io" import "github.com/CityOfZion/neo-go/pkg/io"
// TXer is interface that can act as the underlying data of // TXer is interface that can act as the underlying data of
// a transaction. // a transaction.
type TXer interface { type TXer interface {
DecodeBinary(io.Reader) error io.Serializable
EncodeBinary(io.Writer) error
Size() int
} }

View file

@ -3,9 +3,9 @@ package transaction
import ( import (
"encoding/hex" "encoding/hex"
"encoding/json" "encoding/json"
"io"
"github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -15,23 +15,16 @@ type Witness struct {
VerificationScript []byte VerificationScript []byte
} }
// DecodeBinary implements the payload interface. // DecodeBinary implements Serializable interface.
func (w *Witness) DecodeBinary(r io.Reader) error { func (w *Witness) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
w.InvocationScript = br.ReadBytes() w.InvocationScript = br.ReadBytes()
w.VerificationScript = br.ReadBytes() w.VerificationScript = br.ReadBytes()
return br.Err
} }
// EncodeBinary implements the payload interface. // EncodeBinary implements Serializable interface.
func (w *Witness) EncodeBinary(writer io.Writer) error { func (w *Witness) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: writer}
bw.WriteBytes(w.InvocationScript) bw.WriteBytes(w.InvocationScript)
bw.WriteBytes(w.VerificationScript) bw.WriteBytes(w.VerificationScript)
return bw.Err
} }
// MarshalJSON implements the json marshaller interface. // MarshalJSON implements the json marshaller interface.
@ -44,11 +37,6 @@ func (w *Witness) MarshalJSON() ([]byte, error) {
return json.Marshal(data) return json.Marshal(data)
} }
// Size returns the size in bytes of the Witness.
func (w *Witness) Size() int {
return util.GetVarSize(w.InvocationScript) + util.GetVarSize(w.VerificationScript)
}
// ScriptHash returns the hash of the VerificationScript. // ScriptHash returns the hash of the VerificationScript.
func (w Witness) ScriptHash() util.Uint160 { func (w Witness) ScriptHash() util.Uint160 {
return hash.Hash160(w.VerificationScript) return hash.Hash160(w.VerificationScript)

View file

@ -1,12 +1,11 @@
package core package core
import ( import (
"bytes"
"fmt" "fmt"
"io"
"github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/storage"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -22,8 +21,10 @@ func (u UnspentCoins) getAndUpdate(s storage.Store, hash util.Uint256) (*Unspent
unspent := &UnspentCoinState{} unspent := &UnspentCoinState{}
key := storage.AppendPrefix(storage.STCoin, hash.BytesReverse()) key := storage.AppendPrefix(storage.STCoin, hash.BytesReverse())
if b, err := s.Get(key); err == nil { if b, err := s.Get(key); err == nil {
if err := unspent.DecodeBinary(bytes.NewReader(b)); err != nil { r := io.NewBinReaderFromBuf(b)
return nil, fmt.Errorf("failed to decode (UnspentCoinState): %s", err) unspent.DecodeBinary(r)
if r.Err != nil {
return nil, fmt.Errorf("failed to decode (UnspentCoinState): %s", r.Err)
} }
} else { } else {
unspent = &UnspentCoinState{ unspent = &UnspentCoinState{
@ -53,10 +54,11 @@ func NewUnspentCoinState(n int) *UnspentCoinState {
// commit writes all unspent coin states to the given Batch. // commit writes all unspent coin states to the given Batch.
func (u UnspentCoins) commit(b storage.Batch) error { func (u UnspentCoins) commit(b storage.Batch) error {
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
for hash, state := range u { for hash, state := range u {
if err := state.EncodeBinary(buf); err != nil { state.EncodeBinary(buf.BinWriter)
return err if buf.Err != nil {
return buf.Err
} }
key := storage.AppendPrefix(storage.STCoin, hash.BytesReverse()) key := storage.AppendPrefix(storage.STCoin, hash.BytesReverse())
b.Put(key, buf.Bytes()) b.Put(key, buf.Bytes())
@ -65,19 +67,16 @@ func (u UnspentCoins) commit(b storage.Batch) error {
return nil return nil
} }
// EncodeBinary encodes UnspentCoinState to the given io.Writer. // EncodeBinary encodes UnspentCoinState to the given BinWriter.
func (s *UnspentCoinState) EncodeBinary(w io.Writer) error { func (s *UnspentCoinState) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteVarUint(uint64(len(s.states))) bw.WriteVarUint(uint64(len(s.states)))
for _, state := range s.states { for _, state := range s.states {
bw.WriteLE(byte(state)) bw.WriteLE(byte(state))
} }
return bw.Err
} }
// DecodeBinary decodes UnspentCoinState from the given io.Reader. // DecodeBinary decodes UnspentCoinState from the given BinReader.
func (s *UnspentCoinState) DecodeBinary(r io.Reader) error { func (s *UnspentCoinState) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
lenStates := br.ReadVarUint() lenStates := br.ReadVarUint()
s.states = make([]CoinState, lenStates) s.states = make([]CoinState, lenStates)
for i := 0; i < int(lenStates); i++ { for i := 0; i < int(lenStates); i++ {
@ -85,7 +84,6 @@ func (s *UnspentCoinState) DecodeBinary(r io.Reader) error {
br.ReadLE(&state) br.ReadLE(&state)
s.states[i] = CoinState(state) s.states[i] = CoinState(state)
} }
return br.Err
} }
// IsDoubleSpend verifies that the input transactions are not double spent. // IsDoubleSpend verifies that the input transactions are not double spent.
@ -98,7 +96,9 @@ func IsDoubleSpend(s storage.Store, tx *transaction.Transaction) bool {
unspent := &UnspentCoinState{} unspent := &UnspentCoinState{}
key := storage.AppendPrefix(storage.STCoin, prevHash.BytesReverse()) key := storage.AppendPrefix(storage.STCoin, prevHash.BytesReverse())
if b, err := s.Get(key); err == nil { if b, err := s.Get(key); err == nil {
if err := unspent.DecodeBinary(bytes.NewReader(b)); err != nil { r := io.NewBinReaderFromBuf(b)
unspent.DecodeBinary(r)
if r.Err != nil {
return false return false
} }
if unspent == nil { if unspent == nil {

View file

@ -1,10 +1,10 @@
package core package core
import ( import (
"bytes"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/core/storage" "github.com/CityOfZion/neo-go/pkg/core/storage"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -19,10 +19,13 @@ func TestDecodeEncodeUnspentCoinState(t *testing.T) {
}, },
} }
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
assert.Nil(t, unspent.EncodeBinary(buf)) unspent.EncodeBinary(buf.BinWriter)
assert.Nil(t, buf.Err)
unspentDecode := &UnspentCoinState{} unspentDecode := &UnspentCoinState{}
assert.Nil(t, unspentDecode.DecodeBinary(buf)) r := io.NewBinReaderFromBuf(buf.Bytes())
unspentDecode.DecodeBinary(r)
assert.Nil(t, r.Err)
} }
func TestCommitUnspentCoins(t *testing.T) { func TestCommitUnspentCoins(t *testing.T) {

View file

@ -1,8 +1,6 @@
package core package core
import ( import (
"bytes"
"encoding/binary"
"time" "time"
"github.com/CityOfZion/neo-go/config" "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/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/CityOfZion/neo-go/pkg/crypto/keys" "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/smartcontract"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/CityOfZion/neo-go/pkg/vm" "github.com/CityOfZion/neo-go/pkg/vm"
@ -181,11 +180,9 @@ func headerSliceReverse(dest []*Header) {
// storeAsCurrentBlock stores the given block witch prefix // storeAsCurrentBlock stores the given block witch prefix
// SYSCurrentBlock. // SYSCurrentBlock.
func storeAsCurrentBlock(batch storage.Batch, block *Block) { func storeAsCurrentBlock(batch storage.Batch, block *Block) {
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
buf.Write(block.Hash().BytesReverse()) buf.WriteLE(block.Hash().BytesReverse())
b := make([]byte, 4) buf.WriteLE(block.Index)
binary.LittleEndian.PutUint32(b, block.Index)
buf.Write(b)
batch.Put(storage.SYSCurrentBlock.Bytes(), buf.Bytes()) 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 { func storeAsBlock(batch storage.Batch, block *Block, sysFee uint32) error {
var ( var (
key = storage.AppendPrefix(storage.DataBlock, block.Hash().BytesReverse()) key = storage.AppendPrefix(storage.DataBlock, block.Hash().BytesReverse())
buf = new(bytes.Buffer) buf = io.NewBufBinWriter()
) )
// sysFee needs to be handled somehow
b := make([]byte, 4) // buf.WriteLE(sysFee)
binary.LittleEndian.PutUint32(b, sysFee)
b, err := block.Trim() b, err := block.Trim()
if err != nil { if err != nil {
return err return err
} }
buf.Write(b) buf.WriteLE(b)
if buf.Err != nil {
return buf.Err
}
batch.Put(key, buf.Bytes()) batch.Put(key, buf.Bytes())
return nil return nil
} }
@ -211,15 +209,12 @@ func storeAsBlock(batch storage.Batch, block *Block, sysFee uint32) error {
// storeAsTransaction stores the given TX as DataTransaction. // storeAsTransaction stores the given TX as DataTransaction.
func storeAsTransaction(batch storage.Batch, tx *transaction.Transaction, index uint32) error { func storeAsTransaction(batch storage.Batch, tx *transaction.Transaction, index uint32) error {
key := storage.AppendPrefix(storage.DataTransaction, tx.Hash().BytesReverse()) key := storage.AppendPrefix(storage.DataTransaction, tx.Hash().BytesReverse())
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
if err := tx.EncodeBinary(buf); err != nil { buf.WriteLE(index)
return err tx.EncodeBinary(buf.BinWriter)
if buf.Err != nil {
return buf.Err
} }
batch.Put(key, buf.Bytes())
dest := make([]byte, buf.Len()+4)
binary.LittleEndian.PutUint32(dest[:4], index)
copy(dest[4:], buf.Bytes())
batch.Put(key, dest)
return nil return nil
} }

View file

@ -5,14 +5,13 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"crypto/x509" "crypto/x509"
"encoding/binary"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
"io"
"math/big" "math/big"
"github.com/CityOfZion/neo-go/pkg/crypto" "github.com/CityOfZion/neo-go/pkg/crypto"
"github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/pkg/errors" "github.com/pkg/errors"
) )
@ -51,8 +50,10 @@ func NewPublicKeyFromString(s string) (*PublicKey, error) {
} }
pubKey := new(PublicKey) pubKey := new(PublicKey)
if err := pubKey.DecodeBinary(bytes.NewReader(b)); err != nil { r := io.NewBinReaderFromBuf(b)
return nil, err pubKey.DecodeBinary(r)
if r.Err != nil {
return nil, r.Err
} }
return pubKey, nil return pubKey, nil
@ -122,69 +123,70 @@ func decodeCompressedY(x *big.Int, ylsb uint) (*big.Int, error) {
// DecodeBytes decodes a PublicKey from the given slice of bytes. // DecodeBytes decodes a PublicKey from the given slice of bytes.
func (p *PublicKey) DecodeBytes(data []byte) error { func (p *PublicKey) DecodeBytes(data []byte) error {
var datab []byte b := io.NewBinReaderFromBuf(data)
copy(datab, data) p.DecodeBinary(b)
b := bytes.NewBuffer(datab) return b.Err
return p.DecodeBinary(b)
} }
// DecodeBinary decodes a PublicKey from the given io.Reader. // DecodeBinary decodes a PublicKey from the given BinReader.
func (p *PublicKey) DecodeBinary(r io.Reader) error { func (p *PublicKey) DecodeBinary(r *io.BinReader) {
var prefix uint8 var prefix uint8
var x, y *big.Int var x, y *big.Int
var err error var err error
if err = binary.Read(r, binary.LittleEndian, &prefix); err != nil { r.ReadLE(&prefix)
return err if r.Err != nil {
return
} }
// Infinity // Infinity
switch prefix { switch prefix {
case 0x00: case 0x00:
// noop, initialized to nil // noop, initialized to nil
return nil return
case 0x02, 0x03: case 0x02, 0x03:
// Compressed public keys // Compressed public keys
xbytes := make([]byte, 32) xbytes := make([]byte, 32)
if _, err := io.ReadFull(r, xbytes); err != nil { r.ReadLE(xbytes)
return err if r.Err != nil {
return
} }
x = new(big.Int).SetBytes(xbytes) x = new(big.Int).SetBytes(xbytes)
ylsb := uint(prefix & 0x1) ylsb := uint(prefix & 0x1)
y, err = decodeCompressedY(x, ylsb) y, err = decodeCompressedY(x, ylsb)
if err != nil { if err != nil {
return err return
} }
case 0x04: case 0x04:
xbytes := make([]byte, 32) xbytes := make([]byte, 32)
ybytes := make([]byte, 32) ybytes := make([]byte, 32)
if _, err = io.ReadFull(r, xbytes); err != nil { r.ReadLE(xbytes)
return err r.ReadLE(ybytes)
} if r.Err != nil {
if _, err = io.ReadFull(r, ybytes); err != nil { return
return err
} }
x = new(big.Int).SetBytes(xbytes) x = new(big.Int).SetBytes(xbytes)
y = new(big.Int).SetBytes(ybytes) y = new(big.Int).SetBytes(ybytes)
default: default:
return errors.Errorf("invalid prefix %d", prefix) r.Err = errors.Errorf("invalid prefix %d", prefix)
return
} }
c := elliptic.P256() c := elliptic.P256()
cp := c.Params() cp := c.Params()
if !c.IsOnCurve(x, y) { 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 { 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 p.X, p.Y = x, y
return nil
} }
// EncodeBinary encodes a PublicKey to the given io.Writer. // EncodeBinary encodes a PublicKey to the given BinWriter.
func (p *PublicKey) EncodeBinary(w io.Writer) error { func (p *PublicKey) EncodeBinary(w *io.BinWriter) {
return binary.Write(w, binary.LittleEndian, p.Bytes()) w.WriteLE(p.Bytes())
} }
// Signature returns a NEO-specific hash of the key. // Signature returns a NEO-specific hash of the key.

View file

@ -1,21 +1,23 @@
package keys package keys
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
func TestEncodeDecodeInfinity(t *testing.T) { func TestEncodeDecodeInfinity(t *testing.T) {
key := &PublicKey{} key := &PublicKey{}
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
assert.Nil(t, key.EncodeBinary(buf)) key.EncodeBinary(buf.BinWriter)
assert.Equal(t, 1, buf.Len()) assert.Nil(t, buf.Err)
b := buf.Bytes()
assert.Equal(t, 1, len(b))
keyDecode := &PublicKey{} keyDecode := &PublicKey{}
assert.Nil(t, keyDecode.DecodeBinary(buf)) assert.Nil(t, keyDecode.DecodeBytes(b))
assert.Equal(t, []byte{0x00}, keyDecode.Bytes()) assert.Equal(t, []byte{0x00}, keyDecode.Bytes())
} }
@ -24,11 +26,13 @@ func TestEncodeDecodePublicKey(t *testing.T) {
k, err := NewPrivateKey() k, err := NewPrivateKey()
assert.Nil(t, err) assert.Nil(t, err)
p := k.PublicKey() p := k.PublicKey()
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
assert.Nil(t, p.EncodeBinary(buf)) p.EncodeBinary(buf.BinWriter)
assert.Nil(t, buf.Err)
b := buf.Bytes()
pDecode := &PublicKey{} pDecode := &PublicKey{}
assert.Nil(t, pDecode.DecodeBinary(buf)) assert.Nil(t, pDecode.DecodeBytes(b))
assert.Equal(t, p.X, pDecode.X) assert.Equal(t, p.X, pDecode.X)
} }
} }

39
pkg/io/binaryBufWriter.go Normal file
View file

@ -0,0 +1,39 @@
package io
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()
}
// 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()
}

View file

@ -1,6 +1,7 @@
package util package io
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"io" "io"
) )
@ -8,17 +9,28 @@ import (
//BinReader is a convenient wrapper around a io.Reader and err object //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 // Used to simplify error handling when reading into a struct with many fields
type BinReader struct { type BinReader struct {
R io.Reader r io.Reader
Err error 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 // ReadLE reads from the underlying io.Reader
// into the interface v in little-endian format // into the interface v in little-endian format
func (r *BinReader) ReadLE(v interface{}) { func (r *BinReader) ReadLE(v interface{}) {
if r.Err != nil { if r.Err != nil {
return 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 // ReadBE reads from the underlying io.Reader
@ -27,7 +39,7 @@ func (r *BinReader) ReadBE(v interface{}) {
if r.Err != nil { if r.Err != nil {
return 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 // ReadVarUint reads a variable-length-encoded integer from the
@ -38,21 +50,21 @@ func (r *BinReader) ReadVarUint() uint64 {
} }
var b uint8 var b uint8
r.Err = binary.Read(r.R, binary.LittleEndian, &b) r.Err = binary.Read(r.r, binary.LittleEndian, &b)
if b == 0xfd { if b == 0xfd {
var v uint16 var v uint16
r.Err = binary.Read(r.R, binary.LittleEndian, &v) r.Err = binary.Read(r.r, binary.LittleEndian, &v)
return uint64(v) return uint64(v)
} }
if b == 0xfe { if b == 0xfe {
var v uint32 var v uint32
r.Err = binary.Read(r.R, binary.LittleEndian, &v) r.Err = binary.Read(r.r, binary.LittleEndian, &v)
return uint64(v) return uint64(v)
} }
if b == 0xff { if b == 0xff {
var v uint64 var v uint64
r.Err = binary.Read(r.R, binary.LittleEndian, &v) r.Err = binary.Read(r.r, binary.LittleEndian, &v)
return v return v
} }

View file

@ -1,8 +1,7 @@
package util package io
import ( import (
"encoding/binary" "encoding/binary"
"errors"
"io" "io"
) )
@ -10,16 +9,21 @@ import (
// Used to simplify error handling when writing into a io.Writer // Used to simplify error handling when writing into a io.Writer
// from a struct with many fields // from a struct with many fields
type BinWriter struct { type BinWriter struct {
W io.Writer w io.Writer
Err error 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 // WriteLE writes into the underlying io.Writer from an object v in little-endian format
func (w *BinWriter) WriteLE(v interface{}) { func (w *BinWriter) WriteLE(v interface{}) {
if w.Err != nil { if w.Err != nil {
return 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 // WriteBE writes into the underlying io.Writer from an object v in big-endian format
@ -27,7 +31,7 @@ func (w *BinWriter) WriteBE(v interface{}) {
if w.Err != nil { if w.Err != nil {
return 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 // WriteVarUint writes a uint64 into the underlying writer using variable-length encoding
@ -36,33 +40,24 @@ func (w *BinWriter) WriteVarUint(val uint64) {
return return
} }
if val < 0 {
w.Err = errors.New("value out of range")
return
}
if w.Err != nil {
return
}
if val < 0xfd { if val < 0xfd {
w.Err = binary.Write(w.W, binary.LittleEndian, uint8(val)) w.Err = binary.Write(w.w, binary.LittleEndian, uint8(val))
return return
} }
if val < 0xFFFF { if val < 0xFFFF {
w.Err = binary.Write(w.W, binary.LittleEndian, byte(0xfd)) 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, uint16(val))
return return
} }
if val < 0xFFFFFFFF { if val < 0xFFFFFFFF {
w.Err = binary.Write(w.W, binary.LittleEndian, byte(0xfe)) 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, uint32(val))
return return
} }
w.Err = binary.Write(w.W, binary.LittleEndian, byte(0xff)) 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, val)
} }

193
pkg/io/binaryrw_test.go Normal file
View file

@ -0,0 +1,193 @@
package io
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 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"
)
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)
)
bw := NewBufBinWriter()
bw.WriteVarUint(val)
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) {
var (
val = uint64(1000)
)
bw := NewBufBinWriter()
bw.WriteVarUint(val)
assert.Nil(t, bw.Err)
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)
}
func TestWriteVarUint100000(t *testing.T) {
var (
val = uint64(100000)
)
bw := NewBufBinWriter()
bw.WriteVarUint(val)
assert.Nil(t, bw.Err)
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)
}
func TestWriteVarUint100000000000(t *testing.T) {
var (
val = uint64(1000000000000)
)
bw := NewBufBinWriter()
bw.WriteVarUint(val)
assert.Nil(t, bw.Err)
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)
}

View file

@ -1,10 +1,12 @@
package io package io
import "io" // Serializable defines the binary encoding/decoding interface. Errors are
// returned via BinReader/BinWriter Err field. These functions must have safe
// Serializable defines the binary encoding/decoding interface. // 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 { type Serializable interface {
Size() int DecodeBinary(*BinReader)
DecodeBinary(io.Reader) error EncodeBinary(*BinWriter)
EncodeBinary(io.Writer) error
} }

View file

@ -1,10 +1,8 @@
package util package io
import ( import (
"fmt" "fmt"
"reflect" "reflect"
"github.com/CityOfZion/neo-go/pkg/io"
) )
var ( var (
@ -19,6 +17,20 @@ var (
i64 int64 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 // 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) // (reference: GetVarSize(int value), https://github.com/neo-project/neo/blob/master/neo/IO/Helper.cs)
func GetVarIntSize(value int) int { func GetVarIntSize(value int) int {
@ -61,16 +73,27 @@ func GetVarSize(value interface{}) int {
reflect.Uint32, reflect.Uint32,
reflect.Uint64: reflect.Uint64:
return GetVarIntSize(int(v.Uint())) 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)
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: case reflect.Slice, reflect.Array:
valueLength := v.Len() valueLength := v.Len()
valueSize := 0 valueSize := 0
if valueLength != 0 { if valueLength != 0 {
switch reflect.ValueOf(value).Index(0).Interface().(type) { switch reflect.ValueOf(value).Index(0).Interface().(type) {
case io.Serializable: case Serializable:
for i := 0; i < valueLength; i++ { for i := 0; i < valueLength; i++ {
elem := v.Index(i).Interface().(io.Serializable) valueSize += GetVarSize(v.Index(i).Interface())
valueSize += elem.Size()
} }
case uint8, int8: case uint8, int8:
valueSize = valueLength valueSize = valueLength

View file

@ -1,27 +1,31 @@
package util package io
import ( import (
"fmt" "fmt"
"io"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
// Mock structure to test getting size of an array of serializable things // Mock structure to test getting size of an array of serializable things
type smthSerializable struct { type smthSerializable struct {
some [42]byte
} }
func (*smthSerializable) DecodeBinary(io.Reader) error { func (*smthSerializable) DecodeBinary(*BinReader) {}
return nil
func (ss *smthSerializable) EncodeBinary(bw *BinWriter) {
bw.WriteLE(ss.some)
} }
func (*smthSerializable) EncodeBinary(io.Writer) error { // Mock structure that gives error in EncodeBinary().
return nil type smthNotReallySerializable struct{}
}
func (*smthSerializable) Size() int { func (*smthNotReallySerializable) DecodeBinary(*BinReader) {}
return 42
func (*smthNotReallySerializable) EncodeBinary(bw *BinWriter) {
bw.Err = fmt.Errorf("smth bad happened in smthNotReallySerializable")
} }
func TestVarSize(t *testing.T) { func TestVarSize(t *testing.T) {
@ -87,7 +91,7 @@ func TestVarSize(t *testing.T) {
}, },
{ {
// The neo C# implementation doe not allowed this! // The neo C# implementation doe not allowed this!
Uint160{1, 2, 4, 5, 6}, util.Uint160{1, 2, 4, 5, 6},
"test_Uint160_1", "test_Uint160_1",
21, 21,
}, },
@ -153,7 +157,7 @@ func TestVarSize(t *testing.T) {
241, 241,
}, },
// The neo C# implementation doe not allowed this! // 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", "test_Uint256_1",
33, 33,
}, },
@ -184,11 +188,19 @@ func TestVarSize(t *testing.T) {
} }
} }
func TestVarSizePanic(t *testing.T) { func panicVarSize(t *testing.T, v interface{}) {
defer func() { defer func() {
r := recover() r := recover()
assert.NotNil(t, r) 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{})
} }

View file

@ -1,18 +1,15 @@
package network package network
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt"
"io"
"github.com/CityOfZion/neo-go/config" "github.com/CityOfZion/neo-go/config"
"github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/core"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto/hash" "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/network/payload"
"github.com/CityOfZion/neo-go/pkg/util"
) )
const ( const (
@ -80,12 +77,14 @@ func NewMessage(magic config.NetMode, cmd CommandType, p payload.Payload) *Messa
) )
if p != nil { if p != nil {
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
if err := p.EncodeBinary(buf); err != nil { p.EncodeBinary(buf.BinWriter)
panic(err) if buf.Err != nil {
panic(buf.Err)
} }
size = uint32(buf.Len()) b := buf.Bytes()
checksum = hash.Checksum(buf.Bytes()) size = uint32(len(b))
checksum = hash.Checksum(b)
} else { } else {
checksum = hash.Checksum([]byte{}) checksum = hash.Checksum([]byte{})
} }
@ -147,8 +146,7 @@ func (m *Message) CommandType() CommandType {
} }
// Decode a Message from the given reader. // Decode a Message from the given reader.
func (m *Message) Decode(r io.Reader) error { func (m *Message) Decode(br *io.BinReader) error {
br := util.BinReader{R: r}
br.ReadLE(&m.Magic) br.ReadLE(&m.Magic)
br.ReadLE(&m.Command) br.ReadLE(&m.Command)
br.ReadLE(&m.Length) br.ReadLE(&m.Length)
@ -160,69 +158,45 @@ func (m *Message) Decode(r io.Reader) error {
if m.Length == 0 { if m.Length == 0 {
return nil return nil
} }
return m.decodePayload(r) return m.decodePayload(br)
} }
func (m *Message) decodePayload(r io.Reader) error { func (m *Message) decodePayload(br *io.BinReader) error {
buf := new(bytes.Buffer) buf := make([]byte, m.Length)
n, err := io.CopyN(buf, r, int64(m.Length)) br.ReadLE(buf)
if err != nil { if br.Err != nil {
return err 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. // Compare the checksum of the payload.
if !compareChecksum(m.Checksum, buf.Bytes()) { if !compareChecksum(m.Checksum, buf) {
return errChecksumMismatch return errChecksumMismatch
} }
r := io.NewBinReaderFromBuf(buf)
var p payload.Payload var p payload.Payload
switch m.CommandType() { switch m.CommandType() {
case CMDVersion: case CMDVersion:
p = &payload.Version{} p = &payload.Version{}
if err := p.DecodeBinary(buf); err != nil {
return err
}
case CMDInv, CMDGetData: case CMDInv, CMDGetData:
p = &payload.Inventory{} p = &payload.Inventory{}
if err := p.DecodeBinary(buf); err != nil {
return err
}
case CMDAddr: case CMDAddr:
p = &payload.AddressList{} p = &payload.AddressList{}
if err := p.DecodeBinary(buf); err != nil {
return err
}
case CMDBlock: case CMDBlock:
p = &core.Block{} p = &core.Block{}
if err := p.DecodeBinary(buf); err != nil {
return err
}
case CMDGetBlocks: case CMDGetBlocks:
fallthrough fallthrough
case CMDGetHeaders: case CMDGetHeaders:
p = &payload.GetBlocks{} p = &payload.GetBlocks{}
if err := p.DecodeBinary(buf); err != nil {
return err
}
case CMDHeaders: case CMDHeaders:
p = &payload.Headers{} p = &payload.Headers{}
if err := p.DecodeBinary(buf); err != nil {
return err
}
case CMDTX: case CMDTX:
p = &transaction.Transaction{} p = &transaction.Transaction{}
if err := p.DecodeBinary(buf); err != nil {
return err
}
case CMDMerkleBlock: case CMDMerkleBlock:
p = &payload.MerkleBlock{} p = &payload.MerkleBlock{}
if err := p.DecodeBinary(buf); err != nil { }
return err p.DecodeBinary(r)
} if r.Err != nil {
return r.Err
} }
m.Payload = p m.Payload = p
@ -230,19 +204,19 @@ func (m *Message) decodePayload(r io.Reader) error {
return nil return nil
} }
// Encode a Message to any given io.Writer. // Encode a Message to any given BinWriter.
func (m *Message) Encode(w io.Writer) error { func (m *Message) Encode(br *io.BinWriter) error {
br := util.BinWriter{W: w}
br.WriteLE(m.Magic) br.WriteLE(m.Magic)
br.WriteLE(m.Command) br.WriteLE(m.Command)
br.WriteLE(m.Length) br.WriteLE(m.Length)
br.WriteLE(m.Checksum) br.WriteLE(m.Checksum)
if m.Payload != nil {
m.Payload.EncodeBinary(br)
}
if br.Err != nil { if br.Err != nil {
return br.Err return br.Err
} }
if m.Payload != nil {
return m.Payload.EncodeBinary(w)
}
return nil return nil
} }

View file

@ -1,12 +1,11 @@
package payload package payload
import ( import (
"io"
"net" "net"
"strconv" "strconv"
"time" "time"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/io"
) )
// AddressAndTime payload. // AddressAndTime payload.
@ -28,24 +27,20 @@ func NewAddressAndTime(e *net.TCPAddr, t time.Time) *AddressAndTime {
return &aat return &aat
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (p *AddressAndTime) DecodeBinary(r io.Reader) error { func (p *AddressAndTime) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&p.Timestamp) br.ReadLE(&p.Timestamp)
br.ReadLE(&p.Services) br.ReadLE(&p.Services)
br.ReadBE(&p.IP) br.ReadBE(&p.IP)
br.ReadBE(&p.Port) br.ReadBE(&p.Port)
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (p *AddressAndTime) EncodeBinary(w io.Writer) error { func (p *AddressAndTime) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteLE(p.Timestamp) bw.WriteLE(p.Timestamp)
bw.WriteLE(p.Services) bw.WriteLE(p.Services)
bw.WriteBE(p.IP) bw.WriteBE(p.IP)
bw.WriteBE(p.Port) bw.WriteBE(p.Port)
return bw.Err
} }
// IPPortString makes a string from IP and port specified. // IPPortString makes a string from IP and port specified.
@ -70,35 +65,21 @@ func NewAddressList(n int) *AddressList {
return &alist return &alist
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (p *AddressList) DecodeBinary(r io.Reader) error { func (p *AddressList) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
listLen := br.ReadVarUint() listLen := br.ReadVarUint()
if br.Err != nil {
return br.Err
}
p.Addrs = make([]*AddressAndTime, listLen) p.Addrs = make([]*AddressAndTime, listLen)
for i := 0; i < int(listLen); i++ { for i := 0; i < int(listLen); i++ {
p.Addrs[i] = &AddressAndTime{} p.Addrs[i] = &AddressAndTime{}
if err := p.Addrs[i].DecodeBinary(r); err != nil { p.Addrs[i].DecodeBinary(br)
return err
}
} }
return nil
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (p *AddressList) EncodeBinary(w io.Writer) error { func (p *AddressList) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteVarUint(uint64(len(p.Addrs))) bw.WriteVarUint(uint64(len(p.Addrs)))
if bw.Err != nil {
return bw.Err
}
for _, addr := range p.Addrs { for _, addr := range p.Addrs {
if err := addr.EncodeBinary(w); err != nil { addr.EncodeBinary(bw)
return err
}
} }
return nil
} }

View file

@ -1,12 +1,12 @@
package payload package payload
import ( import (
"bytes"
"fmt" "fmt"
"net" "net"
"testing" "testing"
"time" "time"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -15,7 +15,7 @@ func TestEncodeDecodeAddress(t *testing.T) {
e, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:2000") e, _ = net.ResolveTCPAddr("tcp", "127.0.0.1:2000")
ts = time.Now() ts = time.Now()
addr = NewAddressAndTime(e, ts) addr = NewAddressAndTime(e, ts)
buf = new(bytes.Buffer) buf = io.NewBufBinWriter()
) )
assert.Equal(t, ts.UTC().Unix(), int64(addr.Timestamp)) assert.Equal(t, ts.UTC().Unix(), int64(addr.Timestamp))
@ -23,12 +23,14 @@ func TestEncodeDecodeAddress(t *testing.T) {
copy(aatip, addr.IP[:]) copy(aatip, addr.IP[:])
assert.Equal(t, e.IP, aatip) assert.Equal(t, e.IP, aatip)
assert.Equal(t, e.Port, int(addr.Port)) assert.Equal(t, e.Port, int(addr.Port))
err := addr.EncodeBinary(buf) addr.EncodeBinary(buf.BinWriter)
assert.Nil(t, err) assert.Nil(t, buf.Err)
b := buf.Bytes()
r := io.NewBinReaderFromBuf(b)
addrDecode := &AddressAndTime{} addrDecode := &AddressAndTime{}
err = addrDecode.DecodeBinary(buf) addrDecode.DecodeBinary(r)
assert.Nil(t, err) assert.Nil(t, r.Err)
assert.Equal(t, addr, addrDecode) assert.Equal(t, addr, addrDecode)
} }
@ -41,13 +43,15 @@ func TestEncodeDecodeAddressList(t *testing.T) {
addrList.Addrs[i] = NewAddressAndTime(e, time.Now()) addrList.Addrs[i] = NewAddressAndTime(e, time.Now())
} }
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err := addrList.EncodeBinary(buf) addrList.EncodeBinary(buf.BinWriter)
assert.Nil(t, err) assert.Nil(t, buf.Err)
b := buf.Bytes()
r := io.NewBinReaderFromBuf(b)
addrListDecode := &AddressList{} addrListDecode := &AddressList{}
err = addrListDecode.DecodeBinary(buf) addrListDecode.DecodeBinary(r)
assert.Nil(t, err) assert.Nil(t, r.Err)
assert.Equal(t, addrList, addrListDecode) assert.Equal(t, addrList, addrListDecode)
} }

View file

@ -1,8 +1,7 @@
package payload package payload
import ( import (
"io" "github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -22,25 +21,18 @@ func NewGetBlocks(start []util.Uint256, stop util.Uint256) *GetBlocks {
} }
} }
// DecodeBinary implements the payload interface. // DecodeBinary implements Serializable interface.
func (p *GetBlocks) DecodeBinary(r io.Reader) error { func (p *GetBlocks) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
lenStart := br.ReadVarUint() lenStart := br.ReadVarUint()
p.HashStart = make([]util.Uint256, lenStart) p.HashStart = make([]util.Uint256, lenStart)
br.ReadLE(&p.HashStart) br.ReadLE(&p.HashStart)
br.ReadLE(&p.HashStop) br.ReadLE(&p.HashStop)
return br.Err
} }
// EncodeBinary implements the payload interface. // EncodeBinary implements Serializable interface.
func (p *GetBlocks) EncodeBinary(w io.Writer) error { func (p *GetBlocks) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteVarUint(uint64(len(p.HashStart))) bw.WriteVarUint(uint64(len(p.HashStart)))
bw.WriteLE(p.HashStart) bw.WriteLE(p.HashStart)
bw.WriteLE(p.HashStop) bw.WriteLE(p.HashStop)
return bw.Err
} }
// Size implements the payload interface.
func (p *GetBlocks) Size() uint32 { return 0 }

View file

@ -1,10 +1,10 @@
package payload package payload
import ( import (
"bytes"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -18,13 +18,15 @@ func TestGetBlockEncodeDecode(t *testing.T) {
} }
p := NewGetBlocks(start, util.Uint256{}) p := NewGetBlocks(start, util.Uint256{})
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err := p.EncodeBinary(buf) p.EncodeBinary(buf.BinWriter)
assert.Nil(t, err) assert.Nil(t, buf.Err)
b := buf.Bytes()
r := io.NewBinReaderFromBuf(b)
pDecode := &GetBlocks{} pDecode := &GetBlocks{}
err = pDecode.DecodeBinary(buf) pDecode.DecodeBinary(r)
assert.Nil(t, err) assert.Nil(t, r.Err)
assert.Equal(t, p, pDecode) assert.Equal(t, p, pDecode)
} }
@ -39,12 +41,14 @@ func TestGetBlockEncodeDecodeWithHashStop(t *testing.T) {
stop = hash.Sha256([]byte("e")) stop = hash.Sha256([]byte("e"))
) )
p := NewGetBlocks(start, stop) p := NewGetBlocks(start, stop)
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err := p.EncodeBinary(buf) p.EncodeBinary(buf.BinWriter)
assert.Nil(t, err) assert.Nil(t, buf.Err)
b := buf.Bytes()
r := io.NewBinReaderFromBuf(b)
pDecode := &GetBlocks{} pDecode := &GetBlocks{}
err = pDecode.DecodeBinary(buf) pDecode.DecodeBinary(r)
assert.Nil(t, err) assert.Nil(t, r.Err)
assert.Equal(t, p, pDecode) assert.Equal(t, p, pDecode)
} }

View file

@ -1,10 +1,8 @@
package payload package payload
import ( import (
"io"
"github.com/CityOfZion/neo-go/pkg/core" "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" log "github.com/sirupsen/logrus"
) )
@ -18,13 +16,10 @@ const (
maxHeadersAllowed = 2000 maxHeadersAllowed = 2000
) )
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (p *Headers) DecodeBinary(r io.Reader) error { func (p *Headers) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
lenHeaders := br.ReadVarUint() lenHeaders := br.ReadVarUint()
if br.Err != nil {
return br.Err
}
// C# node does it silently // C# node does it silently
if lenHeaders > maxHeadersAllowed { if lenHeaders > maxHeadersAllowed {
log.Warnf("received %d headers, capping to %d", lenHeaders, maxHeadersAllowed) log.Warnf("received %d headers, capping to %d", lenHeaders, maxHeadersAllowed)
@ -35,27 +30,16 @@ func (p *Headers) DecodeBinary(r io.Reader) error {
for i := 0; i < int(lenHeaders); i++ { for i := 0; i < int(lenHeaders); i++ {
header := &core.Header{} header := &core.Header{}
if err := header.DecodeBinary(r); err != nil { header.DecodeBinary(br)
return err
}
p.Hdrs[i] = header p.Hdrs[i] = header
} }
return nil
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (p *Headers) EncodeBinary(w io.Writer) error { func (p *Headers) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteVarUint(uint64(len(p.Hdrs))) bw.WriteVarUint(uint64(len(p.Hdrs)))
if bw.Err != nil {
return bw.Err
}
for _, header := range p.Hdrs { for _, header := range p.Hdrs {
if err := header.EncodeBinary(w); err != nil { header.EncodeBinary(bw)
return err
}
} }
return nil
} }

View file

@ -1,12 +1,12 @@
package payload package payload
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/core"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -41,13 +41,15 @@ func TestHeadersEncodeDecode(t *testing.T) {
}}, }},
}} }}
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err := headers.EncodeBinary(buf) headers.EncodeBinary(buf.BinWriter)
assert.Nil(t, err) assert.Nil(t, buf.Err)
b := buf.Bytes()
r := io.NewBinReaderFromBuf(b)
headersDecode := &Headers{} headersDecode := &Headers{}
err = headersDecode.DecodeBinary(buf) headersDecode.DecodeBinary(r)
assert.Nil(t, err) assert.Nil(t, r.Err)
for i := 0; i < len(headers.Hdrs); i++ { for i := 0; i < len(headers.Hdrs); i++ {
assert.Equal(t, headers.Hdrs[i].Version, headersDecode.Hdrs[i].Version) assert.Equal(t, headers.Hdrs[i].Version, headersDecode.Hdrs[i].Version)
@ -63,10 +65,10 @@ func TestBinEncodeDecode(t *testing.T) {
rawBlockBytes, _ := hex.DecodeString(rawBlockHeaders) rawBlockBytes, _ := hex.DecodeString(rawBlockHeaders)
r := bytes.NewReader(rawBlockBytes) r := io.NewBinReaderFromBuf(rawBlockBytes)
err := headerMsg.DecodeBinary(r) headerMsg.DecodeBinary(r)
assert.Nil(t, err) assert.Nil(t, r.Err)
assert.Equal(t, 1, len(headerMsg.Hdrs)) assert.Equal(t, 1, len(headerMsg.Hdrs))
header := headerMsg.Hdrs[0] header := headerMsg.Hdrs[0]
@ -74,9 +76,9 @@ func TestBinEncodeDecode(t *testing.T) {
assert.Equal(t, "f3c4ec44c07eccbda974f1ee34bc6654ab6d3f22cd89c2e5c593a16d6cc7e6e8", hash.ReverseString()) assert.Equal(t, "f3c4ec44c07eccbda974f1ee34bc6654ab6d3f22cd89c2e5c593a16d6cc7e6e8", hash.ReverseString())
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err = headerMsg.EncodeBinary(buf) headerMsg.EncodeBinary(buf.BinWriter)
assert.Equal(t, nil, err) assert.Equal(t, nil, buf.Err)
assert.Equal(t, hex.EncodeToString(rawBlockBytes), hex.EncodeToString(buf.Bytes())) assert.Equal(t, hex.EncodeToString(rawBlockBytes), hex.EncodeToString(buf.Bytes()))
} }

View file

@ -1,8 +1,7 @@
package payload package payload
import ( import (
"io" "github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -55,9 +54,8 @@ func NewInventory(typ InventoryType, hashes []util.Uint256) *Inventory {
} }
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (p *Inventory) DecodeBinary(r io.Reader) error { func (p *Inventory) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&p.Type) br.ReadLE(&p.Type)
listLen := br.ReadVarUint() listLen := br.ReadVarUint()
@ -65,13 +63,10 @@ func (p *Inventory) DecodeBinary(r io.Reader) error {
for i := 0; i < int(listLen); i++ { for i := 0; i < int(listLen); i++ {
br.ReadLE(&p.Hashes[i]) br.ReadLE(&p.Hashes[i])
} }
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (p *Inventory) EncodeBinary(w io.Writer) error { func (p *Inventory) EncodeBinary(bw *io.BinWriter) {
bw := util.BinWriter{W: w}
bw.WriteLE(p.Type) bw.WriteLE(p.Type)
listLen := len(p.Hashes) listLen := len(p.Hashes)
@ -79,6 +74,4 @@ func (p *Inventory) EncodeBinary(w io.Writer) error {
for i := 0; i < listLen; i++ { for i := 0; i < listLen; i++ {
bw.WriteLE(p.Hashes[i]) bw.WriteLE(p.Hashes[i])
} }
return bw.Err
} }

View file

@ -1,10 +1,10 @@
package payload package payload
import ( import (
"bytes"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/crypto/hash" "github.com/CityOfZion/neo-go/pkg/crypto/hash"
"github.com/CityOfZion/neo-go/pkg/io"
. "github.com/CityOfZion/neo-go/pkg/util" . "github.com/CityOfZion/neo-go/pkg/util"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -16,22 +16,24 @@ func TestInventoryEncodeDecode(t *testing.T) {
} }
inv := NewInventory(BlockType, hashes) inv := NewInventory(BlockType, hashes)
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err := inv.EncodeBinary(buf) inv.EncodeBinary(buf.BinWriter)
assert.Nil(t, err) assert.Nil(t, buf.Err)
b := buf.Bytes()
r := io.NewBinReaderFromBuf(b)
invDecode := &Inventory{} invDecode := &Inventory{}
err = invDecode.DecodeBinary(buf) invDecode.DecodeBinary(r)
assert.Nil(t, err) assert.Nil(t, r.Err)
assert.Equal(t, inv, invDecode) assert.Equal(t, inv, invDecode)
} }
func TestEmptyInv(t *testing.T) { func TestEmptyInv(t *testing.T) {
msgInv := NewInventory(TXType, []Uint256{}) msgInv := NewInventory(TXType, []Uint256{})
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err := msgInv.EncodeBinary(buf) msgInv.EncodeBinary(buf.BinWriter)
assert.Nil(t, err) assert.Nil(t, buf.Err)
assert.Equal(t, []byte{byte(TXType), 0}, buf.Bytes()) assert.Equal(t, []byte{byte(TXType), 0}, buf.Bytes())
assert.Equal(t, 0, len(msgInv.Hashes)) assert.Equal(t, 0, len(msgInv.Hashes))
} }

View file

@ -1,9 +1,8 @@
package payload package payload
import ( import (
"io"
"github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/core"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -15,13 +14,10 @@ type MerkleBlock struct {
Flags []byte Flags []byte
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (m *MerkleBlock) DecodeBinary(r io.Reader) error { func (m *MerkleBlock) DecodeBinary(br *io.BinReader) {
m.BlockBase = &core.BlockBase{} m.BlockBase = &core.BlockBase{}
if err := m.BlockBase.DecodeBinary(r); err != nil { m.BlockBase.DecodeBinary(br)
return err
}
br := util.BinReader{R: r}
m.TxCount = int(br.ReadVarUint()) m.TxCount = int(br.ReadVarUint())
n := br.ReadVarUint() n := br.ReadVarUint()
@ -30,10 +26,17 @@ func (m *MerkleBlock) DecodeBinary(r io.Reader) error {
br.ReadLE(&m.Hashes[i]) br.ReadLE(&m.Hashes[i])
} }
m.Flags = br.ReadBytes() m.Flags = br.ReadBytes()
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (m *MerkleBlock) EncodeBinary(w io.Writer) error { func (m *MerkleBlock) EncodeBinary(bw *io.BinWriter) {
return nil 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)
} }

View file

@ -1,11 +1,10 @@
package payload package payload
import "io" import "github.com/CityOfZion/neo-go/pkg/io"
// Payload is anything that can be binary encoded/decoded. // Payload is anything that can be binary encoded/decoded.
type Payload interface { type Payload interface {
EncodeBinary(io.Writer) error io.Serializable
DecodeBinary(io.Reader) error
} }
// NullPayload is a dummy payload with no fields. // NullPayload is a dummy payload with no fields.
@ -17,12 +16,8 @@ func NewNullPayload() *NullPayload {
return &NullPayload{} return &NullPayload{}
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (p *NullPayload) DecodeBinary(r io.Reader) error { func (p *NullPayload) DecodeBinary(r *io.BinReader) {}
return nil
}
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (p *NullPayload) EncodeBinary(r io.Writer) error { func (p *NullPayload) EncodeBinary(w *io.BinWriter) {}
return nil
}

View file

@ -1,10 +1,9 @@
package payload package payload
import ( import (
"io"
"time" "time"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/io"
) )
// Size of the payload not counting UserAgent encoding (which is at least 1 byte // Size of the payload not counting UserAgent encoding (which is at least 1 byte
@ -54,9 +53,8 @@ func NewVersion(id uint32, p uint16, ua string, h uint32, r bool) *Version {
} }
} }
// DecodeBinary implements the Payload interface. // DecodeBinary implements Serializable interface.
func (p *Version) DecodeBinary(r io.Reader) error { func (p *Version) DecodeBinary(br *io.BinReader) {
br := util.BinReader{R: r}
br.ReadLE(&p.Version) br.ReadLE(&p.Version)
br.ReadLE(&p.Services) br.ReadLE(&p.Services)
br.ReadLE(&p.Timestamp) br.ReadLE(&p.Timestamp)
@ -65,12 +63,10 @@ func (p *Version) DecodeBinary(r io.Reader) error {
p.UserAgent = br.ReadBytes() p.UserAgent = br.ReadBytes()
br.ReadLE(&p.StartHeight) br.ReadLE(&p.StartHeight)
br.ReadLE(&p.Relay) br.ReadLE(&p.Relay)
return br.Err
} }
// EncodeBinary implements the Payload interface. // EncodeBinary implements Serializable interface.
func (p *Version) EncodeBinary(w io.Writer) error { func (p *Version) EncodeBinary(br *io.BinWriter) {
br := util.BinWriter{W: w}
br.WriteLE(p.Version) br.WriteLE(p.Version)
br.WriteLE(p.Services) br.WriteLE(p.Services)
br.WriteLE(p.Timestamp) br.WriteLE(p.Timestamp)
@ -80,10 +76,4 @@ func (p *Version) EncodeBinary(w io.Writer) error {
br.WriteBytes(p.UserAgent) br.WriteBytes(p.UserAgent)
br.WriteLE(p.StartHeight) br.WriteLE(p.StartHeight)
br.WriteLE(&p.Relay) br.WriteLE(&p.Relay)
return br.Err
}
// Size implements the payloader interface.
func (p *Version) Size() uint32 {
return uint32(minVersionSize + util.GetVarSize(p.UserAgent))
} }

View file

@ -1,9 +1,9 @@
package payload package payload
import ( import (
"bytes"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -16,14 +16,16 @@ func TestVersionEncodeDecode(t *testing.T) {
version := NewVersion(id, port, useragent, height, relay) version := NewVersion(id, port, useragent, height, relay)
buf := new(bytes.Buffer) buf := io.NewBufBinWriter()
err := version.EncodeBinary(buf) version.EncodeBinary(buf.BinWriter)
assert.Nil(t, err) assert.Nil(t, buf.Err)
assert.Equal(t, int(version.Size()), buf.Len()) b := buf.Bytes()
assert.Equal(t, io.GetVarSize(version), len(b))
r := io.NewBinReaderFromBuf(b)
versionDecoded := &Version{} versionDecoded := &Version{}
err = versionDecoded.DecodeBinary(buf) versionDecoded.DecodeBinary(r)
assert.Nil(t, err) assert.Nil(t, r.Err)
assert.Equal(t, versionDecoded.Nonce, id) assert.Equal(t, versionDecoded.Nonce, id)
assert.Equal(t, versionDecoded.Port, port) assert.Equal(t, versionDecoded.Port, port)
assert.Equal(t, versionDecoded.UserAgent, []byte(useragent)) assert.Equal(t, versionDecoded.UserAgent, []byte(useragent))

View file

@ -6,6 +6,7 @@ import (
"net" "net"
"sync" "sync"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/network/payload" "github.com/CityOfZion/neo-go/pkg/network/payload"
) )
@ -68,7 +69,8 @@ func (p *TCPPeer) writeMsg(msg *Message) error {
case err := <-p.done: case err := <-p.done:
return err return err
default: default:
return msg.Encode(p.conn) w := io.NewBinWriterFromIO(p.conn)
return msg.Encode(w)
} }
} }

View file

@ -5,6 +5,7 @@ import (
"regexp" "regexp"
"time" "time"
"github.com/CityOfZion/neo-go/pkg/io"
log "github.com/sirupsen/logrus" log "github.com/sirupsen/logrus"
) )
@ -77,9 +78,10 @@ func (t *TCPTransport) handleConn(conn net.Conn) {
t.server.register <- p t.server.register <- p
r := io.NewBinReaderFromIO(p.conn)
for { for {
msg := &Message{} msg := &Message{}
if err = msg.Decode(p.conn); err != nil { if err = msg.Decode(r); err != nil {
break break
} }
if err = t.server.handleMessage(p, msg); err != nil { if err = t.server.handleMessage(p, msg); err != nil {

View file

@ -1,10 +1,10 @@
package rpc package rpc
import ( import (
"bytes"
"encoding/hex" "encoding/hex"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "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/smartcontract"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
"github.com/pkg/errors" "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) { func (c *Client) SendToAddress(asset util.Uint256, address string, amount util.Fixed8) (*SendToAddressResponse, error) {
var ( var (
err error err error
buf = &bytes.Buffer{} buf = io.NewBufBinWriter()
rawTx *transaction.Transaction rawTx *transaction.Transaction
rawTxStr string rawTxStr string
txParams = ContractTxParams{ txParams = ContractTxParams{
@ -130,8 +130,9 @@ func (c *Client) SendToAddress(asset util.Uint256, address string, amount util.F
if rawTx, err = CreateRawContractTransaction(txParams); err != nil { if rawTx, err = CreateRawContractTransaction(txParams); err != nil {
return nil, errors.Wrap(err, "failed to create raw transaction for `sendtoaddress`") return nil, errors.Wrap(err, "failed to create raw transaction for `sendtoaddress`")
} }
if err = rawTx.EncodeBinary(buf); err != nil { rawTx.EncodeBinary(buf.BinWriter)
return nil, errors.Wrap(err, "failed to encode raw transaction to binary for `sendtoaddress`") if buf.Err != nil {
return nil, errors.Wrap(buf.Err, "failed to encode raw transaction to binary for `sendtoaddress`")
} }
rawTxStr = hex.EncodeToString(buf.Bytes()) rawTxStr = hex.EncodeToString(buf.Bytes())
if resp, err = c.sendRawTransaction(rawTxStr); err != nil { if resp, err = c.sendRawTransaction(rawTxStr); err != nil {

View file

@ -1,7 +1,6 @@
package rpc package rpc
import ( import (
"bytes"
"context" "context"
"encoding/hex" "encoding/hex"
"fmt" "fmt"
@ -11,6 +10,7 @@ import (
"github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/core"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto" "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/network"
"github.com/CityOfZion/neo-go/pkg/rpc/result" "github.com/CityOfZion/neo-go/pkg/rpc/result"
"github.com/CityOfZion/neo-go/pkg/rpc/wrappers" "github.com/CityOfZion/neo-go/pkg/rpc/wrappers"
@ -294,29 +294,29 @@ func (s *Server) sendrawtransaction(reqParams Params) (interface{}, error) {
} else if byteTx, err := hex.DecodeString(param.StringVal); err != nil { } else if byteTx, err := hex.DecodeString(param.StringVal); err != nil {
resultsErr = errInvalidParams resultsErr = errInvalidParams
} else { } else {
r := bytes.NewReader(byteTx) r := io.NewBinReaderFromBuf(byteTx)
tx := &transaction.Transaction{} tx := &transaction.Transaction{}
err = tx.DecodeBinary(r) tx.DecodeBinary(r)
if err != nil { if r.Err != nil {
err = errors.Wrap(err, "transaction DecodeBinary failed") err = errors.Wrap(r.Err, "transaction DecodeBinary failed")
} } else {
relayReason := s.coreServer.RelayTxn(tx) relayReason := s.coreServer.RelayTxn(tx)
switch relayReason { switch relayReason {
case network.RelaySucceed: case network.RelaySucceed:
results = true results = true
case network.RelayAlreadyExists: case network.RelayAlreadyExists:
err = errors.New("block or transaction already exists and cannot be sent repeatedly") err = errors.New("block or transaction already exists and cannot be sent repeatedly")
case network.RelayOutOfMemory: case network.RelayOutOfMemory:
err = errors.New("the memory pool is full and no more transactions can be sent") err = errors.New("the memory pool is full and no more transactions can be sent")
case network.RelayUnableToVerify: case network.RelayUnableToVerify:
err = errors.New("the block cannot be validated") err = errors.New("the block cannot be validated")
case network.RelayInvalid: case network.RelayInvalid:
err = errors.New("block or transaction validation failed") err = errors.New("block or transaction validation failed")
case network.RelayPolicyFail: case network.RelayPolicyFail:
err = errors.New("one of the Policy filters failed") err = errors.New("one of the Policy filters failed")
default: default:
err = errors.New("unknown error") err = errors.New("unknown error")
}
} }
if err != nil { if err != nil {
resultsErr = NewInternalServerError(err.Error(), err) resultsErr = NewInternalServerError(err.Error(), err)

View file

@ -1,11 +1,10 @@
package rpc package rpc
import ( import (
"bytes"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/crypto" "github.com/CityOfZion/neo-go/pkg/crypto"
"github.com/CityOfZion/neo-go/pkg/crypto/keys" "github.com/CityOfZion/neo-go/pkg/crypto/keys"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
errs "github.com/pkg/errors" errs "github.com/pkg/errors"
) )
@ -71,11 +70,12 @@ func GetInvocationScript(tx *transaction.Transaction, wif keys.WIF) ([]byte, err
) )
var ( var (
err error err error
buf = new(bytes.Buffer) buf = io.NewBufBinWriter()
signature []byte signature []byte
) )
if err = tx.EncodeBinary(buf); err != nil { tx.EncodeBinary(buf.BinWriter)
return nil, errs.Wrap(err, "Failed to encode transaction to binary") if buf.Err != nil {
return nil, errs.Wrap(buf.Err, "Failed to encode transaction to binary")
} }
data := buf.Bytes() data := buf.Bytes()
signature, err = wif.PrivateKey.Sign(data[:(len(data) - 1)]) signature, err = wif.PrivateKey.Sign(data[:(len(data) - 1)])

View file

@ -3,6 +3,7 @@ package wrappers
import ( import (
"github.com/CityOfZion/neo-go/pkg/core" "github.com/CityOfZion/neo-go/pkg/core"
"github.com/CityOfZion/neo-go/pkg/core/transaction" "github.com/CityOfZion/neo-go/pkg/core/transaction"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/CityOfZion/neo-go/pkg/util" "github.com/CityOfZion/neo-go/pkg/util"
) )
@ -30,7 +31,7 @@ func NewTransactionOutputRaw(tx *transaction.Transaction, header *core.Header, c
return TransactionOutputRaw{ return TransactionOutputRaw{
Transaction: tx, Transaction: tx,
TxHash: tx.Hash(), TxHash: tx.Hash(),
Size: tx.Size(), Size: io.GetVarSize(tx),
SysFee: chain.SystemFee(tx), SysFee: chain.SystemFee(tx),
NetFee: chain.NetworkFee(tx), NetFee: chain.NetworkFee(tx),
Blockhash: header.Hash(), Blockhash: header.Hash(),

View file

@ -1,11 +1,10 @@
package smartcontract package smartcontract
import ( import (
"bytes"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/crypto/keys" "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/CityOfZion/neo-go/pkg/vm"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
) )
@ -22,8 +21,7 @@ func TestCreateMultiSigRedeemScript(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
buf := bytes.NewBuffer(out) br := io.NewBinReaderFromBuf(out)
br := util.BinReader{R: buf}
var b uint8 var b uint8
br.ReadLE(&b) br.ReadLE(&b)
assert.Equal(t, vm.PUSH3, vm.Instruction(b)) assert.Equal(t, vm.PUSH3, vm.Instruction(b))

View file

@ -1,67 +0,0 @@
package util
import (
"bytes"
"testing"
"github.com/stretchr/testify/assert"
)
func TestWriteVarUint1(t *testing.T) {
var (
val = uint64(1)
buf = new(bytes.Buffer)
)
bw := BinWriter{W: buf}
bw.WriteVarUint(val)
assert.Nil(t, bw.Err)
assert.Equal(t, 1, buf.Len())
}
func TestWriteVarUint1000(t *testing.T) {
var (
val = uint64(1000)
buf = new(bytes.Buffer)
)
bw := BinWriter{W: buf}
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}
res := br.ReadVarUint()
assert.Nil(t, br.Err)
assert.Equal(t, val, res)
}
func TestWriteVarUint100000(t *testing.T) {
var (
val = uint64(100000)
buf = new(bytes.Buffer)
)
bw := BinWriter{W: buf}
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}
res := br.ReadVarUint()
assert.Nil(t, br.Err)
assert.Equal(t, val, res)
}
func TestWriteVarUint100000000000(t *testing.T) {
var (
val = uint64(1000000000000)
buf = new(bytes.Buffer)
)
bw := BinWriter{W: buf}
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}
res := br.ReadVarUint()
assert.Nil(t, br.Err)
assert.Equal(t, val, res)
}

View file

@ -104,11 +104,6 @@ func (f *Fixed8) UnmarshalJSON(data []byte) error {
return nil 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. // MarshalJSON implements the json marshaller interface.
func (f Fixed8) MarshalJSON() ([]byte, error) { func (f Fixed8) MarshalJSON() ([]byte, error) {
return []byte(`"` + f.String() + `"`), nil return []byte(`"` + f.String() + `"`), nil

View file

@ -70,11 +70,6 @@ func (u *Uint160) UnmarshalJSON(data []byte) (err error) {
return err 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. // MarshalJSON implements the json marshaller interface.
func (u Uint160) MarshalJSON() ([]byte, error) { func (u Uint160) MarshalJSON() ([]byte, error) {
return []byte(`"0x` + u.String() + `"`), nil return []byte(`"0x` + u.String() + `"`), nil

View file

@ -82,11 +82,6 @@ func (u *Uint256) UnmarshalJSON(data []byte) (err error) {
return err 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. // MarshalJSON implements the json marshaller interface.
func (u Uint256) MarshalJSON() ([]byte, error) { func (u Uint256) MarshalJSON() ([]byte, error) {
return []byte(`"0x` + u.ReverseString() + `"`), nil return []byte(`"0x` + u.ReverseString() + `"`), nil