Skip to content

Commit 23176cb

Browse files
authored
Merge pull request #596 from ethpandaops/pk910/fix-old-basefee
Pre-capella copatiblity & eip7702 authorizations in tx details
2 parents f859b7b + 717e69e commit 23176cb

16 files changed

Lines changed: 563 additions & 192 deletions

File tree

db/el_accounts.go

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,26 +11,40 @@ import (
1111

1212
func InsertElAccount(ctx context.Context, dbTx *sqlx.Tx, account *dbtypes.ElAccount) (uint64, error) {
1313
var id uint64
14-
query := EngineQuery(map[dbtypes.DBEngineType]string{
15-
dbtypes.DBEnginePgsql: "INSERT INTO el_accounts (address, funder_id, funded, is_contract, last_nonce, last_block_uid) VALUES ($1, $2, $3, $4, $5, $6) RETURNING id",
16-
dbtypes.DBEngineSqlite: "INSERT INTO el_accounts (address, funder_id, funded, is_contract, last_nonce, last_block_uid) VALUES ($1, $2, $3, $4, $5, $6)",
17-
})
1814

1915
if DbEngine == dbtypes.DBEnginePgsql {
16+
// Use ON CONFLICT with a no-op update to return the existing id on conflict.
17+
query := "INSERT INTO el_accounts (address, funder_id, funded, is_contract, last_nonce, last_block_uid) VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT (address) DO UPDATE SET address = excluded.address RETURNING id"
2018
err := dbTx.QueryRowContext(ctx, query, account.Address, account.FunderID, account.Funded, account.IsContract, account.LastNonce, account.LastBlockUid).Scan(&id)
2119
if err != nil {
2220
return 0, err
2321
}
2422
} else {
23+
// SQLite: use INSERT OR IGNORE to skip on duplicate address, then look up the id.
24+
query := "INSERT OR IGNORE INTO el_accounts (address, funder_id, funded, is_contract, last_nonce, last_block_uid) VALUES ($1, $2, $3, $4, $5, $6)"
2525
result, err := dbTx.ExecContext(ctx, query, account.Address, account.FunderID, account.Funded, account.IsContract, account.LastNonce, account.LastBlockUid)
2626
if err != nil {
2727
return 0, err
2828
}
29-
lastID, err := result.LastInsertId()
29+
30+
rowsAffected, err := result.RowsAffected()
3031
if err != nil {
3132
return 0, err
3233
}
33-
id = uint64(lastID)
34+
35+
if rowsAffected > 0 {
36+
lastID, err := result.LastInsertId()
37+
if err != nil {
38+
return 0, err
39+
}
40+
id = uint64(lastID)
41+
} else {
42+
// Row already exists, look up the existing id.
43+
err := dbTx.QueryRowContext(ctx, "SELECT id FROM el_accounts WHERE address = $1", account.Address).Scan(&id)
44+
if err != nil {
45+
return 0, fmt.Errorf("failed to get existing account id: %w", err)
46+
}
47+
}
3448
}
3549
return id, nil
3650
}

db/el_token_transfers.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,13 +338,13 @@ func GetElTokenTransfersByAccountIDCombined(ctx context.Context, accountID uint6
338338
SELECT block_uid, tx_hash, tx_pos, tx_idx, token_id, token_type, token_index,
339339
from_id, to_id, amount, amount_raw
340340
FROM (
341-
(SELECT block_uid, tx_hash, tx_pos, tx_idx, token_id, token_type, token_index,
341+
SELECT * FROM (SELECT block_uid, tx_hash, tx_pos, tx_idx, token_id, token_type, token_index,
342342
from_id, to_id, amount, amount_raw
343343
FROM el_token_transfers WHERE from_id = $1%s
344344
ORDER BY block_uid DESC NULLS LAST
345345
LIMIT $%d)
346346
UNION ALL
347-
(SELECT block_uid, tx_hash, tx_pos, tx_idx, token_id, token_type, token_index,
347+
SELECT * FROM (SELECT block_uid, tx_hash, tx_pos, tx_idx, token_id, token_type, token_index,
348348
from_id, to_id, amount, amount_raw
349349
FROM el_token_transfers WHERE to_id = $2 AND from_id != $3%s
350350
ORDER BY block_uid DESC NULLS LAST

db/el_transactions.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,14 +293,14 @@ func GetElTransactionsByAccountIDCombined(ctx context.Context, accountID uint64,
293293
method_id, gas_limit, gas_used, gas_price, tip_price, blob_count, block_number,
294294
tx_type, tx_index, eff_gas_price
295295
FROM (
296-
(SELECT block_uid, tx_hash, from_id, to_id, nonce, reverted, amount, amount_raw,
296+
SELECT * FROM (SELECT block_uid, tx_hash, from_id, to_id, nonce, reverted, amount, amount_raw,
297297
method_id, gas_limit, gas_used, gas_price, tip_price, blob_count, block_number,
298298
tx_type, tx_index, eff_gas_price
299299
FROM el_transactions WHERE from_id = $1
300300
ORDER BY block_uid DESC NULLS LAST
301301
LIMIT $4)
302302
UNION ALL
303-
(SELECT block_uid, tx_hash, from_id, to_id, nonce, reverted, amount, amount_raw,
303+
SELECT * FROM (SELECT block_uid, tx_hash, from_id, to_id, nonce, reverted, amount, amount_raw,
304304
method_id, gas_limit, gas_used, gas_price, tip_price, blob_count, block_number,
305305
tx_type, tx_index, eff_gas_price
306306
FROM el_transactions WHERE to_id = $2 AND from_id != $3

handlers/transaction.go

Lines changed: 155 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ func Transaction(w http.ResponseWriter, r *http.Request) {
4949
"transaction/statechanges.html",
5050
"transaction/transfers.html",
5151
"transaction/internaltxs.html",
52+
"transaction/authorizations.html",
5253
"transaction/blobs.html",
5354
)
5455
notfoundTemplateFiles := append(layoutTemplateFiles,
@@ -103,7 +104,7 @@ func Transaction(w http.ResponseWriter, r *http.Request) {
103104

104105
if pageData.TxNotFound {
105106
data := InitPageData(w, r, "blockchain", "/tx", "Transaction not found", notfoundTemplateFiles)
106-
data.Data = pageData
107+
data.Data = "notfound"
107108
w.Header().Set("Content-Type", "text/html")
108109
handleTemplateError(w, r, "transaction.go", "Transaction", "notFound", templates.GetTemplate(notfoundTemplateFiles...).ExecuteTemplate(w, "layout", data))
109110
return
@@ -423,8 +424,13 @@ func buildTransactionPageDataFromDB(ctx context.Context, pageData *models.Transa
423424
loadTransactionTransfersFromData(ctx, pageData, transfers)
424425
case "internaltxs":
425426
loadTransactionInternalTxsFromBlockdb(ctx, pageData, tx.BlockUid)
427+
computeInternalTxIndent(pageData)
426428
case "statechanges":
427429
loadTransactionStateChangesFromBlockdb(ctx, pageData, tx.BlockUid)
430+
case "authorizations":
431+
if pageData.TxType == ethtypes.SetCodeTxType && len(pageData.Authorizations) > 0 {
432+
resolveAuthorizationValidity(ctx, pageData, tx.BlockUid)
433+
}
428434
}
429435
}
430436

@@ -532,6 +538,11 @@ func buildTransactionPageDataFromEL(ctx context.Context, pageData *models.Transa
532538
// Blob hashes
533539
pageData.BlobCount = uint32(len(ethTx.BlobHashes()))
534540

541+
// Authorization data for type 4 (EIP-7702) transactions
542+
if ethTx.Type() == ethtypes.SetCodeTxType {
543+
loadAuthorizationData(pageData, ethTx)
544+
}
545+
535546
// Generate RLP and JSON
536547
if rlpData, err := ethTx.MarshalBinary(); err == nil {
537548
pageData.TxRLP = "0x" + hex.EncodeToString(rlpData)
@@ -1162,6 +1173,35 @@ func loadTransactionInternalTxsFromDB(ctx context.Context, pageData *models.Tran
11621173
}
11631174
}
11641175

1176+
// computeInternalTxIndent sets InternalTxIndentPx based on the maximum
1177+
// nesting depth so that deeply nested trees compress to ~300px total.
1178+
func computeInternalTxIndent(pageData *models.TransactionPageData) {
1179+
if len(pageData.InternalTxs) == 0 {
1180+
return
1181+
}
1182+
1183+
var maxDepth uint16
1184+
for _, itx := range pageData.InternalTxs {
1185+
if itx.Depth > maxDepth {
1186+
maxDepth = itx.Depth
1187+
}
1188+
}
1189+
1190+
if maxDepth == 0 {
1191+
pageData.InternalTxIndentPx = 18.0
1192+
return
1193+
}
1194+
1195+
indent := 300.0 / float64(maxDepth)
1196+
if indent > 18.0 {
1197+
indent = 18.0
1198+
}
1199+
if indent < 2.0 {
1200+
indent = 2.0
1201+
}
1202+
pageData.InternalTxIndentPx = indent
1203+
}
1204+
11651205
func loadTransactionTransfersFromData(ctx context.Context, pageData *models.TransactionPageData, transfers []*dbtypes.ElTokenTransfer) {
11661206
if len(transfers) == 0 {
11671207
return
@@ -1294,6 +1334,11 @@ func loadFullTransactionData(ctx context.Context, pageData *models.TransactionPa
12941334
if ethTx.Type() == 3 && len(ethTx.BlobHashes()) > 0 {
12951335
loadBlobData(pageData, &ethTx, blockData)
12961336
}
1337+
1338+
// Load authorization data for type 4 (EIP-7702) transactions
1339+
if ethTx.Type() == ethtypes.SetCodeTxType {
1340+
loadAuthorizationData(pageData, &ethTx)
1341+
}
12971342
}
12981343

12991344
// loadBlobData populates blob-related data for type 3 (blob) transactions.
@@ -1407,3 +1452,112 @@ func applyCallTargetResolution(ctx context.Context, pageData *models.Transaction
14071452
pageData.MethodID = res.MethodID
14081453
}
14091454
}
1455+
1456+
// loadAuthorizationData extracts EIP-7702 authorization list entries from a
1457+
// parsed transaction and populates pageData.Authorizations.
1458+
func loadAuthorizationData(
1459+
pageData *models.TransactionPageData,
1460+
ethTx *ethtypes.Transaction,
1461+
) {
1462+
authList := ethTx.SetCodeAuthorizations()
1463+
if len(authList) == 0 {
1464+
return
1465+
}
1466+
1467+
pageData.Authorizations = make(
1468+
[]*models.TransactionPageDataAuthorization,
1469+
len(authList),
1470+
)
1471+
1472+
for i := range authList {
1473+
auth := &authList[i]
1474+
entry := &models.TransactionPageDataAuthorization{
1475+
Index: uint32(i),
1476+
DelegateAddr: auth.Address.Bytes(),
1477+
}
1478+
1479+
if authority, err := auth.Authority(); err == nil {
1480+
entry.AuthorityAddr = authority.Bytes()
1481+
entry.AuthorityOk = true
1482+
}
1483+
1484+
pageData.Authorizations[i] = entry
1485+
}
1486+
}
1487+
1488+
// resolveAuthorizationValidity loads state diffs from blockdb and checks
1489+
// whether each EIP-7702 authorization was actually applied on-chain.
1490+
// An authorization is considered applied when the authority address has a code
1491+
// change whose post-state matches the delegation designator (0xef0100 + delegate).
1492+
func resolveAuthorizationValidity(
1493+
ctx context.Context,
1494+
pageData *models.TransactionPageData,
1495+
blockUid uint64,
1496+
) {
1497+
if pageData.DataStatus&dbtypes.ElBlockDataStateChanges == 0 {
1498+
return
1499+
}
1500+
1501+
if blockdb.GlobalBlockDb == nil || !blockdb.GlobalBlockDb.SupportsExecData() {
1502+
return
1503+
}
1504+
1505+
slot := blockUid >> 16
1506+
blockRoot := pageData.BlockRoot
1507+
if len(blockRoot) == 0 {
1508+
return
1509+
}
1510+
1511+
ctx, cancel := context.WithTimeout(ctx, 10*time.Second)
1512+
defer cancel()
1513+
1514+
sections, err := blockdb.GlobalBlockDb.GetExecDataTxSections(
1515+
ctx, slot, blockRoot, pageData.TxHash,
1516+
bdbtypes.ExecDataSectionStateChange,
1517+
)
1518+
if err != nil || sections == nil || sections.StateChangeData == nil {
1519+
return
1520+
}
1521+
1522+
uncompData, err := snappy.Decode(nil, sections.StateChangeData)
1523+
if err != nil {
1524+
return
1525+
}
1526+
1527+
var accounts []bdbtypes.StateChangeAccount
1528+
if err := dynssz.GetGlobalDynSsz().UnmarshalSSZ(&accounts, uncompData); err != nil {
1529+
return
1530+
}
1531+
1532+
// Build a lookup of address -> post-code for accounts with code changes.
1533+
type codeInfo struct {
1534+
postCode []byte
1535+
}
1536+
codeByAddr := make(map[common.Address]codeInfo, len(accounts))
1537+
for i := range accounts {
1538+
a := &accounts[i]
1539+
if (a.Flags & bdbtypes.StateChangeFlagCodeChanged) != 0 {
1540+
codeByAddr[a.Address] = codeInfo{postCode: a.PostCode}
1541+
}
1542+
}
1543+
1544+
for _, auth := range pageData.Authorizations {
1545+
if !auth.AuthorityOk {
1546+
continue
1547+
}
1548+
1549+
authorityAddr := common.BytesToAddress(auth.AuthorityAddr)
1550+
ci, found := codeByAddr[authorityAddr]
1551+
if !found {
1552+
auth.Applied = 2 // not applied
1553+
continue
1554+
}
1555+
1556+
delegateAddr, ok := ethtypes.ParseDelegation(ci.postCode)
1557+
if ok && delegateAddr == common.BytesToAddress(auth.DelegateAddr) {
1558+
auth.Applied = 1 // applied
1559+
} else {
1560+
auth.Applied = 2 // not applied
1561+
}
1562+
}
1563+
}

templates/address/address.html

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,18 +235,19 @@ <h5 class="mb-0"><i class="fas fa-coins me-2"></i>Token Holdings ({{ .TokenBalan
235235

236236
function onTabSelected(event) {
237237
event.preventDefault();
238-
var tabId = event.target.getAttribute('data-lazy-tab');
238+
var link = event.currentTarget;
239+
var tabId = link.getAttribute('data-lazy-tab');
239240
var tabEl = document.getElementById(tabId);
240241
currentTab = tabId;
241242

242243
if (!$(tabEl).data("loaded")) {
243-
loadTabContent(tabEl, event.target.getAttribute('href'));
244+
loadTabContent(tabEl, link.getAttribute('href'));
244245
}
245246

246-
var tab = new bootstrap.Tab(event.target);
247+
var tab = new bootstrap.Tab(link);
247248
tab.show();
248249

249-
window.history.replaceState(null, document.title, "/address/" + addressStr + event.target.getAttribute('href'));
250+
window.history.replaceState(null, document.title, "/address/" + addressStr + link.getAttribute('href'));
250251
}
251252

252253
function loadTabContent(tabEl, url) {

templates/consolidations/consolidations.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -349,10 +349,11 @@ <h6 class="m-2 text-muted">This table displays pending consolidations in the que
349349

350350
function onTabSelected(event) {
351351
event.preventDefault();
352-
var tabId = event.target.getAttribute('data-lazy-tab');
352+
var link = event.currentTarget;
353+
var tabId = link.getAttribute('data-lazy-tab');
353354
var tabEl = document.getElementById(tabId);
354355
if (!$(tabEl).data("loaded")) {
355-
$.get(event.target.getAttribute('href') + "&lazy=true", function(data) {
356+
$.get(link.getAttribute('href') + "&lazy=true", function(data) {
356357
$(tabEl).html(data);
357358
$(tabEl).data("loaded", true);
358359
explorer.initControls();
@@ -362,7 +363,7 @@ <h6 class="m-2 text-muted">This table displays pending consolidations in the que
362363
var tab = new bootstrap.Tab(tabEl);
363364
tab.show();
364365

365-
window.history.replaceState(null, document.title, "/validators/consolidations" + event.target.getAttribute('href'));
366+
window.history.replaceState(null, document.title, "/validators/consolidations" + link.getAttribute('href'));
366367
}
367368
});
368369
</script>

templates/deposits/deposits.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -490,10 +490,11 @@ <h6 class="m-2 text-muted">This table displays deposits waiting to be activated
490490

491491
function onTabSelected(event) {
492492
event.preventDefault();
493-
var tabId = event.target.getAttribute('data-lazy-tab');
493+
var link = event.currentTarget;
494+
var tabId = link.getAttribute('data-lazy-tab');
494495
var tabEl = document.getElementById(tabId);
495496
if (!$(tabEl).data("loaded")) {
496-
$.get(event.target.getAttribute('href') + "&lazy=true", function(data) {
497+
$.get(link.getAttribute('href') + "&lazy=true", function(data) {
497498
$(tabEl).html(data);
498499
$(tabEl).data("loaded", true);
499500
explorer.initControls();
@@ -503,7 +504,7 @@ <h6 class="m-2 text-muted">This table displays deposits waiting to be activated
503504
var tab = new bootstrap.Tab(tabEl);
504505
tab.show();
505506

506-
window.history.replaceState(null, document.title, "/validators/deposits" + event.target.getAttribute('href'));
507+
window.history.replaceState(null, document.title, "/validators/deposits" + link.getAttribute('href'));
507508
}
508509
});
509510
</script>

templates/exits/exits.html

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -279,10 +279,11 @@ <h6 class="m-2 text-muted">This table displays validators that are currently exi
279279

280280
function onTabSelected(event) {
281281
event.preventDefault();
282-
var tabId = event.target.getAttribute('data-lazy-tab');
282+
var link = event.currentTarget;
283+
var tabId = link.getAttribute('data-lazy-tab');
283284
var tabEl = document.getElementById(tabId);
284285
if (!$(tabEl).data("loaded")) {
285-
$.get(event.target.getAttribute('href') + "&lazy=true", function(data) {
286+
$.get(link.getAttribute('href') + "&lazy=true", function(data) {
286287
$(tabEl).html(data);
287288
$(tabEl).data("loaded", true);
288289
explorer.initControls();
@@ -292,7 +293,7 @@ <h6 class="m-2 text-muted">This table displays validators that are currently exi
292293
var tab = new bootstrap.Tab(tabEl);
293294
tab.show();
294295

295-
window.history.replaceState(null, document.title, "/validators/exits" + event.target.getAttribute('href'));
296+
window.history.replaceState(null, document.title, "/validators/exits" + link.getAttribute('href'));
296297
}
297298
});
298299
</script>

0 commit comments

Comments
 (0)