io: add type-specific read/write methods

This seriously improves the serialization/deserialization performance for
several reasons:
 * no time spent in `binary` reflection
 * no memory allocations being made on every read/write
 * uses fast ReadBytes everywhere it's appropriate

It also makes Fixed8 Serializable just for convenience.
This commit is contained in:
Roman Khimov 2019-12-12 18:52:23 +03:00
parent 89d7f6d26e
commit 54d888ba70
43 changed files with 441 additions and 205 deletions

View file

@ -167,7 +167,7 @@ func dumpDB(ctx *cli.Context) error {
if count == 0 { if count == 0 {
count = chainHeight - skip count = chainHeight - skip
} }
writer.WriteLE(count) writer.WriteU32LE(count)
for i := skip + 1; i <= skip+count; i++ { for i := skip + 1; i <= skip+count; i++ {
bh := chain.GetHeaderHash(int(i)) bh := chain.GetHeaderHash(int(i))
b, err := chain.GetBlock(bh) b, err := chain.GetBlock(bh)
@ -211,8 +211,7 @@ func restoreDB(ctx *cli.Context) error {
} }
go chain.Run() go chain.Run()
var allBlocks uint32 var allBlocks = reader.ReadU32LE()
reader.ReadLE(&allBlocks)
if reader.Err != nil { if reader.Err != nil {
return cli.NewExitError(err, 1) return cli.NewExitError(err, 1)
} }
@ -249,10 +248,9 @@ func restoreDB(ctx *cli.Context) error {
// readBlock performs reading of block size and then bytes with the length equal to that size. // readBlock performs reading of block size and then bytes with the length equal to that size.
func readBlock(reader *io.BinReader) ([]byte, error) { func readBlock(reader *io.BinReader) ([]byte, error) {
var size uint32 var size = reader.ReadU32LE()
reader.ReadLE(&size)
bytes := make([]byte, size) bytes := make([]byte, size)
reader.ReadLE(bytes) reader.ReadBytes(bytes)
if reader.Err != nil { if reader.Err != nil {
return nil, reader.Err return nil, reader.Err
} }

View file

@ -15,12 +15,12 @@ var _ payload.ChangeView = (*changeView)(nil)
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (c *changeView) EncodeBinary(w *io.BinWriter) { func (c *changeView) EncodeBinary(w *io.BinWriter) {
w.WriteLE(c.timestamp) w.WriteU32LE(c.timestamp)
} }
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (c *changeView) DecodeBinary(r *io.BinReader) { func (c *changeView) DecodeBinary(r *io.BinReader) {
r.ReadLE(&c.timestamp) c.timestamp = r.ReadU32LE()
} }
// NewViewNumber implements payload.ChangeView interface. // NewViewNumber implements payload.ChangeView interface.

View file

@ -161,11 +161,11 @@ func (p *Payload) SetHeight(h uint32) {
// EncodeBinaryUnsigned writes payload to w excluding signature. // EncodeBinaryUnsigned writes payload to w excluding signature.
func (p *Payload) EncodeBinaryUnsigned(w *io.BinWriter) { func (p *Payload) EncodeBinaryUnsigned(w *io.BinWriter) {
w.WriteLE(p.version) w.WriteU32LE(p.version)
w.WriteBytes(p.prevHash[:]) w.WriteBytes(p.prevHash[:])
w.WriteLE(p.height) w.WriteU32LE(p.height)
w.WriteLE(p.validatorIndex) w.WriteU16LE(p.validatorIndex)
w.WriteLE(p.timestamp) w.WriteU32LE(p.timestamp)
ww := io.NewBufBinWriter() ww := io.NewBufBinWriter()
p.message.EncodeBinary(ww.BinWriter) p.message.EncodeBinary(ww.BinWriter)
@ -176,7 +176,7 @@ func (p *Payload) EncodeBinaryUnsigned(w *io.BinWriter) {
func (p *Payload) EncodeBinary(w *io.BinWriter) { func (p *Payload) EncodeBinary(w *io.BinWriter) {
p.EncodeBinaryUnsigned(w) p.EncodeBinaryUnsigned(w)
w.WriteLE(byte(1)) w.WriteByte(1)
p.Witness.EncodeBinary(w) p.Witness.EncodeBinary(w)
} }
@ -211,11 +211,11 @@ func (p *Payload) Verify() bool {
// DecodeBinaryUnsigned reads payload from w excluding signature. // DecodeBinaryUnsigned reads payload from w excluding signature.
func (p *Payload) DecodeBinaryUnsigned(r *io.BinReader) { func (p *Payload) DecodeBinaryUnsigned(r *io.BinReader) {
r.ReadLE(&p.version) p.version = r.ReadU32LE()
r.ReadBytes(p.prevHash[:]) r.ReadBytes(p.prevHash[:])
r.ReadLE(&p.height) p.height = r.ReadU32LE()
r.ReadLE(&p.validatorIndex) p.validatorIndex = r.ReadU16LE()
r.ReadLE(&p.timestamp) p.timestamp = r.ReadU32LE()
data := r.ReadVarBytes() data := r.ReadVarBytes()
if r.Err != nil { if r.Err != nil {
@ -242,8 +242,7 @@ func (p *Payload) DecodeBinary(r *io.BinReader) {
return return
} }
var b byte var b = r.ReadByte()
r.ReadLE(&b)
if b != 1 { if b != 1 {
r.Err = errors.New("invalid format") r.Err = errors.New("invalid format")
return return
@ -255,14 +254,14 @@ func (p *Payload) DecodeBinary(r *io.BinReader) {
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (m *message) EncodeBinary(w *io.BinWriter) { func (m *message) EncodeBinary(w *io.BinWriter) {
w.WriteBytes([]byte{byte(m.Type)}) w.WriteBytes([]byte{byte(m.Type)})
w.WriteLE(m.ViewNumber) w.WriteByte(m.ViewNumber)
m.payload.EncodeBinary(w) m.payload.EncodeBinary(w)
} }
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (m *message) DecodeBinary(r *io.BinReader) { func (m *message) DecodeBinary(r *io.BinReader) {
r.ReadLE((*byte)(&m.Type)) m.Type = messageType(r.ReadByte())
r.ReadLE(&m.ViewNumber) m.ViewNumber = r.ReadByte()
switch m.Type { switch m.Type {
case changeViewType: case changeViewType:

View file

@ -20,8 +20,8 @@ var _ payload.PrepareRequest = (*prepareRequest)(nil)
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (p *prepareRequest) EncodeBinary(w *io.BinWriter) { func (p *prepareRequest) EncodeBinary(w *io.BinWriter) {
w.WriteLE(p.timestamp) w.WriteU32LE(p.timestamp)
w.WriteLE(p.nonce) w.WriteU64LE(p.nonce)
w.WriteBytes(p.nextConsensus[:]) w.WriteBytes(p.nextConsensus[:])
w.WriteArray(p.transactionHashes) w.WriteArray(p.transactionHashes)
p.minerTx.EncodeBinary(w) p.minerTx.EncodeBinary(w)
@ -29,8 +29,8 @@ func (p *prepareRequest) EncodeBinary(w *io.BinWriter) {
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (p *prepareRequest) DecodeBinary(r *io.BinReader) { func (p *prepareRequest) DecodeBinary(r *io.BinReader) {
r.ReadLE(&p.timestamp) p.timestamp = r.ReadU32LE()
r.ReadLE(&p.nonce) p.nonce = r.ReadU64LE()
r.ReadBytes(p.nextConsensus[:]) r.ReadBytes(p.nextConsensus[:])
r.ReadArray(&p.transactionHashes) r.ReadArray(&p.transactionHashes)
p.minerTx.DecodeBinary(r) p.minerTx.DecodeBinary(r)

View file

@ -44,8 +44,7 @@ var _ payload.RecoveryMessage = (*recoveryMessage)(nil)
func (m *recoveryMessage) DecodeBinary(r *io.BinReader) { func (m *recoveryMessage) DecodeBinary(r *io.BinReader) {
r.ReadArray(&m.changeViewPayloads) r.ReadArray(&m.changeViewPayloads)
var hasReq bool var hasReq = r.ReadBool()
r.ReadLE(&hasReq)
if hasReq { if hasReq {
m.prepareRequest = new(prepareRequest) m.prepareRequest = new(prepareRequest)
m.prepareRequest.DecodeBinary(r) m.prepareRequest.DecodeBinary(r)
@ -72,7 +71,7 @@ func (m *recoveryMessage) EncodeBinary(w *io.BinWriter) {
w.WriteArray(m.changeViewPayloads) w.WriteArray(m.changeViewPayloads)
hasReq := m.prepareRequest != nil hasReq := m.prepareRequest != nil
w.WriteLE(hasReq) w.WriteBool(hasReq)
if hasReq { if hasReq {
m.prepareRequest.EncodeBinary(w) m.prepareRequest.EncodeBinary(w)
} else { } else {
@ -90,45 +89,45 @@ func (m *recoveryMessage) EncodeBinary(w *io.BinWriter) {
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (p *changeViewCompact) DecodeBinary(r *io.BinReader) { func (p *changeViewCompact) DecodeBinary(r *io.BinReader) {
r.ReadLE(&p.ValidatorIndex) p.ValidatorIndex = r.ReadU16LE()
r.ReadLE(&p.OriginalViewNumber) p.OriginalViewNumber = r.ReadByte()
r.ReadLE(&p.Timestamp) p.Timestamp = r.ReadU32LE()
p.InvocationScript = r.ReadVarBytes() p.InvocationScript = r.ReadVarBytes()
} }
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (p *changeViewCompact) EncodeBinary(w *io.BinWriter) { func (p *changeViewCompact) EncodeBinary(w *io.BinWriter) {
w.WriteLE(p.ValidatorIndex) w.WriteU16LE(p.ValidatorIndex)
w.WriteLE(p.OriginalViewNumber) w.WriteByte(p.OriginalViewNumber)
w.WriteLE(p.Timestamp) w.WriteU32LE(p.Timestamp)
w.WriteVarBytes(p.InvocationScript) w.WriteVarBytes(p.InvocationScript)
} }
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (p *commitCompact) DecodeBinary(r *io.BinReader) { func (p *commitCompact) DecodeBinary(r *io.BinReader) {
r.ReadLE(&p.ViewNumber) p.ViewNumber = r.ReadByte()
r.ReadLE(&p.ValidatorIndex) p.ValidatorIndex = r.ReadU16LE()
r.ReadBytes(p.Signature[:]) r.ReadBytes(p.Signature[:])
p.InvocationScript = r.ReadVarBytes() p.InvocationScript = r.ReadVarBytes()
} }
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (p *commitCompact) EncodeBinary(w *io.BinWriter) { func (p *commitCompact) EncodeBinary(w *io.BinWriter) {
w.WriteLE(p.ViewNumber) w.WriteByte(p.ViewNumber)
w.WriteLE(p.ValidatorIndex) w.WriteU16LE(p.ValidatorIndex)
w.WriteBytes(p.Signature[:]) w.WriteBytes(p.Signature[:])
w.WriteVarBytes(p.InvocationScript) w.WriteVarBytes(p.InvocationScript)
} }
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (p *preparationCompact) DecodeBinary(r *io.BinReader) { func (p *preparationCompact) DecodeBinary(r *io.BinReader) {
r.ReadLE(&p.ValidatorIndex) p.ValidatorIndex = r.ReadU16LE()
p.InvocationScript = r.ReadVarBytes() p.InvocationScript = r.ReadVarBytes()
} }
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (p *preparationCompact) EncodeBinary(w *io.BinWriter) { func (p *preparationCompact) EncodeBinary(w *io.BinWriter) {
w.WriteLE(p.ValidatorIndex) w.WriteU16LE(p.ValidatorIndex)
w.WriteVarBytes(p.InvocationScript) w.WriteVarBytes(p.InvocationScript)
} }

View file

@ -14,12 +14,12 @@ var _ payload.RecoveryRequest = (*recoveryRequest)(nil)
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (m *recoveryRequest) DecodeBinary(r *io.BinReader) { func (m *recoveryRequest) DecodeBinary(r *io.BinReader) {
r.ReadLE(&m.timestamp) m.timestamp = r.ReadU32LE()
} }
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (m *recoveryRequest) EncodeBinary(w *io.BinWriter) { func (m *recoveryRequest) EncodeBinary(w *io.BinWriter) {
w.WriteLE(m.timestamp) w.WriteU32LE(m.timestamp)
} }
// Timestamp implements payload.RecoveryRequest interface. // Timestamp implements payload.RecoveryRequest interface.

View file

@ -88,8 +88,7 @@ func NewBlockFromTrimmedBytes(b []byte) (*Block, error) {
br := io.NewBinReaderFromBuf(b) br := io.NewBinReaderFromBuf(b)
block.decodeHashableFields(br) block.decodeHashableFields(br)
var padding uint8 _ = br.ReadByte()
br.ReadLE(&padding)
block.Script.DecodeBinary(br) block.Script.DecodeBinary(br)
@ -97,7 +96,7 @@ func NewBlockFromTrimmedBytes(b []byte) (*Block, error) {
block.Transactions = make([]*transaction.Transaction, lenTX) block.Transactions = make([]*transaction.Transaction, lenTX)
for i := 0; i < int(lenTX); i++ { for i := 0; i < int(lenTX); i++ {
var hash util.Uint256 var hash util.Uint256
br.ReadLE(&hash) hash.DecodeBinary(br)
block.Transactions[i] = transaction.NewTrimmedTX(hash) block.Transactions[i] = transaction.NewTrimmedTX(hash)
} }
@ -110,7 +109,7 @@ func NewBlockFromTrimmedBytes(b []byte) (*Block, error) {
func (b *Block) Trim() ([]byte, error) { func (b *Block) Trim() ([]byte, error) {
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
b.encodeHashableFields(buf.BinWriter) b.encodeHashableFields(buf.BinWriter)
buf.WriteBytes([]byte{1}) buf.WriteByte(1)
b.Script.EncodeBinary(buf.BinWriter) b.Script.EncodeBinary(buf.BinWriter)
buf.WriteVarUint(uint64(len(b.Transactions))) buf.WriteVarUint(uint64(len(b.Transactions)))

View file

@ -114,24 +114,24 @@ func (b *BlockBase) createHash() {
// 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(bw *io.BinWriter) { func (b *BlockBase) encodeHashableFields(bw *io.BinWriter) {
bw.WriteLE(b.Version) bw.WriteU32LE(b.Version)
bw.WriteBytes(b.PrevHash[:]) bw.WriteBytes(b.PrevHash[:])
bw.WriteBytes(b.MerkleRoot[:]) bw.WriteBytes(b.MerkleRoot[:])
bw.WriteLE(b.Timestamp) bw.WriteU32LE(b.Timestamp)
bw.WriteLE(b.Index) bw.WriteU32LE(b.Index)
bw.WriteLE(b.ConsensusData) bw.WriteU64LE(b.ConsensusData)
bw.WriteBytes(b.NextConsensus[:]) bw.WriteBytes(b.NextConsensus[:])
} }
// decodeHashableFields decodes the fields used for hashing. // decodeHashableFields decodes 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(br *io.BinReader) { func (b *BlockBase) decodeHashableFields(br *io.BinReader) {
br.ReadLE(&b.Version) b.Version = br.ReadU32LE()
br.ReadBytes(b.PrevHash[:]) br.ReadBytes(b.PrevHash[:])
br.ReadBytes(b.MerkleRoot[:]) br.ReadBytes(b.MerkleRoot[:])
br.ReadLE(&b.Timestamp) b.Timestamp = br.ReadU32LE()
br.ReadLE(&b.Index) b.Index = br.ReadU32LE()
br.ReadLE(&b.ConsensusData) b.ConsensusData = br.ReadU64LE()
br.ReadBytes(b.NextConsensus[:]) br.ReadBytes(b.NextConsensus[:])
// 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

View file

@ -1451,7 +1451,7 @@ func (bc *Blockchain) verifyBlockWitnesses(block *Block, prevHeader *Header) err
func hashAndIndexToBytes(h util.Uint256, index uint32) []byte { func hashAndIndexToBytes(h util.Uint256, index uint32) []byte {
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
buf.WriteBytes(h.BytesLE()) buf.WriteBytes(h.BytesLE())
buf.WriteLE(index) buf.WriteU32LE(index)
return buf.Bytes() return buf.Bytes()
} }

View file

@ -449,8 +449,7 @@ func (dao *dao) GetTransaction(hash util.Uint256) (*transaction.Transaction, uin
} }
r := io.NewBinReaderFromBuf(b) r := io.NewBinReaderFromBuf(b)
var height uint32 var height = r.ReadU32LE()
r.ReadLE(&height)
tx := &transaction.Transaction{} tx := &transaction.Transaction{}
tx.DecodeBinary(r) tx.DecodeBinary(r)
@ -476,9 +475,8 @@ func (dao *dao) PutCurrentHeader(hashAndIndex []byte) error {
func read2000Uint256Hashes(b []byte) ([]util.Uint256, error) { func read2000Uint256Hashes(b []byte) ([]util.Uint256, error) {
r := bytes.NewReader(b) r := bytes.NewReader(b)
br := io.NewBinReaderFromIO(r) br := io.NewBinReaderFromIO(r)
lenHashes := br.ReadVarUint() hashes := make([]util.Uint256, 0)
hashes := make([]util.Uint256, lenHashes) br.ReadArray(&hashes)
br.ReadLE(hashes)
if br.Err != nil { if br.Err != nil {
return nil, br.Err return nil, br.Err
} }
@ -502,12 +500,12 @@ func (dao *dao) StoreAsBlock(block *Block, sysFee uint32) error {
buf = io.NewBufBinWriter() buf = io.NewBufBinWriter()
) )
// sysFee needs to be handled somehow // sysFee needs to be handled somehow
// buf.WriteLE(sysFee) // buf.WriteU32LE(sysFee)
b, err := block.Trim() b, err := block.Trim()
if err != nil { if err != nil {
return err return err
} }
buf.WriteLE(b) buf.WriteBytes(b)
if buf.Err != nil { if buf.Err != nil {
return buf.Err return buf.Err
} }
@ -517,8 +515,9 @@ func (dao *dao) StoreAsBlock(block *Block, sysFee uint32) error {
// StoreAsCurrentBlock stores the given block witch prefix SYSCurrentBlock. // StoreAsCurrentBlock stores the given block witch prefix SYSCurrentBlock.
func (dao *dao) StoreAsCurrentBlock(block *Block) error { func (dao *dao) StoreAsCurrentBlock(block *Block) error {
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
buf.WriteLE(block.Hash().BytesLE()) h := block.Hash()
buf.WriteLE(block.Index) h.EncodeBinary(buf.BinWriter)
buf.WriteU32LE(block.Index)
return dao.store.Put(storage.SYSCurrentBlock.Bytes(), buf.Bytes()) return dao.store.Put(storage.SYSCurrentBlock.Bytes(), buf.Bytes())
} }
@ -526,7 +525,7 @@ func (dao *dao) StoreAsCurrentBlock(block *Block) error {
func (dao *dao) StoreAsTransaction(tx *transaction.Transaction, index uint32) error { func (dao *dao) StoreAsTransaction(tx *transaction.Transaction, index uint32) error {
key := storage.AppendPrefix(storage.DataTransaction, tx.Hash().BytesLE()) key := storage.AppendPrefix(storage.DataTransaction, tx.Hash().BytesLE())
buf := io.NewBufBinWriter() buf := io.NewBufBinWriter()
buf.WriteLE(index) buf.WriteU32LE(index)
tx.EncodeBinary(buf.BinWriter) tx.EncodeBinary(buf.BinWriter)
if buf.Err != nil { if buf.Err != nil {
return buf.Err return buf.Err

View file

@ -26,7 +26,7 @@ func NewSpentCoinState(hash util.Uint256, height uint32) *SpentCoinState {
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (s *SpentCoinState) DecodeBinary(br *io.BinReader) { func (s *SpentCoinState) DecodeBinary(br *io.BinReader) {
br.ReadBytes(s.txHash[:]) br.ReadBytes(s.txHash[:])
br.ReadLE(&s.txHeight) s.txHeight = br.ReadU32LE()
s.items = make(map[uint16]uint32) s.items = make(map[uint16]uint32)
lenItems := br.ReadVarUint() lenItems := br.ReadVarUint()
@ -35,8 +35,8 @@ func (s *SpentCoinState) DecodeBinary(br *io.BinReader) {
key uint16 key uint16
value uint32 value uint32
) )
br.ReadLE(&key) key = br.ReadU16LE()
br.ReadLE(&value) value = br.ReadU32LE()
s.items[key] = value s.items[key] = value
} }
} }
@ -44,10 +44,10 @@ func (s *SpentCoinState) DecodeBinary(br *io.BinReader) {
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (s *SpentCoinState) EncodeBinary(bw *io.BinWriter) { func (s *SpentCoinState) EncodeBinary(bw *io.BinWriter) {
bw.WriteBytes(s.txHash[:]) bw.WriteBytes(s.txHash[:])
bw.WriteLE(s.txHeight) bw.WriteU32LE(s.txHeight)
bw.WriteVarUint(uint64(len(s.items))) bw.WriteVarUint(uint64(len(s.items)))
for k, v := range s.items { for k, v := range s.items {
bw.WriteLE(k) bw.WriteU16LE(k)
bw.WriteLE(v) bw.WriteU32LE(v)
} }
} }

View file

@ -39,9 +39,9 @@ func NewAccount(scriptHash util.Uint160) *Account {
// DecodeBinary decodes Account from the given BinReader. // DecodeBinary decodes Account from the given BinReader.
func (s *Account) DecodeBinary(br *io.BinReader) { func (s *Account) DecodeBinary(br *io.BinReader) {
br.ReadLE(&s.Version) s.Version = uint8(br.ReadByte())
br.ReadBytes(s.ScriptHash[:]) br.ReadBytes(s.ScriptHash[:])
br.ReadLE(&s.IsFrozen) s.IsFrozen = br.ReadBool()
br.ReadArray(&s.Votes) br.ReadArray(&s.Votes)
s.Balances = make(map[util.Uint256][]UnspentBalance) s.Balances = make(map[util.Uint256][]UnspentBalance)
@ -57,9 +57,9 @@ func (s *Account) DecodeBinary(br *io.BinReader) {
// EncodeBinary encodes Account to the given BinWriter. // EncodeBinary encodes Account to the given BinWriter.
func (s *Account) EncodeBinary(bw *io.BinWriter) { func (s *Account) EncodeBinary(bw *io.BinWriter) {
bw.WriteLE(s.Version) bw.WriteByte(byte(s.Version))
bw.WriteBytes(s.ScriptHash[:]) bw.WriteBytes(s.ScriptHash[:])
bw.WriteLE(s.IsFrozen) bw.WriteBool(s.IsFrozen)
bw.WriteArray(s.Votes) bw.WriteArray(s.Votes)
bw.WriteVarUint(uint64(len(s.Balances))) bw.WriteVarUint(uint64(len(s.Balances)))
@ -72,15 +72,15 @@ func (s *Account) EncodeBinary(bw *io.BinWriter) {
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (u *UnspentBalance) DecodeBinary(r *io.BinReader) { func (u *UnspentBalance) DecodeBinary(r *io.BinReader) {
u.Tx.DecodeBinary(r) u.Tx.DecodeBinary(r)
r.ReadLE(&u.Index) u.Index = r.ReadU16LE()
r.ReadLE(&u.Value) u.Value.DecodeBinary(r)
} }
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (u *UnspentBalance) EncodeBinary(w *io.BinWriter) { func (u *UnspentBalance) EncodeBinary(w *io.BinWriter) {
u.Tx.EncodeBinary(w) u.Tx.EncodeBinary(w)
w.WriteLE(u.Index) w.WriteU16LE(u.Index)
w.WriteLE(u.Value) u.Value.EncodeBinary(w)
} }
// GetBalanceValues sums all unspent outputs and returns a map of asset IDs to // GetBalanceValues sums all unspent outputs and returns a map of asset IDs to

View file

@ -29,40 +29,40 @@ type Asset struct {
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (a *Asset) DecodeBinary(br *io.BinReader) { func (a *Asset) DecodeBinary(br *io.BinReader) {
br.ReadBytes(a.ID[:]) br.ReadBytes(a.ID[:])
br.ReadLE(&a.AssetType) a.AssetType = transaction.AssetType(br.ReadByte())
a.Name = br.ReadString() a.Name = br.ReadString()
br.ReadLE(&a.Amount) a.Amount.DecodeBinary(br)
br.ReadLE(&a.Available) a.Available.DecodeBinary(br)
br.ReadLE(&a.Precision) a.Precision = uint8(br.ReadByte())
br.ReadLE(&a.FeeMode) a.FeeMode = uint8(br.ReadByte())
br.ReadBytes(a.FeeAddress[:]) br.ReadBytes(a.FeeAddress[:])
a.Owner.DecodeBinary(br) a.Owner.DecodeBinary(br)
br.ReadBytes(a.Admin[:]) br.ReadBytes(a.Admin[:])
br.ReadBytes(a.Issuer[:]) br.ReadBytes(a.Issuer[:])
br.ReadLE(&a.Expiration) a.Expiration = br.ReadU32LE()
br.ReadLE(&a.IsFrozen) a.IsFrozen = br.ReadBool()
} }
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (a *Asset) EncodeBinary(bw *io.BinWriter) { func (a *Asset) EncodeBinary(bw *io.BinWriter) {
bw.WriteBytes(a.ID[:]) bw.WriteBytes(a.ID[:])
bw.WriteLE(a.AssetType) bw.WriteByte(byte(a.AssetType))
bw.WriteString(a.Name) bw.WriteString(a.Name)
bw.WriteLE(a.Amount) a.Amount.EncodeBinary(bw)
bw.WriteLE(a.Available) a.Available.EncodeBinary(bw)
bw.WriteLE(a.Precision) bw.WriteByte(byte(a.Precision))
bw.WriteLE(a.FeeMode) bw.WriteByte(byte(a.FeeMode))
bw.WriteBytes(a.FeeAddress[:]) bw.WriteBytes(a.FeeAddress[:])
a.Owner.EncodeBinary(bw) a.Owner.EncodeBinary(bw)
bw.WriteBytes(a.Admin[:]) bw.WriteBytes(a.Admin[:])
bw.WriteBytes(a.Issuer[:]) bw.WriteBytes(a.Issuer[:])
bw.WriteLE(a.Expiration) bw.WriteU32LE(a.Expiration)
bw.WriteLE(a.IsFrozen) bw.WriteBool(a.IsFrozen)
} }
// GetName returns the asset name based on its type. // GetName returns the asset name based on its type.

View file

@ -26,8 +26,8 @@ type Contract struct {
func (cs *Contract) DecodeBinary(br *io.BinReader) { func (cs *Contract) DecodeBinary(br *io.BinReader) {
cs.Script = br.ReadVarBytes() cs.Script = br.ReadVarBytes()
br.ReadArray(&cs.ParamList) br.ReadArray(&cs.ParamList)
br.ReadLE(&cs.ReturnType) cs.ReturnType = smartcontract.ParamType(br.ReadByte())
br.ReadLE(&cs.Properties) cs.Properties = smartcontract.PropertyState(br.ReadByte())
cs.Name = br.ReadString() cs.Name = br.ReadString()
cs.CodeVersion = br.ReadString() cs.CodeVersion = br.ReadString()
cs.Author = br.ReadString() cs.Author = br.ReadString()
@ -40,8 +40,8 @@ func (cs *Contract) DecodeBinary(br *io.BinReader) {
func (cs *Contract) EncodeBinary(bw *io.BinWriter) { func (cs *Contract) EncodeBinary(bw *io.BinWriter) {
bw.WriteVarBytes(cs.Script) bw.WriteVarBytes(cs.Script)
bw.WriteArray(cs.ParamList) bw.WriteArray(cs.ParamList)
bw.WriteLE(cs.ReturnType) bw.WriteByte(byte(cs.ReturnType))
bw.WriteLE(cs.Properties) bw.WriteByte(byte(cs.Properties))
bw.WriteString(cs.Name) bw.WriteString(cs.Name)
bw.WriteString(cs.CodeVersion) bw.WriteString(cs.CodeVersion)
bw.WriteString(cs.Author) bw.WriteString(cs.Author)

View file

@ -39,9 +39,9 @@ func (ne *NotificationEvent) DecodeBinary(r *io.BinReader) {
// EncodeBinary implements the Serializable interface. // EncodeBinary implements the Serializable interface.
func (aer *AppExecResult) EncodeBinary(w *io.BinWriter) { func (aer *AppExecResult) EncodeBinary(w *io.BinWriter) {
w.WriteBytes(aer.TxHash[:]) w.WriteBytes(aer.TxHash[:])
w.WriteLE(aer.Trigger) w.WriteByte(aer.Trigger)
w.WriteString(aer.VMState) w.WriteString(aer.VMState)
w.WriteLE(aer.GasConsumed) aer.GasConsumed.EncodeBinary(w)
w.WriteString(aer.Stack) w.WriteString(aer.Stack)
w.WriteArray(aer.Events) w.WriteArray(aer.Events)
} }
@ -49,9 +49,9 @@ func (aer *AppExecResult) EncodeBinary(w *io.BinWriter) {
// DecodeBinary implements the Serializable interface. // DecodeBinary implements the Serializable interface.
func (aer *AppExecResult) DecodeBinary(r *io.BinReader) { func (aer *AppExecResult) DecodeBinary(r *io.BinReader) {
r.ReadBytes(aer.TxHash[:]) r.ReadBytes(aer.TxHash[:])
r.ReadLE(&aer.Trigger) aer.Trigger = r.ReadByte()
aer.VMState = r.ReadString() aer.VMState = r.ReadString()
r.ReadLE(&aer.GasConsumed) aer.GasConsumed.DecodeBinary(r)
aer.Stack = r.ReadString() aer.Stack = r.ReadString()
r.ReadArray(&aer.Events) r.ReadArray(&aer.Events)
} }

View file

@ -13,11 +13,11 @@ type StorageItem struct {
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (si *StorageItem) EncodeBinary(w *io.BinWriter) { func (si *StorageItem) EncodeBinary(w *io.BinWriter) {
w.WriteVarBytes(si.Value) w.WriteVarBytes(si.Value)
w.WriteLE(si.IsConst) w.WriteBool(si.IsConst)
} }
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (si *StorageItem) DecodeBinary(r *io.BinReader) { func (si *StorageItem) DecodeBinary(r *io.BinReader) {
si.Value = r.ReadVarBytes() si.Value = r.ReadVarBytes()
r.ReadLE(&si.IsConst) si.IsConst = r.ReadBool()
} }

View file

@ -21,16 +21,16 @@ func (vs *Validator) RegisteredAndHasVotes() bool {
// EncodeBinary encodes Validator to the given BinWriter. // EncodeBinary encodes Validator to the given BinWriter.
func (vs *Validator) EncodeBinary(bw *io.BinWriter) { func (vs *Validator) EncodeBinary(bw *io.BinWriter) {
vs.PublicKey.EncodeBinary(bw) vs.PublicKey.EncodeBinary(bw)
bw.WriteLE(vs.Registered) bw.WriteBool(vs.Registered)
bw.WriteLE(vs.Votes) vs.Votes.EncodeBinary(bw)
} }
// DecodeBinary decodes Validator from the given BinReader. // DecodeBinary decodes Validator from the given BinReader.
func (vs *Validator) DecodeBinary(reader *io.BinReader) { func (vs *Validator) DecodeBinary(reader *io.BinReader) {
vs.PublicKey = &keys.PublicKey{} vs.PublicKey = &keys.PublicKey{}
vs.PublicKey.DecodeBinary(reader) vs.PublicKey.DecodeBinary(reader)
reader.ReadLE(&vs.Registered) vs.Registered = reader.ReadBool()
reader.ReadLE(&vs.Votes) vs.Votes.DecodeBinary(reader)
} }
// GetValidatorsWeightedAverage applies weighted filter based on votes for validator and returns number of validators. // GetValidatorsWeightedAverage applies weighted filter based on votes for validator and returns number of validators.

View file

@ -16,7 +16,7 @@ type Attribute struct {
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (attr *Attribute) DecodeBinary(br *io.BinReader) { func (attr *Attribute) DecodeBinary(br *io.BinReader) {
br.ReadLE(&attr.Usage) attr.Usage = AttrUsage(br.ReadByte())
// very special case // very special case
if attr.Usage == ECDH02 || attr.Usage == ECDH03 { if attr.Usage == ECDH02 || attr.Usage == ECDH03 {
@ -35,8 +35,7 @@ func (attr *Attribute) DecodeBinary(br *io.BinReader) {
datasize = 20 datasize = 20
case DescriptionURL: case DescriptionURL:
// It's not VarUint as per C# implementation, dunno why // It's not VarUint as per C# implementation, dunno why
var urllen uint8 var urllen = br.ReadByte()
br.ReadLE(&urllen)
datasize = uint64(urllen) datasize = uint64(urllen)
case Description, Remark, Remark1, Remark2, Remark3, Remark4, case Description, Remark, Remark1, Remark2, Remark3, Remark4,
Remark5, Remark6, Remark7, Remark8, Remark9, Remark10, Remark11, Remark5, Remark6, Remark7, Remark8, Remark9, Remark10, Remark11,
@ -52,7 +51,7 @@ func (attr *Attribute) DecodeBinary(br *io.BinReader) {
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (attr *Attribute) EncodeBinary(bw *io.BinWriter) { func (attr *Attribute) EncodeBinary(bw *io.BinWriter) {
bw.WriteLE(&attr.Usage) bw.WriteByte(byte(attr.Usage))
switch attr.Usage { switch attr.Usage {
case ECDH02, ECDH03: case ECDH02, ECDH03:
bw.WriteBytes(attr.Data[1:]) bw.WriteBytes(attr.Data[1:])
@ -61,8 +60,7 @@ func (attr *Attribute) EncodeBinary(bw *io.BinWriter) {
Remark12, Remark13, Remark14, Remark15: Remark12, Remark13, Remark14, Remark15:
bw.WriteVarBytes(attr.Data) bw.WriteVarBytes(attr.Data)
case DescriptionURL: case DescriptionURL:
var urllen = uint8(len(attr.Data)) bw.WriteByte(byte(len(attr.Data)))
bw.WriteLE(urllen)
fallthrough fallthrough
case Script, ContractHash, Vote, Hash1, Hash2, Hash3, Hash4, Hash5, Hash6, case Script, ContractHash, Vote, Hash1, Hash2, Hash3, Hash4, Hash5, Hash6,
Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15: Hash7, Hash8, Hash9, Hash10, Hash11, Hash12, Hash13, Hash14, Hash15:

View file

@ -17,11 +17,11 @@ type Input struct {
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (in *Input) DecodeBinary(br *io.BinReader) { func (in *Input) DecodeBinary(br *io.BinReader) {
br.ReadBytes(in.PrevHash[:]) br.ReadBytes(in.PrevHash[:])
br.ReadLE(&in.PrevIndex) in.PrevIndex = br.ReadU16LE()
} }
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (in *Input) EncodeBinary(bw *io.BinWriter) { func (in *Input) EncodeBinary(bw *io.BinWriter) {
bw.WriteBytes(in.PrevHash[:]) bw.WriteBytes(in.PrevHash[:])
bw.WriteLE(in.PrevIndex) bw.WriteU16LE(in.PrevIndex)
} }

View file

@ -37,7 +37,7 @@ func NewInvocationTX(script []byte, gas util.Fixed8) *Transaction {
func (tx *InvocationTX) DecodeBinary(br *io.BinReader) { func (tx *InvocationTX) DecodeBinary(br *io.BinReader) {
tx.Script = br.ReadVarBytes() tx.Script = br.ReadVarBytes()
if tx.Version >= 1 { if tx.Version >= 1 {
br.ReadLE(&tx.Gas) tx.Gas.DecodeBinary(br)
} else { } else {
tx.Gas = util.Fixed8FromInt64(0) tx.Gas = util.Fixed8FromInt64(0)
} }
@ -47,6 +47,6 @@ func (tx *InvocationTX) DecodeBinary(br *io.BinReader) {
func (tx *InvocationTX) EncodeBinary(bw *io.BinWriter) { func (tx *InvocationTX) EncodeBinary(bw *io.BinWriter) {
bw.WriteVarBytes(tx.Script) bw.WriteVarBytes(tx.Script)
if tx.Version >= 1 { if tx.Version >= 1 {
bw.WriteLE(tx.Gas) tx.Gas.EncodeBinary(bw)
} }
} }

View file

@ -12,10 +12,10 @@ type MinerTX struct {
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (tx *MinerTX) DecodeBinary(r *io.BinReader) { func (tx *MinerTX) DecodeBinary(r *io.BinReader) {
r.ReadLE(&tx.Nonce) tx.Nonce = r.ReadU32LE()
} }
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (tx *MinerTX) EncodeBinary(w *io.BinWriter) { func (tx *MinerTX) EncodeBinary(w *io.BinWriter) {
w.WriteLE(tx.Nonce) w.WriteU32LE(tx.Nonce)
} }

View file

@ -36,14 +36,14 @@ func NewOutput(assetID util.Uint256, amount util.Fixed8, scriptHash util.Uint160
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (out *Output) DecodeBinary(br *io.BinReader) { func (out *Output) DecodeBinary(br *io.BinReader) {
br.ReadBytes(out.AssetID[:]) br.ReadBytes(out.AssetID[:])
br.ReadLE(&out.Amount) out.Amount.DecodeBinary(br)
br.ReadBytes(out.ScriptHash[:]) br.ReadBytes(out.ScriptHash[:])
} }
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (out *Output) EncodeBinary(bw *io.BinWriter) { func (out *Output) EncodeBinary(bw *io.BinWriter) {
bw.WriteBytes(out.AssetID[:]) bw.WriteBytes(out.AssetID[:])
bw.WriteLE(out.Amount) out.Amount.EncodeBinary(bw)
bw.WriteBytes(out.ScriptHash[:]) bw.WriteBytes(out.ScriptHash[:])
} }

View file

@ -27,17 +27,13 @@ func (tx *PublishTX) DecodeBinary(br *io.BinReader) {
lenParams := br.ReadVarUint() lenParams := br.ReadVarUint()
tx.ParamList = make([]smartcontract.ParamType, lenParams) tx.ParamList = make([]smartcontract.ParamType, lenParams)
for i := 0; i < int(lenParams); i++ { for i := 0; i < int(lenParams); i++ {
var ptype uint8 tx.ParamList[i] = smartcontract.ParamType(br.ReadByte())
br.ReadLE(&ptype)
tx.ParamList[i] = smartcontract.ParamType(ptype)
} }
var rtype uint8 tx.ReturnType = smartcontract.ParamType(br.ReadByte())
br.ReadLE(&rtype)
tx.ReturnType = smartcontract.ParamType(rtype)
if tx.Version >= 1 { if tx.Version >= 1 {
br.ReadLE(&tx.NeedStorage) tx.NeedStorage = br.ReadBool()
} else { } else {
tx.NeedStorage = false tx.NeedStorage = false
} }
@ -54,11 +50,11 @@ func (tx *PublishTX) EncodeBinary(bw *io.BinWriter) {
bw.WriteVarBytes(tx.Script) bw.WriteVarBytes(tx.Script)
bw.WriteVarUint(uint64(len(tx.ParamList))) bw.WriteVarUint(uint64(len(tx.ParamList)))
for _, param := range tx.ParamList { for _, param := range tx.ParamList {
bw.WriteLE(uint8(param)) bw.WriteByte(byte(param))
} }
bw.WriteLE(uint8(tx.ReturnType)) bw.WriteByte(byte(tx.ReturnType))
if tx.Version >= 1 { if tx.Version >= 1 {
bw.WriteLE(tx.NeedStorage) bw.WriteBool(tx.NeedStorage)
} }
bw.WriteString(tx.Name) bw.WriteString(tx.Name)
bw.WriteString(tx.CodeVersion) bw.WriteString(tx.CodeVersion)

View file

@ -30,12 +30,12 @@ type RegisterTX struct {
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (tx *RegisterTX) DecodeBinary(br *io.BinReader) { func (tx *RegisterTX) DecodeBinary(br *io.BinReader) {
br.ReadLE(&tx.AssetType) tx.AssetType = AssetType(br.ReadByte())
tx.Name = br.ReadString() tx.Name = br.ReadString()
br.ReadLE(&tx.Amount) tx.Amount.DecodeBinary(br)
br.ReadLE(&tx.Precision) tx.Precision = uint8(br.ReadByte())
tx.Owner.DecodeBinary(br) tx.Owner.DecodeBinary(br)
@ -44,10 +44,10 @@ func (tx *RegisterTX) DecodeBinary(br *io.BinReader) {
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) { func (tx *RegisterTX) EncodeBinary(bw *io.BinWriter) {
bw.WriteLE(tx.AssetType) bw.WriteByte(byte(tx.AssetType))
bw.WriteString(tx.Name) bw.WriteString(tx.Name)
bw.WriteLE(tx.Amount) tx.Amount.EncodeBinary(bw)
bw.WriteLE(tx.Precision) bw.WriteByte(byte(tx.Precision))
bw.WriteBytes(tx.Owner.Bytes()) bw.WriteBytes(tx.Owner.Bytes())
bw.WriteBytes(tx.Admin[:]) bw.WriteBytes(tx.Admin[:])
} }

View file

@ -23,7 +23,7 @@ type StateDescriptor struct {
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (s *StateDescriptor) DecodeBinary(r *io.BinReader) { func (s *StateDescriptor) DecodeBinary(r *io.BinReader) {
r.ReadLE(&s.Type) s.Type = DescStateType(r.ReadByte())
s.Key = r.ReadVarBytes() s.Key = r.ReadVarBytes()
s.Value = r.ReadVarBytes() s.Value = r.ReadVarBytes()
@ -32,7 +32,7 @@ func (s *StateDescriptor) DecodeBinary(r *io.BinReader) {
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (s *StateDescriptor) EncodeBinary(w *io.BinWriter) { func (s *StateDescriptor) EncodeBinary(w *io.BinWriter) {
w.WriteLE(s.Type) w.WriteByte(byte(s.Type))
w.WriteVarBytes(s.Key) w.WriteVarBytes(s.Key)
w.WriteVarBytes(s.Value) w.WriteVarBytes(s.Value)
w.WriteString(s.Field) w.WriteString(s.Field)

View file

@ -92,8 +92,8 @@ func (t *Transaction) AddInput(in *Input) {
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (t *Transaction) DecodeBinary(br *io.BinReader) { func (t *Transaction) DecodeBinary(br *io.BinReader) {
br.ReadLE(&t.Type) t.Type = TXType(br.ReadByte())
br.ReadLE(&t.Version) t.Version = uint8(br.ReadByte())
t.decodeData(br) t.decodeData(br)
br.ReadArray(&t.Attributes) br.ReadArray(&t.Attributes)
@ -151,8 +151,8 @@ func (t *Transaction) EncodeBinary(bw *io.BinWriter) {
// encodeHashableFields encodes the fields that are not used for // encodeHashableFields encodes 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(bw *io.BinWriter) { func (t *Transaction) encodeHashableFields(bw *io.BinWriter) {
bw.WriteLE(t.Type) bw.WriteByte(byte(t.Type))
bw.WriteLE(t.Version) bw.WriteByte(byte(t.Version))
// Underlying TXer. // Underlying TXer.
if t.Data != nil { if t.Data != nil {

View file

@ -25,7 +25,7 @@ func NewUnspentCoinState(n int) *UnspentCoinState {
func (s *UnspentCoinState) EncodeBinary(bw *io.BinWriter) { func (s *UnspentCoinState) EncodeBinary(bw *io.BinWriter) {
bw.WriteVarUint(uint64(len(s.states))) bw.WriteVarUint(uint64(len(s.states)))
for _, state := range s.states { for _, state := range s.states {
bw.WriteBytes([]byte{byte(state)}) bw.WriteByte(byte(state))
} }
} }
@ -34,8 +34,6 @@ func (s *UnspentCoinState) DecodeBinary(br *io.BinReader) {
lenStates := br.ReadVarUint() lenStates := br.ReadVarUint()
s.states = make([]state.Coin, lenStates) s.states = make([]state.Coin, lenStates)
for i := 0; i < int(lenStates); i++ { for i := 0; i < int(lenStates); i++ {
var coinState uint8 s.states[i] = state.Coin(br.ReadByte())
br.ReadLE(&coinState)
s.states[i] = state.Coin(coinState)
} }
} }

View file

@ -168,7 +168,7 @@ func (p *PublicKey) DecodeBinary(r *io.BinReader) {
var x, y *big.Int var x, y *big.Int
var err error var err error
r.ReadLE(&prefix) prefix = uint8(r.ReadByte())
if r.Err != nil { if r.Err != nil {
return return
} }

View file

@ -16,12 +16,20 @@ const maxArraySize = 0x1000000
// 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
u64 []byte
u32 []byte
u16 []byte
u8 []byte
Err error Err error
} }
// NewBinReaderFromIO makes a BinReader from io.Reader. // NewBinReaderFromIO makes a BinReader from io.Reader.
func NewBinReaderFromIO(ior io.Reader) *BinReader { func NewBinReaderFromIO(ior io.Reader) *BinReader {
return &BinReader{r: ior} u64 := make([]byte, 8)
u32 := u64[:4]
u16 := u64[:2]
u8 := u64[:1]
return &BinReader{r: ior, u64: u64, u32: u32, u16: u16, u8: u8}
} }
// NewBinReaderFromBuf makes a BinReader from byte buffer. // NewBinReaderFromBuf makes a BinReader from byte buffer.
@ -39,6 +47,62 @@ func (r *BinReader) ReadLE(v interface{}) {
r.Err = binary.Read(r.r, binary.LittleEndian, v) r.Err = binary.Read(r.r, binary.LittleEndian, v)
} }
// ReadU64LE reads a little-endian encoded uint64 value from the underlying
// io.Reader. On read failures it returns zero.
func (r *BinReader) ReadU64LE() uint64 {
r.ReadBytes(r.u64)
if r.Err != nil {
return 0
}
return binary.LittleEndian.Uint64(r.u64)
}
// ReadU32LE reads a little-endian encoded uint32 value from the underlying
// io.Reader. On read failures it returns zero.
func (r *BinReader) ReadU32LE() uint32 {
r.ReadBytes(r.u32)
if r.Err != nil {
return 0
}
return binary.LittleEndian.Uint32(r.u32)
}
// ReadU16LE reads a little-endian encoded uint16 value from the underlying
// io.Reader. On read failures it returns zero.
func (r *BinReader) ReadU16LE() uint16 {
r.ReadBytes(r.u16)
if r.Err != nil {
return 0
}
return binary.LittleEndian.Uint16(r.u16)
}
// ReadU16BE reads a big-endian encoded uint16 value from the underlying
// io.Reader. On read failures it returns zero.
func (r *BinReader) ReadU16BE() uint16 {
r.ReadBytes(r.u16)
if r.Err != nil {
return 0
}
return binary.BigEndian.Uint16(r.u16)
}
// ReadByte reads a byte from the underlying io.Reader. On read failures it
// returns zero.
func (r *BinReader) ReadByte() byte {
r.ReadBytes(r.u8)
if r.Err != nil {
return 0
}
return r.u8[0]
}
// ReadBool reads a boolean value encoded in a zero/non-zero byte from the
// underlying io.Reader. On read failures it returns false.
func (r *BinReader) ReadBool() bool {
return r.ReadByte() != 0
}
// ReadArray reads array into value which must be // ReadArray reads array into value which must be
// a pointer to a slice. // a pointer to a slice.
func (r *BinReader) ReadArray(t interface{}, maxSize ...int) { func (r *BinReader) ReadArray(t interface{}, maxSize ...int) {

View file

@ -11,12 +11,20 @@ import (
// from a struct with many fields. // from a struct with many fields.
type BinWriter struct { type BinWriter struct {
w io.Writer w io.Writer
u64 []byte
u32 []byte
u16 []byte
u8 []byte
Err error Err error
} }
// NewBinWriterFromIO makes a BinWriter from io.Writer. // NewBinWriterFromIO makes a BinWriter from io.Writer.
func NewBinWriterFromIO(iow io.Writer) *BinWriter { func NewBinWriterFromIO(iow io.Writer) *BinWriter {
return &BinWriter{w: iow} u64 := make([]byte, 8)
u32 := u64[:4]
u16 := u64[:2]
u8 := u64[:1]
return &BinWriter{w: iow, u64: u64, u32: u32, u16: u16, u8: u8}
} }
// 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.
@ -35,6 +43,50 @@ func (w *BinWriter) WriteBE(v interface{}) {
w.Err = binary.Write(w.w, binary.BigEndian, v) w.Err = binary.Write(w.w, binary.BigEndian, v)
} }
// WriteU64LE writes an uint64 value into the underlying io.Writer in
// little-endian format.
func (w *BinWriter) WriteU64LE(u64 uint64) {
binary.LittleEndian.PutUint64(w.u64, u64)
w.WriteBytes(w.u64)
}
// WriteU32LE writes an uint32 value into the underlying io.Writer in
// little-endian format.
func (w *BinWriter) WriteU32LE(u32 uint32) {
binary.LittleEndian.PutUint32(w.u32, u32)
w.WriteBytes(w.u32)
}
// WriteU16LE writes an uint16 value into the underlying io.Writer in
// little-endian format.
func (w *BinWriter) WriteU16LE(u16 uint16) {
binary.LittleEndian.PutUint16(w.u16, u16)
w.WriteBytes(w.u16)
}
// WriteU16BE writes an uint16 value into the underlying io.Writer in
// big-endian format.
func (w *BinWriter) WriteU16BE(u16 uint16) {
binary.BigEndian.PutUint16(w.u16, u16)
w.WriteBytes(w.u16)
}
// WriteByte writes a byte into the underlying io.Writer.
func (w *BinWriter) WriteByte(u8 byte) {
w.u8[0] = u8
w.WriteBytes(w.u8)
}
// WriteBool writes a boolean value into the underlying io.Writer encoded as
// a byte with values of 0 or 1.
func (w *BinWriter) WriteBool(b bool) {
var i byte
if b {
i = 1
}
w.WriteByte(i)
}
// WriteArray writes a slice or an array arr into w. Note that nil slices and // WriteArray writes a slice or an array arr into w. Note that nil slices and
// empty slices are gonna be treated the same resulting in equal zero-length // empty slices are gonna be treated the same resulting in equal zero-length
// array encoded. // array encoded.

View file

@ -53,6 +53,123 @@ func TestWriteBE(t *testing.T) {
assert.Equal(t, val, readval) assert.Equal(t, val, readval)
} }
func TestWriteU64LE(t *testing.T) {
var (
val uint64 = 0xbadc0de15a11dead
readval uint64
bin = []byte{0xad, 0xde, 0x11, 0x5a, 0xe1, 0x0d, 0xdc, 0xba}
)
bw := NewBufBinWriter()
bw.WriteU64LE(val)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
readval = br.ReadU64LE()
assert.Nil(t, br.Err)
assert.Equal(t, val, readval)
}
func TestWriteU32LE(t *testing.T) {
var (
val uint32 = 0xdeadbeef
readval uint32
bin = []byte{0xef, 0xbe, 0xad, 0xde}
)
bw := NewBufBinWriter()
bw.WriteU32LE(val)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
readval = br.ReadU32LE()
assert.Nil(t, br.Err)
assert.Equal(t, val, readval)
}
func TestWriteU16LE(t *testing.T) {
var (
val uint16 = 0xbabe
readval uint16
bin = []byte{0xbe, 0xba}
)
bw := NewBufBinWriter()
bw.WriteU16LE(val)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
readval = br.ReadU16LE()
assert.Nil(t, br.Err)
assert.Equal(t, val, readval)
}
func TestWriteU16BE(t *testing.T) {
var (
val uint16 = 0xbabe
readval uint16
bin = []byte{0xba, 0xbe}
)
bw := NewBufBinWriter()
bw.WriteU16BE(val)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
readval = br.ReadU16BE()
assert.Nil(t, br.Err)
assert.Equal(t, val, readval)
}
func TestWriteByte(t *testing.T) {
var (
val byte = 0xa5
readval byte
bin = []byte{0xa5}
)
bw := NewBufBinWriter()
bw.WriteByte(val)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
readval = br.ReadByte()
assert.Nil(t, br.Err)
assert.Equal(t, val, readval)
}
func TestWriteBool(t *testing.T) {
var (
bin = []byte{0x01, 0x00}
)
bw := NewBufBinWriter()
bw.WriteBool(true)
bw.WriteBool(false)
assert.Nil(t, bw.Err)
wrotebin := bw.Bytes()
assert.Equal(t, wrotebin, bin)
br := NewBinReaderFromBuf(bin)
assert.Equal(t, true, br.ReadBool())
assert.Equal(t, false, br.ReadBool())
assert.Nil(t, br.Err)
}
func TestReadLEErrors(t *testing.T) {
bin := []byte{0xad, 0xde, 0x11, 0x5a, 0xe1, 0x0d, 0xdc, 0xba}
br := NewBinReaderFromBuf(bin)
// Prime the buffers with something.
_ = br.ReadU64LE()
assert.Nil(t, br.Err)
assert.Equal(t, uint64(0), br.ReadU64LE())
assert.Equal(t, uint32(0), br.ReadU32LE())
assert.Equal(t, uint16(0), br.ReadU16LE())
assert.Equal(t, uint16(0), br.ReadU16BE())
assert.Equal(t, byte(0), br.ReadByte())
assert.Equal(t, false, br.ReadBool())
assert.NotNil(t, br.Err)
}
func TestBufBinWriter_Len(t *testing.T) { func TestBufBinWriter_Len(t *testing.T) {
val := []byte{0xde} val := []byte{0xde}
bw := NewBufBinWriter() bw := NewBufBinWriter()

View file

@ -17,7 +17,7 @@ type smthSerializable struct {
func (*smthSerializable) DecodeBinary(*io.BinReader) {} func (*smthSerializable) DecodeBinary(*io.BinReader) {}
func (ss *smthSerializable) EncodeBinary(bw *io.BinWriter) { func (ss *smthSerializable) EncodeBinary(bw *io.BinWriter) {
bw.WriteLE(ss.some) bw.WriteBytes(ss.some[:])
} }
// Mock structure that gives error in EncodeBinary(). // Mock structure that gives error in EncodeBinary().

View file

@ -149,10 +149,10 @@ func (m *Message) CommandType() CommandType {
// Decode decodes a Message from the given reader. // Decode decodes a Message from the given reader.
func (m *Message) Decode(br *io.BinReader) error { func (m *Message) Decode(br *io.BinReader) error {
br.ReadLE(&m.Magic) m.Magic = config.NetMode(br.ReadU32LE())
br.ReadBytes(m.Command[:]) br.ReadBytes(m.Command[:])
br.ReadLE(&m.Length) m.Length = br.ReadU32LE()
br.ReadLE(&m.Checksum) m.Checksum = br.ReadU32LE()
if br.Err != nil { if br.Err != nil {
return br.Err return br.Err
} }
@ -165,7 +165,7 @@ func (m *Message) Decode(br *io.BinReader) error {
func (m *Message) decodePayload(br *io.BinReader) error { func (m *Message) decodePayload(br *io.BinReader) error {
buf := make([]byte, m.Length) buf := make([]byte, m.Length)
br.ReadLE(buf) br.ReadBytes(buf)
if br.Err != nil { if br.Err != nil {
return br.Err return br.Err
} }
@ -212,10 +212,10 @@ func (m *Message) decodePayload(br *io.BinReader) error {
// Encode encodes a Message to any given BinWriter. // Encode encodes a Message to any given BinWriter.
func (m *Message) Encode(br *io.BinWriter) error { func (m *Message) Encode(br *io.BinWriter) error {
br.WriteLE(m.Magic) br.WriteU32LE(uint32(m.Magic))
br.WriteBytes(m.Command[:]) br.WriteBytes(m.Command[:])
br.WriteLE(m.Length) br.WriteU32LE(m.Length)
br.WriteLE(m.Checksum) br.WriteU32LE(m.Checksum)
if m.Payload != nil { if m.Payload != nil {
m.Payload.EncodeBinary(br) m.Payload.EncodeBinary(br)

View file

@ -29,18 +29,18 @@ func NewAddressAndTime(e *net.TCPAddr, t time.Time) *AddressAndTime {
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (p *AddressAndTime) DecodeBinary(br *io.BinReader) { func (p *AddressAndTime) DecodeBinary(br *io.BinReader) {
br.ReadLE(&p.Timestamp) p.Timestamp = br.ReadU32LE()
br.ReadLE(&p.Services) p.Services = br.ReadU64LE()
br.ReadBytes(p.IP[:]) br.ReadBytes(p.IP[:])
br.ReadBE(&p.Port) p.Port = br.ReadU16BE()
} }
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (p *AddressAndTime) EncodeBinary(bw *io.BinWriter) { func (p *AddressAndTime) EncodeBinary(bw *io.BinWriter) {
bw.WriteLE(p.Timestamp) bw.WriteU32LE(p.Timestamp)
bw.WriteLE(p.Services) bw.WriteU64LE(p.Services)
bw.WriteBytes(p.IP[:]) bw.WriteBytes(p.IP[:])
bw.WriteBE(p.Port) bw.WriteU16BE(p.Port)
} }
// IPPortString makes a string from IP and port specified. // IPPortString makes a string from IP and port specified.

View file

@ -56,12 +56,12 @@ func NewInventory(typ InventoryType, hashes []util.Uint256) *Inventory {
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (p *Inventory) DecodeBinary(br *io.BinReader) { func (p *Inventory) DecodeBinary(br *io.BinReader) {
br.ReadLE(&p.Type) p.Type = InventoryType(br.ReadByte())
br.ReadArray(&p.Hashes) br.ReadArray(&p.Hashes)
} }
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (p *Inventory) EncodeBinary(bw *io.BinWriter) { func (p *Inventory) EncodeBinary(bw *io.BinWriter) {
bw.WriteLE(p.Type) bw.WriteByte(byte(p.Type))
bw.WriteArray(p.Hashes) bw.WriteArray(p.Hashes)
} }

View file

@ -55,25 +55,25 @@ func NewVersion(id uint32, p uint16, ua string, h uint32, r bool) *Version {
// DecodeBinary implements Serializable interface. // DecodeBinary implements Serializable interface.
func (p *Version) DecodeBinary(br *io.BinReader) { func (p *Version) DecodeBinary(br *io.BinReader) {
br.ReadLE(&p.Version) p.Version = br.ReadU32LE()
br.ReadLE(&p.Services) p.Services = br.ReadU64LE()
br.ReadLE(&p.Timestamp) p.Timestamp = br.ReadU32LE()
br.ReadLE(&p.Port) p.Port = br.ReadU16LE()
br.ReadLE(&p.Nonce) p.Nonce = br.ReadU32LE()
p.UserAgent = br.ReadVarBytes() p.UserAgent = br.ReadVarBytes()
br.ReadLE(&p.StartHeight) p.StartHeight = br.ReadU32LE()
br.ReadLE(&p.Relay) p.Relay = br.ReadBool()
} }
// EncodeBinary implements Serializable interface. // EncodeBinary implements Serializable interface.
func (p *Version) EncodeBinary(br *io.BinWriter) { func (p *Version) EncodeBinary(br *io.BinWriter) {
br.WriteLE(p.Version) br.WriteU32LE(p.Version)
br.WriteLE(p.Services) br.WriteU64LE(p.Services)
br.WriteLE(p.Timestamp) br.WriteU32LE(p.Timestamp)
br.WriteLE(p.Port) br.WriteU16LE(p.Port)
br.WriteLE(p.Nonce) br.WriteU32LE(p.Nonce)
br.WriteVarBytes(p.UserAgent) br.WriteVarBytes(p.UserAgent)
br.WriteLE(p.StartHeight) br.WriteU32LE(p.StartHeight)
br.WriteLE(&p.Relay) br.WriteBool(p.Relay)
} }

View file

@ -188,7 +188,7 @@ func initServerWithInMemoryChain(t *testing.T) (*core.Blockchain, http.HandlerFu
f, err := os.Open("testdata/50testblocks.acc") f, err := os.Open("testdata/50testblocks.acc")
require.Nil(t, err) require.Nil(t, err)
br := io.NewBinReaderFromIO(f) br := io.NewBinReaderFromIO(f)
br.ReadLE(&nBlocks) nBlocks = br.ReadU32LE()
require.Nil(t, br.Err) require.Nil(t, br.Err)
for i := 0; i < int(nBlocks); i++ { for i := 0; i < int(nBlocks); i++ {
block := &core.Block{} block := &core.Block{}

View file

@ -22,9 +22,7 @@ func TestCreateMultiSigRedeemScript(t *testing.T) {
} }
br := io.NewBinReaderFromBuf(out) br := io.NewBinReaderFromBuf(out)
var b uint8 assert.Equal(t, opcode.PUSH3, opcode.Opcode(br.ReadByte()))
br.ReadLE(&b)
assert.Equal(t, opcode.PUSH3, opcode.Opcode(b))
for i := 0; i < len(validators); i++ { for i := 0; i < len(validators); i++ {
bb := br.ReadVarBytes() bb := br.ReadVarBytes()
@ -34,8 +32,6 @@ func TestCreateMultiSigRedeemScript(t *testing.T) {
assert.Equal(t, validators[i].Bytes(), bb) assert.Equal(t, validators[i].Bytes(), bb)
} }
br.ReadLE(&b) assert.Equal(t, opcode.PUSH3, opcode.Opcode(br.ReadByte()))
assert.Equal(t, opcode.PUSH3, opcode.Opcode(b)) assert.Equal(t, opcode.CHECKMULTISIG, opcode.Opcode(br.ReadByte()))
br.ReadLE(&b)
assert.Equal(t, opcode.CHECKMULTISIG, opcode.Opcode(b))
} }

View file

@ -80,12 +80,12 @@ func (pt ParamType) MarshalJSON() ([]byte, error) {
// EncodeBinary implements io.Serializable interface. // EncodeBinary implements io.Serializable interface.
func (pt ParamType) EncodeBinary(w *io.BinWriter) { func (pt ParamType) EncodeBinary(w *io.BinWriter) {
w.WriteBytes([]byte{byte(pt)}) w.WriteByte(byte(pt))
} }
// DecodeBinary implements io.Serializable interface. // DecodeBinary implements io.Serializable interface.
func (pt *ParamType) DecodeBinary(r *io.BinReader) { func (pt *ParamType) DecodeBinary(r *io.BinReader) {
r.ReadLE(pt) *pt = ParamType(r.ReadByte())
} }
// NewParameter returns a Parameter with proper initialized Value // NewParameter returns a Parameter with proper initialized Value

View file

@ -5,6 +5,8 @@ import (
"errors" "errors"
"strconv" "strconv"
"strings" "strings"
"github.com/CityOfZion/neo-go/pkg/io"
) )
const ( const (
@ -109,6 +111,16 @@ func (f Fixed8) MarshalJSON() ([]byte, error) {
return []byte(`"` + f.String() + `"`), nil return []byte(`"` + f.String() + `"`), nil
} }
// DecodeBinary implements the io.Serializable interface.
func (f *Fixed8) DecodeBinary(r *io.BinReader) {
*f = Fixed8(r.ReadU64LE())
}
// EncodeBinary implements the io.Serializable interface.
func (f *Fixed8) EncodeBinary(w *io.BinWriter) {
w.WriteU64LE(uint64(*f))
}
// Satoshi defines the value of a 'Satoshi'. // Satoshi defines the value of a 'Satoshi'.
func Satoshi() Fixed8 { func Satoshi() Fixed8 {
return Fixed8(1) return Fixed8(1)

View file

@ -5,7 +5,9 @@ import (
"strconv" "strconv"
"testing" "testing"
"github.com/CityOfZion/neo-go/pkg/io"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
) )
func TestFixed8FromInt64(t *testing.T) { func TestFixed8FromInt64(t *testing.T) {
@ -134,3 +136,16 @@ func TestFixed8_Arith(t *testing.T) {
assert.Zero(t, u1.CompareTo(u1)) assert.Zero(t, u1.CompareTo(u1))
assert.EqualValues(t, Fixed8(2), u2.Div(3)) assert.EqualValues(t, Fixed8(2), u2.Div(3))
} }
func TestFixed8_Serializable(t *testing.T) {
a := Fixed8(0x0102030405060708)
w := io.NewBufBinWriter()
a.EncodeBinary(w.BinWriter)
require.NoError(t, w.Err)
var b Fixed8
r := io.NewBinReaderFromBuf(w.Bytes())
b.DecodeBinary(r)
require.Equal(t, a, b)
}

View file

@ -50,26 +50,22 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) {
} }
r := io.NewBinReaderFromBuf(c.prog[c.ip:]) r := io.NewBinReaderFromBuf(c.prog[c.ip:])
var instrbyte byte var instrbyte = r.ReadByte()
r.ReadLE(&instrbyte)
instr := opcode.Opcode(instrbyte) instr := opcode.Opcode(instrbyte)
c.nextip++ c.nextip++
var numtoread int var numtoread int
switch instr { switch instr {
case opcode.PUSHDATA1, opcode.SYSCALL: case opcode.PUSHDATA1, opcode.SYSCALL:
var n byte var n = r.ReadByte()
r.ReadLE(&n)
numtoread = int(n) numtoread = int(n)
c.nextip++ c.nextip++
case opcode.PUSHDATA2: case opcode.PUSHDATA2:
var n uint16 var n = r.ReadU16LE()
r.ReadLE(&n)
numtoread = int(n) numtoread = int(n)
c.nextip += 2 c.nextip += 2
case opcode.PUSHDATA4: case opcode.PUSHDATA4:
var n uint32 var n = r.ReadU32LE()
r.ReadLE(&n)
if n > MaxItemSize { if n > MaxItemSize {
return instr, nil, errors.New("parameter is too big") return instr, nil, errors.New("parameter is too big")
} }
@ -92,7 +88,7 @@ func (c *Context) Next() (opcode.Opcode, []byte, error) {
} }
} }
parameter := make([]byte, numtoread) parameter := make([]byte, numtoread)
r.ReadLE(parameter) r.ReadBytes(parameter)
if r.Err != nil { if r.Err != nil {
return instr, nil, errors.New("failed to read instruction parameter") return instr, nil, errors.New("failed to read instruction parameter")
} }

View file

@ -47,7 +47,7 @@ func serializeItemTo(item StackItem, w *io.BinWriter, seen map[StackItem]bool) {
w.WriteVarBytes(t.value) w.WriteVarBytes(t.value)
case *BoolItem: case *BoolItem:
w.WriteBytes([]byte{byte(booleanT)}) w.WriteBytes([]byte{byte(booleanT)})
w.WriteLE(t.value) w.WriteBool(t.value)
case *BigIntegerItem: case *BigIntegerItem:
w.WriteBytes([]byte{byte(integerT)}) w.WriteBytes([]byte{byte(integerT)})
w.WriteVarBytes(t.Bytes()) w.WriteVarBytes(t.Bytes())
@ -94,8 +94,7 @@ func deserializeItem(data []byte) (StackItem, error) {
// as a function because StackItem itself is an interface. Caveat: always check // as a function because StackItem itself is an interface. Caveat: always check
// reader's error value before using the returned StackItem. // reader's error value before using the returned StackItem.
func DecodeBinaryStackItem(r *io.BinReader) StackItem { func DecodeBinaryStackItem(r *io.BinReader) StackItem {
var t byte var t = r.ReadByte()
r.ReadLE(&t)
if r.Err != nil { if r.Err != nil {
return nil return nil
} }
@ -105,8 +104,7 @@ func DecodeBinaryStackItem(r *io.BinReader) StackItem {
data := r.ReadVarBytes() data := r.ReadVarBytes()
return NewByteArrayItem(data) return NewByteArrayItem(data)
case booleanT: case booleanT:
var b bool var b = r.ReadBool()
r.ReadLE(&b)
return NewBoolItem(b) return NewBoolItem(b)
case integerT: case integerT:
data := r.ReadVarBytes() data := r.ReadVarBytes()