Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .hack/devnet/run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@ EXECUTION_NODES=$(docker ps -aq -f "label=kurtosis_enclave_uuid=$ENCLAVE_UUID" \
-f "label=com.kurtosistech.app-id=kurtosis" \
-f "label=com.kurtosistech.custom.ethereum-package.client-type=execution" | tac)

TRACOOR_NODES=$(docker ps -aq -f "label=kurtosis_enclave_uuid=$ENCLAVE_UUID" \
-f "label=com.kurtosistech.app-id=kurtosis" \
-f "label=com.kurtosistech.id=tracoor" | tac)

TRACOOR_PORT=$(docker inspect --format='{{ (index (index .NetworkSettings.Ports "7007/tcp") 0).HostPort }}' $TRACOOR_NODES)

cat <<EOF > "${__dir}/generated-dora-config.yaml"
logging:
outputLevel: "info"
Expand Down Expand Up @@ -82,6 +88,8 @@ frontend:
disableDasGuardianCheck: false
enableDasGuardianMassScan: true
showValidatorSummary: true
tracoorUrl: "http://127.0.0.1:$TRACOOR_PORT"
tracoorNetwork: "kurtosis"
api:
enabled: true
corsOrigins:
Expand Down
2 changes: 2 additions & 0 deletions clients/execution/chainstate.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ import (
var DefaultSystemContractAddresses = map[string]common.Address{
rpc.ConsolidationRequestContract: common.HexToAddress("0x0000BBdDc7CE488642fb579F8B00f3a590007251"),
rpc.WithdrawalRequestContract: common.HexToAddress("0x00000961Ef480Eb55e80D19ad83579A64c007002"),
rpc.BeaconRootsContract: common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02"),
rpc.HistoryStorageContract: common.HexToAddress("0x0000F90827F1C53a10cb7A02335B175320002935"),
}

type ChainState struct {
Expand Down
2 changes: 2 additions & 0 deletions clients/execution/rpc/ethconfig.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const (
DepositContract = "DEPOSIT_CONTRACT_ADDRESS"
ConsolidationRequestContract = "CONSOLIDATION_REQUEST_PREDEPLOY_ADDRESS"
WithdrawalRequestContract = "WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS"
BeaconRootsContract = "BEACON_ROOTS_ADDRESS"
HistoryStorageContract = "HISTORY_STORAGE_ADDRESS"
)

type EthConfigFork struct {
Expand Down
19 changes: 9 additions & 10 deletions handlers/slot.go
Original file line number Diff line number Diff line change
Expand Up @@ -940,16 +940,15 @@ func getSlotPageBlockData(ctx context.Context, blockData *services.CombinedBlock
getSlotPageTransactions(ctx, pageData, transactions, blockUid)
}

// EIP-7928 Block Access List — Gloas stores the RLP-encoded list on
// the envelope's payload; other forks don't carry it.
if executionPayload.Version >= spec.DataVersionGloas && executionPayload.Gloas != nil {
if balBytes := []byte(executionPayload.Gloas.BlockAccessList); len(balBytes) > 0 {
accesses, err := utils.DecodeBlockAccessList(balBytes)
if err != nil {
logrus.Warnf("error decoding block access list for slot %v: %v", blockData.Header.Message.Slot, err)
} else {
pageData.ExecutionData.BlockAccessList = convertBALToModel(accesses)
}
// EIP-7928 Block Access List — the chainservice sources the bytes
// either from the envelope (fresh from the node) or from blockdb
// (preserved after the node pruned it).
if len(blockData.BlockAccessList) > 0 {
accesses, err := utils.DecodeBlockAccessList(blockData.BlockAccessList)
if err != nil {
logrus.Warnf("error decoding block access list for slot %v: %v", blockData.Header.Message.Slot, err)
} else {
pageData.ExecutionData.BlockAccessList = convertBALToModel(accesses)
}
}

Expand Down
155 changes: 155 additions & 0 deletions handlers/slot_download.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
bdbtypes "github.com/ethpandaops/dora/blockdb/types"
"github.com/ethpandaops/dora/indexer/beacon"
"github.com/ethpandaops/dora/services"
"github.com/ethpandaops/dora/utils"
"github.com/ethpandaops/go-eth2-client/spec/bellatrix"
"github.com/ethpandaops/go-eth2-client/spec/phase0"
"github.com/golang/snappy"
Expand Down Expand Up @@ -88,6 +89,56 @@ func handleSlotDownload(ctx context.Context, w http.ResponseWriter, blockSlot in
case "block-body-json":
return handleBlockBodyDownload(w, blockData)

case "payload-ssz":
if blockData.Payload == nil {
return fmt.Errorf("block has no execution payload envelope")
}
dynSsz := services.GlobalBeaconService.GetBeaconIndexer().GetDynSSZ()
ssz, err := dynSsz.MarshalSSZ(blockData.Payload)
if err != nil {
return fmt.Errorf("error serializing payload envelope: %v", err)
}
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=payload-%d-%x.ssz", blockData.Header.Message.Slot, blockData.Root[:]))
_, _ = w.Write(ssz)
return nil

case "payload-json":
if blockData.Payload == nil {
return fmt.Errorf("block has no execution payload envelope")
}
jsonRes, err := blockData.Payload.MarshalJSON()
if err != nil {
return fmt.Errorf("error serializing payload envelope: %v", err)
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=payload-%d-%x.json", blockData.Header.Message.Slot, blockData.Root[:]))
_, _ = w.Write(jsonRes)
return nil

case "bal-rlp":
if len(blockData.BlockAccessList) == 0 {
return fmt.Errorf("block has no block access list")
}
w.Header().Set("Content-Type", "application/octet-stream")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=bal-%d-%x.rlp", blockData.Header.Message.Slot, blockData.Root[:]))
_, _ = w.Write(blockData.BlockAccessList)
return nil

case "bal-json":
if len(blockData.BlockAccessList) == 0 {
return fmt.Errorf("block has no block access list")
}
accesses, err := utils.DecodeBlockAccessList(blockData.BlockAccessList)
if err != nil {
return fmt.Errorf("error decoding block access list: %v", err)
}
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=bal-%d-%x.json", blockData.Header.Message.Slot, blockData.Root[:]))
encoder := json.NewEncoder(w)
encoder.SetIndent("", " ")
return encoder.Encode(balToJSON(accesses))

default:
return fmt.Errorf("unknown download type: %s", downloadType)
}
Expand Down Expand Up @@ -513,3 +564,107 @@ func buildSingleReceipt(

return receipt, nil
}

// balAccountJSON is the download-friendly JSON shape for one EIP-7928 account
// entry. Uses hex strings for all byte fields so the dump is readable and
// stable across tooling.
type balAccountJSON struct {
Address string `json:"address"`
StorageWrites []balSlotWritesJSON `json:"storage_writes,omitempty"`
StorageReads []string `json:"storage_reads,omitempty"`
BalanceChanges []balBalanceChangeJSON `json:"balance_changes,omitempty"`
NonceChanges []balNonceChangeJSON `json:"nonce_changes,omitempty"`
CodeChanges []balCodeChangeJSON `json:"code_changes,omitempty"`
}

type balSlotWritesJSON struct {
Slot string `json:"slot"`
Accesses []balStorageWriteJSON `json:"accesses"`
}

type balStorageWriteJSON struct {
TxIndex uint16 `json:"tx_index"`
ValueAfter string `json:"value_after"`
}

type balBalanceChangeJSON struct {
TxIndex uint16 `json:"tx_index"`
Balance string `json:"balance"`
}

type balNonceChangeJSON struct {
TxIndex uint16 `json:"tx_index"`
Nonce uint64 `json:"nonce"`
}

type balCodeChangeJSON struct {
TxIndex uint16 `json:"tx_index"`
Code string `json:"code"`
}

// balToJSON converts the RLP-decoded BAL structure into the download JSON shape.
func balToJSON(accesses []utils.BALAccountAccess) []balAccountJSON {
result := make([]balAccountJSON, len(accesses))
for i, entry := range accesses {
out := balAccountJSON{
Address: fmt.Sprintf("0x%x", entry.Address[:]),
}

if len(entry.StorageWrites) > 0 {
out.StorageWrites = make([]balSlotWritesJSON, len(entry.StorageWrites))
for j, sw := range entry.StorageWrites {
writes := make([]balStorageWriteJSON, len(sw.Accesses))
for k, w := range sw.Accesses {
writes[k] = balStorageWriteJSON{
TxIndex: w.TxIdx,
ValueAfter: fmt.Sprintf("0x%x", w.ValueAfter),
}
}
out.StorageWrites[j] = balSlotWritesJSON{
Slot: fmt.Sprintf("0x%x", sw.Slot),
Accesses: writes,
}
}
}

if len(entry.StorageReads) > 0 {
out.StorageReads = make([]string, len(entry.StorageReads))
for j, r := range entry.StorageReads {
out.StorageReads[j] = fmt.Sprintf("0x%x", r)
}
}

if len(entry.BalanceChanges) > 0 {
out.BalanceChanges = make([]balBalanceChangeJSON, len(entry.BalanceChanges))
for j, b := range entry.BalanceChanges {
out.BalanceChanges[j] = balBalanceChangeJSON{
TxIndex: b.TxIdx,
Balance: fmt.Sprintf("0x%x", b.Balance),
}
}
}

if len(entry.NonceChanges) > 0 {
out.NonceChanges = make([]balNonceChangeJSON, len(entry.NonceChanges))
for j, n := range entry.NonceChanges {
out.NonceChanges[j] = balNonceChangeJSON{
TxIndex: n.TxIdx,
Nonce: n.Nonce,
}
}
}

if len(entry.CodeChanges) > 0 {
out.CodeChanges = make([]balCodeChangeJSON, len(entry.CodeChanges))
for j, c := range entry.CodeChanges {
out.CodeChanges[j] = balCodeChangeJSON{
TxIndex: c.TxIndex,
Code: fmt.Sprintf("0x%x", c.Code),
}
}
}

result[i] = out
}
return result
}
6 changes: 3 additions & 3 deletions handlers/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,7 @@ func buildInternalTxsFromBlockdb(ctx context.Context, pageData *models.Transacti
isCreate := f.Type == 3 || f.Type == 4
precompileInfo := utils.GetPrecompileInfo(f.To[:])
sysName, isSysContract := sysContracts[f.To]
isNonDepositSys := isSysContract && sysName != "Deposit"
isNonDepositSys := isSysContract && sysName != "Deposit Contract"

if isCreate {
itx.MethodName = "deploy"
Expand All @@ -1090,9 +1090,9 @@ func buildInternalTxsFromBlockdb(ctx context.Context, pageData *models.Transacti
} else if isNonDepositSys {
itx.MethodName = sysName
switch sysName {
case "Withdrawal Request":
case "Withdrawal Request (EIP-7002)":
itx.DecodedCalldata = utils.DecodeWithdrawalRequestInput(f.Input)
case "Consolidation Request":
case "Consolidation Request (EIP-7251)":
itx.DecodedCalldata = utils.DecodeConsolidationRequestInput(f.Input)
}
} else {
Expand Down
32 changes: 19 additions & 13 deletions services/chainservice.go
Original file line number Diff line number Diff line change
Expand Up @@ -424,24 +424,30 @@ func (bs *ChainService) GetSystemContractAddress(systemContract string) common.A
}

// GetSystemContractAddresses returns a map of all known system contract
// addresses to their human-readable names. Includes deposit, withdrawal
// request, and consolidation request contracts.
// addresses to their human-readable labels (with EIP tags). Includes
// deposit, withdrawal request, consolidation request, beacon roots, and
// block hash history contracts.
func (bs *ChainService) GetSystemContractAddresses() map[common.Address]string {
result := make(map[common.Address]string, 4)
result := make(map[common.Address]string, 5)

labels := map[string]string{
exerpc.WithdrawalRequestContract: "Withdrawal Request (EIP-7002)",
exerpc.ConsolidationRequestContract: "Consolidation Request (EIP-7251)",
exerpc.BeaconRootsContract: "Beacon Roots (EIP-4788)",
exerpc.HistoryStorageContract: "Block Hash History (EIP-2935)",
}

execChainState := bs.GetExecutionChainState()
if execChainState != nil {
withdrawalAddr := execChainState.GetSystemContractAddress(exerpc.WithdrawalRequestContract)
consolidationAddr := execChainState.GetSystemContractAddress(exerpc.ConsolidationRequestContract)
result[withdrawalAddr] = "Withdrawal Request"
result[consolidationAddr] = "Consolidation Request"
for name, label := range labels {
if addr := execChainState.GetSystemContractAddress(name); addr != (common.Address{}) {
result[addr] = label
}
}
} else {
for name, addr := range execution.DefaultSystemContractAddresses {
switch name {
case exerpc.WithdrawalRequestContract:
result[addr] = "Withdrawal Request"
case exerpc.ConsolidationRequestContract:
result[addr] = "Consolidation Request"
if label, ok := labels[name]; ok {
result[addr] = label
}
}
}
Expand All @@ -453,7 +459,7 @@ func (bs *ChainService) GetSystemContractAddresses() map[common.Address]string {
if specs != nil && len(specs.DepositContractAddress) == 20 {
var depositAddr common.Address
copy(depositAddr[:], specs.DepositContractAddress)
result[depositAddr] = "Deposit"
result[depositAddr] = "Deposit Contract"
}
}

Expand Down
Loading