Skip to content

Commit 1be3ee7

Browse files
authored
Merge branch 'main' into fix-boilerplates
2 parents b623689 + 5ff2ec7 commit 1be3ee7

File tree

13 files changed

+535
-15
lines changed

13 files changed

+535
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
- [\#511](https://github.com/cosmos/evm/pull/511) Minor code cleanup for `AddPrecompileFn`.
2727
- [\#544](https://github.com/cosmos/evm/pull/544) Parse logs from the txResult.Data and avoid emitting EVM events to cosmos-sdk events.
2828
- [\#582](https://github.com/cosmos/evm/pull/582) Add block max-gas (from genesis.json) and new min-tip (from app.toml/flags) ingestion into mempool config
29+
- [\#598](https://github.com/cosmos/evm/pull/598) Reduce number of times CreateQueryContext in mempool.
2930
- [\#577](https://github.com/cosmos/evm/pull/577) Cleanup precompiles boilerplate code.
3031

3132
### FEATURES

Makefile

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,3 +395,73 @@ mocks:
395395
@go get github.com/vektra/mockery/v2
396396
@go generate ./...
397397
@make format-go
398+
399+
###############################################################################
400+
### D2 Diagrams ###
401+
###############################################################################
402+
403+
D2_THEME=300
404+
D2_DARK_THEME=200
405+
D2_LAYOUT=tala
406+
407+
D2_ENV_VARS=D2_THEME=$(D2_THEME) \
408+
D2_DARK_THEME=$(D2_DARK_THEME) \
409+
D2_LAYOUT=$(D2_LAYOUT)
410+
411+
.PHONY: d2check d2watch d2gen d2gen-all
412+
413+
d2check:
414+
@echo "🔍 checking if d2 is installed..."
415+
@which d2 > /dev/null 2>&1 || { \
416+
echo "🔴 d2 is not installed, see installation docs: https://d2lang.com/tour/install/"; \
417+
exit 1; \
418+
}
419+
@echo "🟢 d2 is installed"
420+
@echo "🔍 checking if $(D2_LAYOUT) layout is installed..."
421+
@d2 layout | grep $(D2_LAYOUT) > /dev/null 2>&1 || { \
422+
echo "🔴 $(D2_LAYOUT) layout is not installed, see docs: https://d2lang.com/tour/layouts/"; \
423+
exit 1; \
424+
}
425+
@echo "🟢 $(D2_LAYOUT) layout is installed"
426+
427+
d2watch: d2check
428+
@if [ -z "$(FILE)" ]; then \
429+
echo "🔴 missing required parameter FILE, the correct usage is: make d2watch FILE=path/to/file.d2"; \
430+
exit 1; \
431+
fi
432+
@if [ ! -f "$(FILE)" ]; then \
433+
echo "🔴 file $(FILE) does not exist"; \
434+
exit 1; \
435+
fi
436+
@echo "🔄 watching $(FILE) for changes..."
437+
@dir=$$(dirname "$(FILE)"); \
438+
basename=$$(basename "$(FILE)" .d2); \
439+
svgfile="$$dir/$$basename.svg"; \
440+
printf "📊 generating $$svgfile from $(FILE)... "; \
441+
$(D2_ENV_VARS) d2 --watch "$(FILE)" "$$svgfile"
442+
443+
d2gen: d2check
444+
@if [ -z "$(FILE)" ]; then \
445+
echo "🔴 missing required parameter FILE, the correct usage is: make d2gen FILE=path/to/file.d2"; \
446+
exit 1; \
447+
fi
448+
@if [ ! -f "$(FILE)" ]; then \
449+
echo "🔴 file $(FILE) does not exist"; \
450+
exit 1; \
451+
fi
452+
@dir=$$(dirname "$(FILE)"); \
453+
basename=$$(basename "$(FILE)" .d2); \
454+
svgfile="$$dir/$$basename.svg"; \
455+
printf "📊 generating $$svgfile from $(FILE)... "; \
456+
$(D2_ENV_VARS) d2 "$(FILE)" "$$svgfile" > /dev/null 2>&1 && echo "done ✅" || echo "failed ❌";
457+
458+
d2gen-all: d2check
459+
@echo "🟢 generating svg files for all d2 diagrams..."
460+
@find . -name "*.d2" -type f | while read d2file; do \
461+
dir=$$(dirname "$$d2file"); \
462+
basename=$$(basename "$$d2file" .d2); \
463+
svgfile="$$dir/$$basename.svg"; \
464+
printf "📊 generating $$svgfile from $$d2file... "; \
465+
$(D2_ENV_VARS) d2 "$$d2file" "$$svgfile" > /dev/null 2>&1 && echo "done ✅" || echo "failed ❌"; \
466+
done
467+
@echo "✅ svg files generated for all d2 diagrams"

contracts/solidity/precompiles/testutil/contracts/StakingReverter.sol

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,36 @@ contract StakingReverter {
4949
STAKING_CONTRACT.delegate(address(this), validatorAddress, 10);
5050
}
5151

52+
/// @dev nestedTryCatchDelegations performs nested try/catch calls to precompile
53+
/// where inner calls revert intentionally. Only the successful delegations
54+
/// outside the reverting scope should persist.
55+
///
56+
/// Expected successful delegations: 1 (before loop) + outerTimes (after each catch) + 1 (after loop)
57+
function nestedTryCatchDelegations(uint outerTimes, uint innerTimes, string calldata validatorAddress) external {
58+
// Initial successful delegate before any nested reverts
59+
STAKING_CONTRACT.delegate(address(this), validatorAddress, 10);
60+
61+
for (uint i = 0; i < outerTimes; i++) {
62+
// Outer call that will revert and be caught
63+
try StakingReverter(address(this)).performDelegation(validatorAddress) {
64+
// no-op
65+
} catch {
66+
// After catching the revert, perform a successful delegate
67+
STAKING_CONTRACT.delegate(address(this), validatorAddress, 10);
68+
69+
// Inner nested loop of reverting calls
70+
for (uint j = 0; j < innerTimes; j++) {
71+
try StakingReverter(address(this)).performDelegation(validatorAddress) {
72+
// no-op
73+
} catch {}
74+
}
75+
}
76+
}
77+
78+
// Final successful delegate after the loops
79+
STAKING_CONTRACT.delegate(address(this), validatorAddress, 10);
80+
}
81+
5282
function performDelegation(string calldata validatorAddress) external {
5383
STAKING_CONTRACT.delegate(address(this), validatorAddress, 10);
5484
revert();

crypto/ethsecp256k1/ethsecp256k1.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@ import (
88

99
"github.com/ethereum/go-ethereum/crypto"
1010

11-
tmcrypto "github.com/cometbft/cometbft/crypto"
12-
1311
"github.com/cosmos/evm/ethereum/eip712"
1412

1513
errorsmod "cosmossdk.io/errors"
@@ -147,13 +145,13 @@ var (
147145

148146
// Address returns the address of the ECDSA public key.
149147
// The function will return an empty address if the public key is invalid.
150-
func (pubKey PubKey) Address() tmcrypto.Address {
148+
func (pubKey PubKey) Address() cryptotypes.Address {
151149
pubk, err := crypto.DecompressPubkey(pubKey.Key)
152150
if err != nil {
153151
return nil
154152
}
155153

156-
return tmcrypto.Address(crypto.PubkeyToAddress(*pubk).Bytes())
154+
return cryptotypes.Address(crypto.PubkeyToAddress(*pubk).Bytes())
157155
}
158156

159157
// Bytes returns the raw bytes of the ECDSA public key.

mempool/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,7 @@ The following diagrams illustrate the complete transaction flow architecture, sh
411411

412412
### Architecture Overview
413413

414-
![EVM Mempool Architecture](img/mempool_architecture.jpg)
414+
![EVM Mempool Architecture](img/mempool_architecture.svg)
415415

416416
### Transaction Flow
417417

mempool/blockchain.go

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ type Blockchain struct {
4141
zeroHeader *types.Header
4242
blockGasLimit uint64
4343
previousHeaderHash common.Hash
44+
latestCtx sdk.Context
4445
}
4546

4647
// newBlockchain creates a new Blockchain instance that bridges Cosmos SDK state with Ethereum mempools.
@@ -78,10 +79,8 @@ func (b Blockchain) Config() *params.ChainConfig {
7879
// including block height, timestamp, gas limits, and base fee (if London fork is active).
7980
// Returns a zero header as placeholder if the context is not yet available.
8081
func (b Blockchain) CurrentBlock() *types.Header {
81-
ctx, err := b.GetLatestCtx()
82-
// This should only error out on the first block.
82+
ctx, err := b.GetLatestContext()
8383
if err != nil {
84-
b.logger.Debug("failed to get latest context, returning zero header", "error", err)
8584
return b.zeroHeader
8685
}
8786

@@ -169,6 +168,12 @@ func (b Blockchain) SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event
169168

170169
// NotifyNewBlock sends a chain head event when a new block is finalized
171170
func (b *Blockchain) NotifyNewBlock() {
171+
latestCtx, err := b.newLatestContext()
172+
if err != nil {
173+
b.latestCtx = sdk.Context{}
174+
b.logger.Debug("failed to get latest context, notifying chain head", "error", err)
175+
}
176+
b.latestCtx = latestCtx
172177
header := b.CurrentBlock()
173178
headerHash := header.Hash()
174179

@@ -197,7 +202,7 @@ func (b Blockchain) StateAt(hash common.Hash) (vm.StateDB, error) {
197202
}
198203

199204
// Always get the latest context to avoid stale nonce state.
200-
ctx, err := b.GetLatestCtx()
205+
ctx, err := b.GetLatestContext()
201206
if err != nil {
202207
// If we can't get the latest context for blocks past 1, something is seriously wrong with the chain state
203208
return nil, fmt.Errorf("failed to get latest context for StateAt: %w", err)
@@ -210,9 +215,21 @@ func (b Blockchain) StateAt(hash common.Hash) (vm.StateDB, error) {
210215
return stateDB, nil
211216
}
212217

213-
// GetLatestCtx retrieves the most recent query context from the application.
218+
// GetLatestContext returns the latest context as updated by the block,
219+
// or attempts to retrieve it again if unavailable.
220+
func (b Blockchain) GetLatestContext() (sdk.Context, error) {
221+
b.logger.Debug("getting latest context")
222+
223+
if b.latestCtx.Context() != nil {
224+
return b.latestCtx, nil
225+
}
226+
227+
return b.newLatestContext()
228+
}
229+
230+
// newLatestContext retrieves the most recent query context from the application.
214231
// This provides access to the current blockchain state for transaction validation and execution.
215-
func (b Blockchain) GetLatestCtx() (sdk.Context, error) {
232+
func (b Blockchain) newLatestContext() (sdk.Context, error) {
216233
b.logger.Debug("getting latest context")
217234

218235
ctx, err := b.getCtxCallback(0, false)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
direction: right
2+
3+
# entities
4+
prepare proposal
5+
check tx\nhandler
6+
comet bft
7+
rpc call
8+
broadcast
9+
rebroadcast\ncallback: { shape: diamond }
10+
evm mempool: {
11+
direction: up
12+
13+
# entities
14+
ext mempool\ninterface impl
15+
cosmos priority\nnonce mempool
16+
tx pool: {
17+
direction: up
18+
19+
# entities
20+
queued\ntransactions
21+
pending\ntransactions
22+
tx pool\ninterface
23+
reset loop\n(evicts from\nqueued and\npending txs)
24+
promotion: {shape: diamond }
25+
filter: { shape: diamond }
26+
27+
# edges
28+
filter -> queued\ntransactions: add nonce\ngapped txs
29+
filter -> pending\ntransactions: add\nexecutable txs
30+
promotion -> pending\ntransactions: promote tx
31+
queued\ntransactions -> promotion: check closed gap\nand promote tx
32+
pending\ntransactions -> tx pool\ninterface: get txs for\nblock building
33+
tx pool\ninterface -> filter: add valid txs
34+
}
35+
36+
# edges
37+
tx pool.tx pool\ninterface -> ext mempool\ninterface impl: get txs for\nblock building
38+
39+
cosmos priority\nnonce mempool -> ext mempool\ninterface impl: get txs for\nblock building
40+
41+
ext mempool\ninterface impl -> tx pool.tx pool\ninterface: success/nonce gap failure:\nadd valid evm txs
42+
ext mempool\ninterface impl -> tx pool.tx pool\ninterface: recheck tx\neviction
43+
ext mempool\ninterface impl -> cosmos priority\nnonce mempool: add\ncosmos txs
44+
}
45+
46+
# edges
47+
rebroadcast\ncallback -> comet bft: rebroadcast\nrebuilt tx
48+
49+
evm mempool.tx pool.promotion -> rebroadcast\ncallback: call rebroadcast\ncallback
50+
evm mempool.ext mempool\ninterface impl -> prepare proposal: get txs for\nblock building
51+
52+
comet bft -> broadcast: success:\nbroadcast tx
53+
comet bft -> check tx\nhandler: send tx for validation
54+
comet bft -> check tx\nhandler: send tx again\nfor recheck
55+
56+
check tx\nhandler -> rpc call: queued\nsuccess response
57+
check tx\nhandler -> comet bft: success: broadcast\nand add to mempool
58+
check tx\nhandler -> comet bft: recheck tx complete\nfailure: discard from pool
59+
check tx\nhandler -> evm mempool.ext mempool\ninterface impl: complete failure:\nremove from pending
60+
check tx\nhandler -> evm mempool.ext mempool\ninterface impl: nonce gap failure:\nadd transaction
61+
check tx\nhandler -> evm mempool.ext mempool\ninterface impl: success:\nadd txs
62+
check tx\nhandler -> evm mempool.ext mempool\ninterface impl: recheck tx complete\nfailure: eviction

0 commit comments

Comments
 (0)