Skip to content

Commit

Permalink
feat: Port blockchains client/parser changes (#106)
Browse files Browse the repository at this point in the history
* Port blockchains client/parser changes
  • Loading branch information
wangwzhou authored Sep 23, 2024
1 parent 57f1971 commit f8bff30
Show file tree
Hide file tree
Showing 15 changed files with 2,776 additions and 1,149 deletions.
4 changes: 2 additions & 2 deletions internal/blockchain/client/aptos/aptos.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,12 +122,12 @@ func (c *aptosClientImpl) GetLatestHeight(ctx context.Context) (uint64, error) {
return 0, xerrors.Errorf("failed to unmarshal ledger info: %w", err)
}

block_height, err := strconv.ParseUint(ledgerInfo.LatestBlockHeight, 10, 64)
blockHeight, err := strconv.ParseUint(ledgerInfo.LatestBlockHeight, 10, 64)
if err != nil {
return 0, xerrors.Errorf("failed to parse ledgerInfo's block_height=%v: %w", ledgerInfo.LatestBlockHeight, err)
}

return block_height, nil
return blockHeight, nil
}

func (c *aptosClientImpl) UpgradeBlock(_ context.Context, _ *api.Block, _ uint32) (*api.Block, error) {
Expand Down
577 changes: 372 additions & 205 deletions internal/blockchain/parser/aptos/aptos_native.go

Large diffs are not rendered by default.

112 changes: 83 additions & 29 deletions internal/blockchain/parser/ethereum/ethereum_native.go
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ type (
// Note that the unit of withdrawal `amount` is in Gwei (1e9 wei).
Withdrawals []*EthereumWithdrawal `json:"withdrawals"`
WithdrawalsRoot EthereumHexString `json:"withdrawalsRoot"`

// EIP-4788 introduces the parent beacon block root in the execution payload.
// https://eips.ethereum.org/EIPS/eip-4788
ParentBeaconBlockRoot EthereumHexString `json:"parentBeaconBlockRoot"`

// EIP-4844 introduces blob gas fields in the execution payload.
// https://eips.ethereum.org/EIPS/eip-4844
BlobGasUsed *EthereumQuantity `json:"blobGasUsed"`
ExcessBlobGas *EthereumQuantity `json:"excessBlobGas"`
}

PolygonHeader struct {
Expand Down Expand Up @@ -116,6 +125,9 @@ type (
MaxPriorityFeePerGas *EthereumQuantity `json:"maxPriorityFeePerGas"`
AccessList *[]*EthereumTransactionAccess `json:"accessList"`
Mint *EthereumBigQuantity `json:"mint"`
// The EIP-4844 related fields
MaxFeePerBlobGas *EthereumBigQuantity `json:"maxFeePerBlobGas"`
BlobVersionedHashes *[]EthereumHexString `json:"blobVersionedHashes"`

// Deposit transaction fields for Optimism and Base.
SourceHash EthereumHexString `json:"sourceHash"`
Expand Down Expand Up @@ -162,6 +174,10 @@ type (
// Base/Optimism specific fields.
DepositNonce *EthereumQuantity `json:"depositNonce"`
DepositReceiptVersion *EthereumQuantity `json:"depositReceiptVersion"`

// The EIP-4844 related fields
BlobGasPrice *EthereumQuantity `json:"blobGasPrice"`
BlobGasUsed *EthereumQuantity `json:"blobGasUsed"`
}

EthereumTransactionReceiptLit struct {
Expand Down Expand Up @@ -665,6 +681,7 @@ func (p *ethereumNativeParserImpl) parseHeader(data []byte) (*api.EthereumHeader
SourceHash: transaction.SourceHash.Value(),
IsSystemTx: transaction.IsSystemTx,
}
outTransaction := transactions[i]
gasPrice, err := transaction.GasPrice.Uint64()
if err != nil {
// Ignore parse error for ethereum testnets and arbitrum
Expand All @@ -681,21 +698,21 @@ func (p *ethereumNativeParserImpl) parseHeader(data []byte) (*api.EthereumHeader
return nil, nil, xerrors.Errorf("failed to parse transaction GasPrice to uint64 %v", transaction.GasPrice.Value())
}
}
transactions[i].GasPrice = gasPrice
outTransaction.GasPrice = gasPrice

if transaction.MaxFeePerGas != nil {
transactions[i].OptionalMaxFeePerGas = &api.EthereumTransaction_MaxFeePerGas{
outTransaction.OptionalMaxFeePerGas = &api.EthereumTransaction_MaxFeePerGas{
MaxFeePerGas: transaction.MaxFeePerGas.Value(),
}
}
if transaction.MaxPriorityFeePerGas != nil {
transactions[i].OptionalMaxPriorityFeePerGas = &api.EthereumTransaction_MaxPriorityFeePerGas{
outTransaction.OptionalMaxPriorityFeePerGas = &api.EthereumTransaction_MaxPriorityFeePerGas{
MaxPriorityFeePerGas: transaction.MaxPriorityFeePerGas.Value(),
}
}

if transaction.Mint != nil && transaction.Mint.Value() != "0" {
transactions[i].OptionalMint = &api.EthereumTransaction_Mint{
outTransaction.OptionalMint = &api.EthereumTransaction_Mint{
Mint: transaction.Mint.Value(),
}
}
Expand All @@ -715,13 +732,13 @@ func (p *ethereumNativeParserImpl) parseHeader(data []byte) (*api.EthereumHeader
// Legacy transaction where effectiveGasPrice = gasPrice
priorityFeePerGas = gasPrice - block.BaseFeePerGas.Value()
}
transactions[i].OptionalPriorityFeePerGas = &api.EthereumTransaction_PriorityFeePerGas{
outTransaction.OptionalPriorityFeePerGas = &api.EthereumTransaction_PriorityFeePerGas{
PriorityFeePerGas: priorityFeePerGas,
}
}

if transaction.AccessList != nil {
transactions[i].OptionalTransactionAccessList = &api.EthereumTransaction_TransactionAccessList{
outTransaction.OptionalTransactionAccessList = &api.EthereumTransaction_TransactionAccessList{
TransactionAccessList: &api.EthereumTransactionAccessList{
AccessList: p.parseTransactionAccessList(transaction),
},
Expand All @@ -730,36 +747,61 @@ func (p *ethereumNativeParserImpl) parseHeader(data []byte) (*api.EthereumHeader

// EIP-155 related filed.
if transaction.ChainId != nil {
transactions[i].OptionalChainId = &api.EthereumTransaction_ChainId{
outTransaction.OptionalChainId = &api.EthereumTransaction_ChainId{
ChainId: transaction.ChainId.Value(),
}
}

if transaction.MaxFeePerBlobGas != nil {
outTransaction.OptionalMaxFeePerBlobGas = &api.EthereumTransaction_MaxFeePerBlobGas{
MaxFeePerBlobGas: transaction.MaxFeePerBlobGas.Value(),
}
}

if transaction.BlobVersionedHashes != nil {
hashes := make([]string, len(*transaction.BlobVersionedHashes))
for j, h := range *transaction.BlobVersionedHashes {
hashes[j] = h.Value()
}
outTransaction.BlobVersionedHashes = hashes
}
}
uncles := p.copyEthereumHexStrings(block.Uncles)
withdrawals := p.parseWithdrawals(block.Withdrawals)
header := &api.EthereumHeader{
Hash: block.Hash.Value(),
ParentHash: block.ParentHash.Value(),
Number: block.Number.Value(),
Timestamp: &timestamp.Timestamp{Seconds: int64(block.Timestamp.Value())},
Transactions: transactionHashes,
Nonce: block.Nonce.Value(),
Sha3Uncles: block.Sha3Uncles.Value(),
LogsBloom: block.LogsBloom.Value(),
TransactionsRoot: block.TransactionsRoot.Value(),
StateRoot: block.StateRoot.Value(),
ReceiptsRoot: block.ReceiptsRoot.Value(),
Miner: block.Miner.Value(),
Difficulty: block.Difficulty.Value(),
TotalDifficulty: block.TotalDifficulty.Value(),
ExtraData: block.ExtraData.Value(),
Size: block.Size.Value(),
GasLimit: block.GasLimit.Value(),
GasUsed: block.GasUsed.Value(),
Uncles: uncles,
MixHash: block.MixHash.Value(),
Withdrawals: withdrawals,
WithdrawalsRoot: block.WithdrawalsRoot.Value(),
Hash: block.Hash.Value(),
ParentHash: block.ParentHash.Value(),
Number: block.Number.Value(),
Timestamp: &timestamp.Timestamp{Seconds: int64(block.Timestamp.Value())},
Transactions: transactionHashes,
Nonce: block.Nonce.Value(),
Sha3Uncles: block.Sha3Uncles.Value(),
LogsBloom: block.LogsBloom.Value(),
TransactionsRoot: block.TransactionsRoot.Value(),
StateRoot: block.StateRoot.Value(),
ReceiptsRoot: block.ReceiptsRoot.Value(),
Miner: block.Miner.Value(),
Difficulty: block.Difficulty.Value(),
TotalDifficulty: block.TotalDifficulty.Value(),
ExtraData: block.ExtraData.Value(),
Size: block.Size.Value(),
GasLimit: block.GasLimit.Value(),
GasUsed: block.GasUsed.Value(),
Uncles: uncles,
MixHash: block.MixHash.Value(),
Withdrawals: withdrawals,
WithdrawalsRoot: block.WithdrawalsRoot.Value(),
ParentBeaconBlockRoot: block.ParentBeaconBlockRoot.Value(),
}
if block.BlobGasUsed != nil {
header.OptionalBlobGasUsed = &api.EthereumHeader_BlobGasUsed{
BlobGasUsed: block.BlobGasUsed.Value(),
}
}
if block.ExcessBlobGas != nil {
header.OptionalExcessBlobGas = &api.EthereumHeader_ExcessBlobGas{
ExcessBlobGas: block.ExcessBlobGas.Value(),
}
}
if block.BaseFeePerGas != nil {
header.OptionalBaseFeePerGas = &api.EthereumHeader_BaseFeePerGas{
Expand Down Expand Up @@ -877,6 +919,18 @@ func (p *ethereumNativeParserImpl) parseTransactionReceipts(blobdata *api.Ethere
DepositReceiptVersion: receipt.DepositReceiptVersion.Value(),
}
}

if receipt.BlobGasPrice != nil {
receipts[i].OptionalBlobGasPrice = &api.EthereumTransactionReceipt_BlobGasPrice{
BlobGasPrice: receipt.BlobGasPrice.Value(),
}
}

if receipt.BlobGasUsed != nil {
receipts[i].OptionalBlobGasUsed = &api.EthereumTransactionReceipt_BlobGasUsed{
BlobGasUsed: receipt.BlobGasUsed.Value(),
}
}
}

return receipts, nil
Expand Down
55 changes: 55 additions & 0 deletions internal/blockchain/parser/ethereum/ethereum_native_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,14 @@ var (
ParentHeight: uint64(0xc5d823),
}

ethereumMetadataPostDencun = &api.BlockMetadata{
Tag: ethereumTag,
Hash: "0x063d33e2bcaaf7120314c8e182fd5f123e0aea285b5efacfacf3733906eeb25e",
ParentHash: "0xf6f01969dcd86ccb581212587c27d4be0962e8a46a441efdaf667c34ac908e7a",
Height: uint64(0x1e06b),
ParentHeight: uint64(0x1e06a),
}

fixtureHeaderPostLondon = []byte(`
{
"difficulty": "0x1ac98fe2d7d4a9",
Expand Down Expand Up @@ -2689,6 +2697,53 @@ func TestParseEthereumBlock_PostLondon_LegacyTransaction(t *testing.T) {
require.Equal(expected.Transactions, actual.Transactions)
}

func TestParseEthereumBlock_DencunBlobTransaction(t *testing.T) {
require := testutil.Require(t)
fixtureHeaderPostDencun := fixtures.MustReadFile("parser/ethereum/ethereum_header_post_dencun_122987.json")
fixtureReceiptPostDencun := fixtures.MustReadFile("parser/ethereum/ethereum_receipt_post_dencun_122987.json")
fixtureTracesPostDencun := fixtures.MustReadFile("parser/ethereum/ethereum_traces_post_dencun_122987.json")

block := &api.Block{
Blockchain: common.Blockchain_BLOCKCHAIN_ETHEREUM,
Network: common.Network_NETWORK_ETHEREUM_MAINNET,
Metadata: ethereumMetadataPostDencun,
Blobdata: &api.Block_Ethereum{
Ethereum: &api.EthereumBlobdata{
Header: fixtureHeaderPostDencun,
TransactionReceipts: [][]byte{fixtureReceiptPostDencun},
TransactionTraces: [][]byte{fixtureTracesPostDencun},
},
},
}

var expected api.EthereumBlock
fixtures.MustUnmarshalPB("parser/ethereum/ethereum_header_expected_post_dencun_122987.json", &expected)

var parser internal.Parser
app := testapp.New(
t,
Module,
internal.Module,
fx.Populate(&parser),
)
defer app.Close()

require.NotNil(parser)

nativeBlock, err := parser.ParseNativeBlock(context.Background(), block)

require.NoError(err)

require.Equal(common.Blockchain_BLOCKCHAIN_ETHEREUM, nativeBlock.Blockchain)
require.Equal(common.Network_NETWORK_ETHEREUM_MAINNET, nativeBlock.Network)

actual := nativeBlock.GetEthereum()
require.NotNil(actual)
require.Equal(expected.Header, actual.Header)

require.Equal(expected.Transactions, actual.Transactions)
}

func TestParseEthereumBlock_FlattenedTraces(t *testing.T) {
require := testutil.Require(t)

Expand Down
2 changes: 1 addition & 1 deletion internal/blockchain/parser/solana/solana_instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ type (
Source string `json:"source" validate:"required"`
NewAccount string `json:"newAccount" validate:"required"`
Base string `json:"base" validate:"required"`
Seed string `json:"seed" validate:"required"`
Seed string `json:"seed"`
Lamports uint64 `json:"lamports"`
Space uint64 `json:"space"`
Owner string `json:"owner" validate:"required"`
Expand Down
25 changes: 25 additions & 0 deletions internal/blockchain/parser/solana/solana_native_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,31 @@ func (s *solanaNativeParserTestSuite) TestParseBlockV2() {
}, transaction.GetPayload())
}

// This block had a failed transaction (Instruction Error - ProgramFailedToComplete). Test that we can parse it
// without error.
func (s *solanaNativeParserTestSuite) TestParseBlockV2_Slot_241043141() {
require := testutil.Require(s.T())

block := &api.Block{
Blockchain: common.Blockchain_BLOCKCHAIN_SOLANA,
Network: common.Network_NETWORK_SOLANA_MAINNET,
Metadata: &api.BlockMetadata{
Tag: 2,
Hash: "7UVhKXDoFXfQWHRRMNaXiEXiQsabDvU7oz4TRLHFuzd8",
ParentHash: "8KrXYfWrGMBJg6owJ5U5X1c6rxh3iVxbybvSK5hbTZtA",
Height: 241043141,
ParentHeight: 241043140,
},
Blobdata: &api.Block_Solana{
Solana: &api.SolanaBlobdata{
Header: fixtures.MustReadFile("parser/solana/block_241043141_v2.json"),
},
},
}
_, err := s.parser.ParseBlock(context.Background(), block)
require.NoError(err)
}

func (s *solanaNativeParserTestSuite) TestParseBlockV2_Slot_217003034() {
require := testutil.Require(s.T())

Expand Down
Loading

0 comments on commit f8bff30

Please sign in to comment.