This commit is contained in:
iteye 2026-07-06 18:44:27 +08:00
parent 9db15e21f4
commit 9292105a4a
4 changed files with 43 additions and 37 deletions

View file

@ -239,7 +239,6 @@ type DestroyClusterPeerConnectionCommand struct {
// FIELDS = [("root_block", RootBlock), ("expect_switch", boolean)]
type AddRootBlockRequest struct {
// TODO: Replace with *RootBlock once core.RootBlock is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
RootBlock *RawBytes
ExpectSwitch bool
}
@ -346,7 +345,6 @@ type AccountBranchData struct {
Branch uint32
TransactionCount *big.Int // uint256
// TODO: Replace with *TokenBalanceMap once core.TokenBalanceMap is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
TokenBalances *RawBytes
IsContract bool
PoswMineableBlocks uint16
@ -415,12 +413,10 @@ type ShardStats struct {
// ]
type AddMinorBlockHeaderRequest struct {
// TODO: Replace with *MinorBlockHeader once core.MinorBlockHeader is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
MinorBlockHeader *RawBytes
TxCount uint32
XShardTxCount uint32
// TODO: Replace with *TokenBalanceMap once core.TokenBalanceMap is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
CoinbaseAmountMap *RawBytes
ShardStats ShardStats
}
@ -461,7 +457,6 @@ type SyncMinorBlockListRequest struct {
type SyncMinorBlockListResponse struct {
ErrorCode uint32
// TODO: Replace with real block_coinbase_map once core.TokenBalanceMap is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
BlockCoinbaseMap *RawBytes
ShardStats *ShardStats `ser:"nil"`
}
@ -489,7 +484,6 @@ type GetMinorBlockRequest struct {
type GetMinorBlockResponse struct {
ErrorCode uint32
// TODO: Replace with *MinorBlock once core.MinorBlock is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
MinorBlock *RawBytes
ExtraInfo *MinorBlockExtraInfo `ser:"nil"`
}
@ -504,7 +498,6 @@ type GetTransactionRequest struct {
type GetTransactionResponse struct {
ErrorCode uint32
// TODO: Replace with *MinorBlock once core.MinorBlock is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
MinorBlock *RawBytes
Index uint32
}
@ -512,7 +505,6 @@ type GetTransactionResponse struct {
// ExecuteTransactionRequest (ClusterOp.EXECUTE_TRANSACTION_REQUEST, 0xA3).
type ExecuteTransactionRequest struct {
// TODO: Replace with *TypedTransaction once core.TypedTransaction is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
Tx *RawBytes
FromAddress [AddressLength]byte
BlockHeight *uint64 `ser:"nil"`
@ -534,7 +526,6 @@ type GetTransactionReceiptRequest struct {
type GetTransactionReceiptResponse struct {
ErrorCode uint32
// TODO: Replace with *MinorBlock once core.MinorBlock is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
MinorBlock *RawBytes
Index uint32
// TODO: Replace with *TransactionReceipt once core.TransactionReceipt is ported.
@ -612,7 +603,6 @@ type GetLogResponse struct {
// EstimateGasRequest (ClusterOp.ESTIMATE_GAS_REQUEST, 0xAF).
type EstimateGasRequest struct {
// TODO: Replace with *TypedTransaction once core.TypedTransaction is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
Tx *RawBytes
FromAddress [AddressLength]byte
}
@ -773,7 +763,6 @@ type HelloCommand struct {
PeerPort uint16
ChainMaskList []uint32 `bytesizeofslicelen:"4"`
// TODO: Replace with *RootBlockHeader once core.RootBlockHeader is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
RootBlockHeader *RawBytes
GenesisRootBlockHash [HashLength]byte
}
@ -781,7 +770,6 @@ type HelloCommand struct {
// NewMinorBlockHeaderListCommand (CommandOp.NEW_MINOR_BLOCK_HEADER_LIST, 0x01).
type NewMinorBlockHeaderListCommand struct {
// TODO: Replace with *RootBlockHeader once core.RootBlockHeader is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
RootBlockHeader *RawBytes
MinorBlockHeaderList []*RawBytes `bytesizeofslicelen:"4"` // TODO: Replace with []*MinorBlockHeader once core.MinorBlockHeader is ported
}
@ -836,7 +824,6 @@ type GetRootBlockHeaderListRequest struct {
// GetRootBlockHeaderListResponse (CommandOp.GET_ROOT_BLOCK_HEADER_LIST_RESPONSE, 0x06).
type GetRootBlockHeaderListResponse struct {
// TODO: Replace with *RootBlockHeader once core.RootBlockHeader is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
RootTip *RawBytes
BlockHeaderList []*RawBytes `bytesizeofslicelen:"4"` // TODO: Replace with []*RootBlockHeader once core.RootBlockHeader is ported
}
@ -881,10 +868,8 @@ type GetMinorBlockHeaderListRequest struct {
// GetMinorBlockHeaderListResponse (CommandOp.GET_MINOR_BLOCK_HEADER_LIST_RESPONSE, 0x0C).
type GetMinorBlockHeaderListResponse struct {
// TODO: Replace with *RootBlockHeader once core.RootBlockHeader is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
RootTip *RawBytes
// TODO: Replace with *MinorBlockHeader once core.MinorBlockHeader is ported.
// WARNING: not the last field; RawBytes.Deserialize consumes remaining bytes.
ShardTip *RawBytes
BlockHeaderList []*RawBytes `bytesizeofslicelen:"4"` // TODO: Replace with []*MinorBlockHeader once core.MinorBlockHeader is ported
}

View file

@ -357,8 +357,17 @@ func TestNonOptionalRawBytes_NoMarker(t *testing.T) {
if err := serialize.Serialize(&buf, &req); err != nil {
t.Fatalf("Serialize: %v", err)
}
if buf[0] != 0xAA {
t.Errorf("non-optional RawBytes should not have presence marker, got %x", buf[0])
// RawBytes now uses 4-byte length prefix, so first bytes should be 00000001 (length=1)
// followed by AA (actual data), then 01 (ExpectSwitch=true)
want := []byte{0x00, 0x00, 0x00, 0x01, 0xAA, 0x01}
if len(buf) < len(want) {
t.Fatalf("buffer too short: got %d bytes, want at least %d", len(buf), len(want))
}
for i, b := range want {
if buf[i] != b {
t.Errorf("byte %d: got %x, want %x\nfull buf: %x", i, buf[i], b, buf)
break
}
}
}

View file

@ -39,14 +39,16 @@
// RawBytes Semantics
// -----------------------------------------------------------------------------
//
// RawBytes is a terminal wire sink type.
// RawBytes is a bounded-length passthrough placeholder.
//
// It represents an opaque byte segment whose internal structure is defined
// by the Python FIELDS schema but is not yet implemented in Go.
//
// Wire behavior:
// - Serialize: writes raw bytes unchanged
// - Deserialize: consumes ALL remaining bytes in buffer
// - Serialize: writes 4-byte length prefix + raw bytes (matches Python PrependedSizeBytesSerializer(4))
// - Deserialize: reads 4-byte length prefix + corresponding bytes
//
// This design allows RawBytes to be used in ANY struct position (not just last field).
//
// -----------------------------------------------------------------------------
// SAFETY CONSTRAINTS
@ -54,10 +56,9 @@
//
// RawBytes MUST obey the following rules:
//
// 1. MUST only appear as the LAST field in a struct
// 2. MUST NOT be partially decoded or inspected
// 3. MUST NOT be used in stable protocol definitions
// 4. MUST be removed once real Go types are introduced
// 1. MUST NOT be partially decoded or inspected
// 2. MUST NOT be used in stable protocol definitions
// 3. MUST be removed once real Go types are introduced
//
// Any violation of these rules results in undefined wire behavior.
//
@ -81,6 +82,7 @@
package wire
import (
"encoding/binary"
"fmt"
"github.com/ethereum/go-ethereum/qkc/serialize"
@ -95,28 +97,36 @@ func (r RawBytes) Serialize(w *[]byte) error {
return fmt.Errorf("RawBytes.Serialize: size %d exceeds max %d", len(r), maxRawBytesSize)
}
// Write 4-byte length prefix (matches Python PrependedSizeBytesSerializer(4))
lenBuf := make([]byte, 4)
binary.BigEndian.PutUint32(lenBuf, uint32(len(r)))
*w = append(*w, lenBuf...)
*w = append(*w, r...)
return nil
}
// Deserialize consumes all remaining bytes from the buffer.
//
// SAFETY: This is only safe when RawBytes is the LAST field in its parent
// struct. If RawBytes appears before other fields, consuming the remaining
// bytes will corrupt subsequent fields. Structs with non-last RawBytes fields
// are marked with a WARNING in messages.go and cannot be correctly deserialized
// until the real Go type is ported.
// Deserialize reads 4-byte length prefix and corresponding bytes.
//
// TEMPORARY: Delete this placeholder once real types (RootBlock, MinorBlockHeader) are ported.
func (r *RawBytes) Deserialize(bb *serialize.ByteBuffer) error {
const maxRawBytesSize = 100 * 1024 * 1024 // 100 MB, matches Serialize
if bb.Remaining() > maxRawBytesSize {
return fmt.Errorf("RawBytes.Deserialize: size %d exceeds max %d", bb.Remaining(), maxRawBytesSize)
}
bytes, err := bb.ReadRemaining()
// Read 4-byte length prefix
length, err := bb.GetUInt32()
if err != nil {
return err
}
if length > maxRawBytesSize {
return fmt.Errorf("RawBytes.Deserialize: length %d exceeds max %d", length, maxRawBytesSize)
}
// Read the actual bytes
bytes, err := bb.ReadBytes(int(length))
if err != nil {
return err
}
*r = RawBytes(bytes)
return nil
}

View file

@ -74,13 +74,15 @@ func (p *PrependedSizeHashList4) Deserialize(bb *serialize.ByteBuffer) error {
return fmt.Errorf("PrependedSizeHashList4.Deserialize: length %d exceeds capacity", length)
}
list := make([][HashLength]byte, length)
list := make([][HashLength]byte, int(length))
for i := 0; i < int(length); i++ {
hashBytes, err := bb.ReadBytes(HashLength)
if err != nil {
return err
}
list[i] = [HashLength]byte(hashBytes)
var hash [HashLength]byte
copy(hash[:], hashBytes)
list[i] = hash
}
*p = PrependedSizeHashList4(list)