neo-go/pkg/network/payload/extensible.go
Roman Khimov 6fd5f4e86d payload: extensible payload hashes are network-dependent
Of course they are. Fixes

2021-02-04T13:39:02.351Z        WARN    peer disconnected       {"addr": "172.29.0.4:20333", "reason": "handling CMDExtensible message: signature check failed: invalid signature", "peerCount": 3}
2021-02-04T13:39:02.352Z        WARN    peer disconnected       {"addr": "172.29.0.3:20334", "reason": "handling CMDExtensible message: signature check failed: invalid signature", "peerCount": 2}

in 2+2 setting.
2021-02-04 16:50:51 +03:00

127 lines
3.1 KiB
Go

package payload
import (
"errors"
"math"
"github.com/nspcc-dev/neo-go/pkg/config/netmode"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/hash"
"github.com/nspcc-dev/neo-go/pkg/io"
"github.com/nspcc-dev/neo-go/pkg/util"
)
const (
maxExtensibleCategorySize = 32
maxExtensibleDataSize = math.MaxUint16
)
// Extensible represents payload containing arbitrary data.
type Extensible struct {
// Network represents network magic.
Network netmode.Magic
// Category is payload type.
Category string
// ValidBlockStart is starting height for payload to be valid.
ValidBlockStart uint32
// ValidBlockEnd is height after which payload becomes invalid.
ValidBlockEnd uint32
// Sender is payload sender or signer.
Sender util.Uint160
// Data is custom payload data.
Data []byte
// Witness is payload witness.
Witness transaction.Witness
hash util.Uint256
signedHash util.Uint256
signedpart []byte
}
var errInvalidPadding = errors.New("invalid padding")
// NewExtensible creates new extensible payload.
func NewExtensible(network netmode.Magic) *Extensible {
return &Extensible{Network: network}
}
func (e *Extensible) encodeBinaryUnsigned(w *io.BinWriter) {
w.WriteString(e.Category)
w.WriteU32LE(e.ValidBlockStart)
w.WriteU32LE(e.ValidBlockEnd)
w.WriteBytes(e.Sender[:])
w.WriteVarBytes(e.Data)
}
// EncodeBinary implements io.Serializable.
func (e *Extensible) EncodeBinary(w *io.BinWriter) {
e.encodeBinaryUnsigned(w)
w.WriteB(1)
e.Witness.EncodeBinary(w)
}
func (e *Extensible) decodeBinaryUnsigned(r *io.BinReader) {
e.Category = r.ReadString(maxExtensibleCategorySize)
e.ValidBlockStart = r.ReadU32LE()
e.ValidBlockEnd = r.ReadU32LE()
r.ReadBytes(e.Sender[:])
e.Data = r.ReadVarBytes(maxExtensibleDataSize)
}
// DecodeBinary implements io.Serializable.
func (e *Extensible) DecodeBinary(r *io.BinReader) {
e.decodeBinaryUnsigned(r)
if r.ReadB() != 1 {
if r.Err != nil {
return
}
r.Err = errInvalidPadding
return
}
e.Witness.DecodeBinary(r)
}
// GetSignedPart implements crypto.Verifiable.
func (e *Extensible) GetSignedPart() []byte {
if e.signedpart == nil {
e.updateSignedPart()
}
return e.signedpart
}
// GetSignedHash implements crypto.Verifiable.
func (e *Extensible) GetSignedHash() util.Uint256 {
if e.signedHash.Equals(util.Uint256{}) {
e.createHash()
}
return e.signedHash
}
// Hash returns payload hash.
func (e *Extensible) Hash() util.Uint256 {
if e.hash.Equals(util.Uint256{}) {
e.createHash()
}
return e.hash
}
// createHash creates hashes of the payload.
func (e *Extensible) createHash() {
b := e.GetSignedPart()
e.updateHashes(b)
}
// updateHashes updates hashes based on the given buffer which should
// be a signable data slice.
func (e *Extensible) updateHashes(b []byte) {
e.signedHash = hash.Sha256(b)
e.hash = hash.Sha256(e.signedHash.BytesBE())
}
// updateSignedPart updates serialized message if needed.
func (e *Extensible) updateSignedPart() {
w := io.NewBufBinWriter()
w.WriteU32LE(uint32(e.Network))
e.encodeBinaryUnsigned(w.BinWriter)
e.signedpart = w.Bytes()
}