Skip to content

Commit 357831e

Browse files
rlp: fix encoding/decoding of state-sync tx (#43)
* rlp: fix encoding/decoding of state-sync tx * chore: add state-sync tx receipt in Finalize * ssTxs: fix receiptsHash mismatch * chore: remove block hash and number * revert: add block number * fix: rpc fixes * polygon/sync: announce blocks/hashes for blocks received via hash announcements (#44) * fix: log slicing in newStateSyncReceipt --------- Co-authored-by: Manav Darji <manavdarji.india@gmail.com>
1 parent 4befd04 commit 357831e

File tree

9 files changed

+101
-49
lines changed

9 files changed

+101
-49
lines changed

core/vm/evmtypes/rules.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,7 @@ func (bc *BlockContext) Rules(c *chain.Config) *chain.Rules {
4747
IsPrague: c.IsPrague(bc.Time) || c.IsBhilai(bc.BlockNumber),
4848
IsOsaka: c.IsOsaka(bc.Time),
4949
IsAura: c.Aura != nil,
50+
IsRio: c.IsRio(bc.BlockNumber),
51+
IsStateSync: c.IsStateSync(bc.BlockNumber),
5052
}
5153
}

execution/chain/chain_config.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,16 @@ func (c *Config) IsBhilai(num uint64) bool {
334334
return (c != nil) && (c.Bor != nil) && c.Bor.IsBhilai(num)
335335
}
336336

337+
// IsRio returns whether num is either equal to the Rio fork block or greater.
338+
func (c *Config) IsRio(num uint64) bool {
339+
return (c != nil) && (c.Bor != nil) && c.Bor.IsRio(num)
340+
}
341+
342+
// IsStateSync returns whether num is either equal to the StateSync fork block or greater.
343+
func (c *Config) IsStateSync(num uint64) bool {
344+
return (c != nil) && (c.Bor != nil) && c.Bor.IsStateSync(num)
345+
}
346+
337347
// IsCancun returns whether time is either equal to the Cancun fork time or greater.
338348
func (c *Config) IsCancun(time uint64) bool {
339349
return isForked(c.CancunTime, time)
@@ -703,10 +713,9 @@ type Rules struct {
703713
IsHomestead, IsTangerineWhistle, IsSpuriousDragon bool
704714
IsByzantium, IsConstantinople, IsPetersburg bool
705715
IsIstanbul, IsBerlin, IsLondon, IsShanghai bool
706-
IsCancun, IsNapoli, IsBhilai bool
716+
IsCancun, IsNapoli, IsBhilai, IsRio, IsStateSync bool
707717
IsPrague, IsOsaka bool
708718
IsAura bool
709-
IsStateSync bool // TODO define a name when we have a fork that enables it
710719
}
711720

712721
// isForked returns whether a fork scheduled at block s is active at the given head block.

execution/stagedsync/stage_senders.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,12 @@ func recoverSenders(ctx context.Context, logPrefix string, cryptoContext *secp25
353353
signer := types.MakeSigner(config, job.blockNumber, job.blockTime)
354354
job.senders = make([]byte, len(body.Transactions)*length.Addr)
355355
for i, txn := range body.Transactions {
356+
// Skip StateSyncTx - they have no sender.
357+
if txn.Type() == types.StateSyncTxType {
358+
// Leave sender as zero address
359+
continue
360+
}
361+
356362
from, err := signer.SenderWithContext(cryptoContext, txn)
357363
if err != nil {
358364
job.err = fmt.Errorf("%w: error recovering sender for tx=%x, %v",

execution/types/receipt.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,7 @@ func (r *Receipt) decodeTyped(b []byte) error {
214214
return errShortTypedReceipt
215215
}
216216
switch b[0] {
217-
case DynamicFeeTxType, AccessListTxType, BlobTxType:
217+
case DynamicFeeTxType, AccessListTxType, BlobTxType, SetCodeTxType, StateSyncTxType:
218218
var data receiptRLP
219219
err := rlp.DecodeBytes(b[1:], &data)
220220
if err != nil {
@@ -319,7 +319,7 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
319319
}
320320
r.Type = b[0]
321321
switch r.Type {
322-
case AccessListTxType, DynamicFeeTxType, BlobTxType, SetCodeTxType:
322+
case AccessListTxType, DynamicFeeTxType, BlobTxType, SetCodeTxType, StateSyncTxType:
323323
if err := r.decodePayload(s); err != nil {
324324
return err
325325
}
@@ -486,6 +486,11 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
486486
if err := rlp.Encode(w, data); err != nil {
487487
panic(err)
488488
}
489+
case StateSyncTxType:
490+
w.WriteByte(StateSyncTxType)
491+
if err := rlp.Encode(w, data); err != nil {
492+
panic(err)
493+
}
489494
default:
490495
// For unsupported types, write nothing. Since this is for
491496
// DeriveSha, the error will be caught matching the derived hash

execution/types/state_sync_tx.go

Lines changed: 31 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ func (tx *StateSyncTx) Type() byte {
2424
}
2525

2626
func (tx *StateSyncTx) GetChainID() *uint256.Int {
27-
panic("chainID called from StateSyncTx")
27+
return nil
2828
}
2929

3030
func (tx *StateSyncTx) GetNonce() uint64 {
@@ -65,31 +65,33 @@ func (tx *StateSyncTx) GetTo() *common.Address {
6565

6666
func (tx *StateSyncTx) AsMessage(_ Signer, baseFee *big.Int, rules *chain.Rules) (*Message, error) {
6767
if !rules.IsStateSync {
68-
// TODO change to better name when we have a hard fork for this
68+
// TODO: Change to a better name when we have a hard fork for this.
6969
return nil, errors.New("StateSync typed tx requires StateSync hard fork")
7070
}
71+
7172
msg := Message{
73+
to: &common.Address{},
74+
from: common.Address{},
7275
nonce: 0,
76+
amount: *uint256.NewInt(0),
7377
gasLimit: 0,
7478
gasPrice: *uint256.NewInt(0),
75-
tipCap: *uint256.NewInt(0),
7679
feeCap: *uint256.NewInt(0),
77-
to: tx.GetTo(),
78-
amount: *uint256.NewInt(0),
80+
tipCap: *uint256.NewInt(0),
7981
data: []byte{},
8082
accessList: nil,
8183
checkNonce: false,
8284
}
85+
8386
if baseFee != nil {
8487
_ = msg.gasPrice.SetFromBig(baseFee)
8588
}
8689

87-
msg.from = common.Address{}
8890
return &msg, nil
8991
}
9092

9193
func (tx *StateSyncTx) WithSignature(_ Signer, _ []byte) (Transaction, error) {
92-
return nil, errors.New("StateSyncTx are not signed")
94+
return nil, errors.New("StateSyncTx is not signed")
9395
}
9496

9597
func (tx *StateSyncTx) Hash() common.Hash {
@@ -105,7 +107,7 @@ func (tx *StateSyncTx) Hash() common.Hash {
105107
}
106108

107109
func (tx *StateSyncTx) SigningHash(_ *big.Int) common.Hash {
108-
// StateSync txs are never signed, return canonical hash
110+
// StateSync txs are never signed, return canonical hash.
109111
return tx.Hash()
110112
}
111113

@@ -132,24 +134,26 @@ func (tx *StateSyncTx) RawSignatureValues() (*uint256.Int, *uint256.Int, *uint25
132134
func (tx *StateSyncTx) EncodingSize() int {
133135
var b bytes.Buffer
134136
_ = tx.encode(&b)
135-
return 1 + b.Len()
137+
data := make([]byte, 1+b.Len())
138+
return rlp.StringLen(data)
136139
}
137140

138-
// EncodeRLP writes the inner payload ([]StateSyncData) without the type prefix.
141+
// EncodeRLP implements rlp.Encoder for database storage.
139142
func (tx *StateSyncTx) EncodeRLP(w io.Writer) error {
140143
if tx == nil {
141144
return errors.New("nil StateSyncTx")
142145
}
143146
var buf bytes.Buffer
147+
buf.WriteByte(StateSyncTxType)
144148
if err := tx.encode(&buf); err != nil {
145149
return err
146150
}
147-
_, err := w.Write(buf.Bytes())
148-
return err
151+
b := newEncodingBuf()
152+
defer pooledBuf.Put(b)
153+
return rlp.EncodeString(buf.Bytes(), w, b[:])
149154
}
150155

151-
// DecodeRLP consumes the RLP stream and populates tx.StateSyncData.
152-
// The type byte (0x7F) is already stripped by the UnmarshalTransaction path.
156+
// DecodeRLP implements rlp.Decoder.
153157
func (tx *StateSyncTx) DecodeRLP(s *rlp.Stream) error {
154158
raw, err := s.Raw()
155159
if err != nil {
@@ -158,11 +162,20 @@ func (tx *StateSyncTx) DecodeRLP(s *rlp.Stream) error {
158162
return tx.decode(raw)
159163
}
160164

165+
// MarshalBinary returns the canonical encoding for network transmission.
161166
func (tx *StateSyncTx) MarshalBinary(w io.Writer) error {
167+
if tx == nil {
168+
return errors.New("nil StateSyncTx")
169+
}
162170
if _, err := w.Write([]byte{StateSyncTxType}); err != nil {
163171
return err
164172
}
165-
return tx.EncodeRLP(w)
173+
var payloadBuf bytes.Buffer
174+
if err := tx.encode(&payloadBuf); err != nil {
175+
return err
176+
}
177+
_, err := w.Write(payloadBuf.Bytes())
178+
return err
166179
}
167180

168181
func (tx *StateSyncTx) Sender(_ Signer) (common.Address, error) {
@@ -178,7 +191,7 @@ func (tx *StateSyncTx) GetSender() (common.Address, bool) {
178191
}
179192

180193
func (tx *StateSyncTx) SetSender(_ common.Address) {
181-
// no-op, StateSyncTx has no sender
194+
// no-op, StateSyncTx has no sender.
182195
}
183196

184197
func (tx *StateSyncTx) IsContractDeploy() bool {
@@ -226,7 +239,7 @@ func (tx *StateSyncTx) encode(buf *bytes.Buffer) error {
226239
if tx == nil {
227240
return errors.New("nil StateSyncTx")
228241
}
229-
// Validate ascending and contiguous IDs as per PIP-74
242+
// Validate ascending and contiguous IDs as per PIP-74.
230243
var prev uint64
231244
for i, d := range tx.StateSyncData {
232245
if d == nil {
@@ -253,7 +266,7 @@ func (tx *StateSyncTx) decode(b []byte) error {
253266
if err := rlp.DecodeBytes(b, &dec); err != nil {
254267
return err
255268
}
256-
// Validate ascending and contiguous IDs as per PIP-74
269+
// Validate ascending and contiguous IDs as per PIP-74.
257270
if len(dec) > 0 {
258271
prev := dec[0].ID
259272
for i := 1; i < len(dec); i++ {

polygon/bor/bor.go

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -798,7 +798,7 @@ func (c *Bor) CalculateRewards(_ *chain.Config, _ *types.Header, _ []*types.Head
798798
// Finalize implements consensus.Engine, ensuring no uncles are set, nor block
799799
// rewards given.
800800
func (c *Bor) Finalize(_ *chain.Config, header *types.Header, state *state.IntraBlockState,
801-
_ types.Transactions, _ []*types.Header, _ types.Receipts, withdrawals []*types.Withdrawal,
801+
txs types.Transactions, _ []*types.Header, receipts types.Receipts, withdrawals []*types.Withdrawal,
802802
chain consensus.ChainReader, syscall consensus.SystemCall, _ bool, _ log.Logger,
803803
) (types.FlatRequests, error) {
804804
headerNumber := header.Number.Uint64()
@@ -841,7 +841,14 @@ func (c *Bor) Finalize(_ *chain.Config, header *types.Header, state *state.Intra
841841
return nil, err
842842
}
843843

844-
// PIP-74: Finalize does not append txs/receipts (that’s done in FinalizeAndAssemble)
844+
if c.config.IsStateSync(headerNumber) && len(txs) > 0 {
845+
lastTx := txs[len(txs)-1]
846+
if lastTx.Type() == types.StateSyncTxType && receipts[len(txs)-1] == nil {
847+
prevReceipts := receipts[:len(txs)-1]
848+
stateSyncReceipt := newStateSyncReceipt(lastTx, prevReceipts, state, header, txs)
849+
receipts[len(txs)-1] = stateSyncReceipt
850+
}
851+
}
845852

846853
return nil, nil
847854
}
@@ -920,7 +927,7 @@ func (c *Bor) FinalizeAndAssemble(
920927
return nil, nil, err
921928
}
922929

923-
// PIP-74: append StateSyncTx and receipt post-fork if any events executed
930+
// PIP-74: append StateSyncTx and receipt post-fork if any state-sync events executed.
924931
if c.config.IsStateSync(headerNumber) && len(execStateSync) > 0 {
925932
c.logger.Info("FinalizeAndAssemble: Appending state sync txs", "count", len(execStateSync))
926933
stateSyncTx := &types.StateSyncTx{StateSyncData: execStateSync}
@@ -1451,30 +1458,35 @@ func VerifyUncles(uncles []*types.Header) error {
14511458

14521459
// newStateSyncReceipt creates a new receipt for the StateSyncTx
14531460
func newStateSyncReceipt(tx types.Transaction, prev types.Receipts, state *state.IntraBlockState, header *types.Header, txs types.Transactions) *types.Receipt {
1454-
// Slice logs since previous receipts
1455-
allLogs := state.Logs()
1456-
logsFromReceiptCount := countLogsFromReceipts(prev)
1457-
stateSyncLogs := allLogs[logsFromReceiptCount:]
1461+
// state.Logs() only contains the state sync logs.
1462+
// regular tx logs are already in their receipts, not in state.
1463+
// Here, state is the intra block state.
1464+
stateSyncLogs := state.Logs()
1465+
1466+
// Fix log TxIndex - logs inherit TxIndex from state context during CommitStates.
1467+
txIndex := uint(len(txs) - 1)
1468+
for _, l := range stateSyncLogs {
1469+
l.TxIndex = txIndex
1470+
}
1471+
1472+
var cumulativeGasUsed uint64
1473+
if len(prev) > 0 {
1474+
cumulativeGasUsed = prev[len(prev)-1].CumulativeGasUsed
1475+
}
14581476

14591477
r := &types.Receipt{
14601478
Type: tx.Type(),
14611479
Status: types.ReceiptStatusSuccessful,
1462-
CumulativeGasUsed: header.GasUsed,
1463-
GasUsed: 0,
1464-
TxHash: tx.Hash(),
1480+
CumulativeGasUsed: cumulativeGasUsed,
14651481
Logs: stateSyncLogs,
1466-
BlockNumber: header.Number,
1467-
TransactionIndex: uint(len(txs) - 1),
1482+
// Implementation fields
1483+
TxHash: tx.Hash(),
1484+
GasUsed: 0,
1485+
// Inclusion information
1486+
BlockNumber: header.Number,
1487+
TransactionIndex: txIndex,
14681488
}
14691489
r.Bloom = types.CreateBloom(types.Receipts{r})
1470-
return r
1471-
}
14721490

1473-
// countLogsFromReceipts counts the total number of logs in the given receipts.
1474-
func countLogsFromReceipts(receipts types.Receipts) int {
1475-
count := 0
1476-
for _, r := range receipts {
1477-
count += len(r.Logs)
1478-
}
1479-
return count
1491+
return r
14801492
}

polygon/sync/sync.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ func (s *Sync) applyNewBlockChainOnTip(ctx context.Context, blockChain []*types.
413413
return err
414414
}
415415

416-
if source == EventSourceP2PNewBlock {
416+
if source == EventSourceP2PNewBlock || source == EventSourceP2PNewBlockHashes {
417417
// https://github.com/ethereum/devp2p/blob/master/caps/eth.md#block-propagation
418418
// devp2p spec: After the header validity check, the client imports the block into its local chain by executing
419419
// all transactions contained in the block, computing the block's 'post state'. The block's state-root hash

rpc/ethapi/api.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -519,11 +519,16 @@ func NewRPCTransaction(txn types.Transaction, blockHash common.Hash, blockNumber
519519
}
520520
result.GasPrice = (*hexutil.Big)(txn.GetTipCap().ToBig())
521521
} else {
522-
chainId.Set(txn.GetChainID())
523-
result.ChainID = (*hexutil.Big)(chainId.ToBig())
522+
if txn.Type() != types.StateSyncTxType {
523+
chainId.Set(txn.GetChainID())
524+
result.ChainID = (*hexutil.Big)(chainId.ToBig())
525+
}
524526
result.YParity = (*hexutil.Big)(v.ToBig())
525-
acl := txn.GetAccessList()
526-
result.Accesses = &acl
527+
528+
if txn.Type() != types.StateSyncTxType {
529+
acl := txn.GetAccessList()
530+
result.Accesses = &acl
531+
}
527532

528533
if txn.Type() == types.AccessListTxType {
529534
result.GasPrice = (*hexutil.Big)(txn.GetTipCap().ToBig())

rpc/jsonrpc/eth_block.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ func (api *APIImpl) GetBlockByNumber(ctx context.Context, number rpc.BlockNumber
229229
}
230230
var borTx types.Transaction
231231
var borTxHash common.Hash
232-
if chainConfig.Bor != nil {
232+
if chainConfig.Bor != nil && !chainConfig.Bor.IsStateSync(b.NumberU64()) {
233233
possibleBorTxnHash := bortypes.ComputeBorTxHash(b.NumberU64(), b.Hash())
234234
_, ok, err := api.bridgeReader.EventTxnLookup(ctx, possibleBorTxnHash)
235235
if err != nil {

0 commit comments

Comments
 (0)