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

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

View file

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

View file

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

View file

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

View file

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