Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add address_getAppearances #453

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
25 changes: 25 additions & 0 deletions scripts/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,18 @@ methodFiles.forEach(file => {
];
});

methodsBase = "src/address/methods/";
methodFiles = fs.readdirSync(methodsBase);
methodFiles.forEach(file => {
console.log(file);
let raw = fs.readFileSync(methodsBase + file);
let parsed = yaml.load(raw);
methods = [
...methods,
...parsed,
];
});

methodsBase = "src/debug/";
methodFiles = fs.readdirSync(methodsBase);
methodFiles.forEach(file => {
Expand All @@ -55,6 +67,7 @@ methodFiles.forEach(file => {
});

let schemas = {};

let schemasBase = "src/schemas/"
let schemaFiles = fs.readdirSync(schemasBase);
schemaFiles.forEach(file => {
Expand All @@ -67,6 +80,18 @@ schemaFiles.forEach(file => {
};
});

schemasBase = "src/address/schemas/"
schemaFiles = fs.readdirSync(schemasBase);
schemaFiles.forEach(file => {
console.log(file);
let raw = fs.readFileSync(schemasBase + file);
let parsed = yaml.load(raw);
schemas = {
...schemas,
...parsed,
};
});

schemasBase = "src/engine/openrpc/schemas/"
schemaFiles = fs.readdirSync(schemasBase);
schemaFiles.forEach(file => {
Expand Down
84 changes: 84 additions & 0 deletions src/address/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
# Address JSON-RPC API

## Table of Contents

- [Address JSON-RPC API](#address-json-rpc-api)
- [Table of Contents](#table-of-contents)
- [Overview](#overview)
- [Separate `address_` namespace](#separate-address_-namespace)
- [Database requirement](#database-requirement)
- [Rationale for the index existing inside the node](#rationale-for-the-index-existing-inside-the-node)
- ["Address appearances" concept](#address-appearances-concept)
- [Security considerations](#security-considerations)
- [Increased resource use](#increased-resource-use)

## Overview

The Address JSON-RPC API is a collection of methods that Ethereum archival execution clients MAY implement.

This interface allows the use of an archive node from the perspective of an end user.
It provides information about which transactions are important for a given address.
This includes any address, including an externally owned account, a smart wallet, an account abstraction wallet or an application contract.

The API is desinged around an index mapping addresses to transaction identifiers. This index is created in advance so that queries are responded to quickly and do not require block re-execution.

The API allows introspection into otherwise opaque history. An example is an externally
owned account that received ether via a `CALL` opcode.
The API can return this transaction id, which can then be used with other methods (e.g., `debug_traceTransaction`) to identify the meaning of the transaction,
in this case an ether transfer.

## Separate `address_` namespace

A separace `address_` namespace exists because the method(s) within the namespace
require additional considerations that the `eth_` namespace does not require.
Clients that support the `address_` therefore have a clear way to toggle on this feature
to explicitly opt in to these requirements.

The requirements are:
- Archival node (store history for all blocks)
- Additional database requirement (see below)

## Database requirement

A node that supports the `address_` must store an index consisting of a mapping of address
to transaction identifiers. Each block must be parsed and addresses detected. Then for each
address the block number and transaction index must be stored.

The space required for a basic implementation is estimated at 80GB. Client implementations
may be able to reduce this amount significantly.

## Rationale for the index existing inside the node

The rationale for storing the index alongside other chain data is to standardise a new pattern
of data access. Archive nodes that support the `address_` namespace will be able to provide
users with the ability to introspect on particular addresses out of the box. This
means that a frontend can connect to a node and have historical data access for an
arbitrary combination of addresses.

This provides application developers with a new tool for decentralised front ends that
include historical information.

As the `address_` namespace methods apply to all addresses, this is a generalised solution
that makes inclusion inside the node an immediate utility for every user and protocol.

## "Address appearances" concept

`address_getAppearances` is the basic method to discover which transactions are relevant to a given address.

For a given address, this method returns an array of transaction identifiers in which the
address "appears". An "address appearance" is defined in [../../specs/appearance](../../specs/appearance.md)

## Security considerations

See [../../specs/appearance](../../specs/appearance.md) for additional security
considerations.

### Increased resource use

The provision of the `address_` namespace will result in the index being created by
the client. This can cause a temporary high resource use (CPU/disk), and then an
additional amount of work as the chain grows.

The amount of new work for a new block may impact a resource constrained node. The
task involves the equivalent of calling `debug_traceTransaction` with a `callTracer`,
parsing for addresses, and then adding these to a local database.
17 changes: 17 additions & 0 deletions src/address/methods/appearances.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
- name: address_getAppearances
summary: Returns transaction identifiers relevant to an address.
params:
- name: Address
required: true
schema:
$ref: '#/components/schemas/address'
- name: Block range
required: false
schema:
$ref: '#/components/schemas/BlockRange'
result:
name: Address appearances
schema:
oneOf:
- $ref: '#/components/schemas/notFound'
- $ref: '#/components/schemas/AddressAppearances'
38 changes: 38 additions & 0 deletions src/address/schemas/appearances.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
AddressAppearances:
title: Transaction identifiers relevant to an address
type: array
additionalProperties: false
$ref: '#/components/schemas/RelevantTransaction'
RelevantTransaction:
title: Relevant Transaction
type: object
description: Identifier of a transaction relevant to an address
required:
- blockNumber
- location
additionalProperties: false
properties:
blockNumber:
title: Block number
description: Block containing the relevant transactions
$ref: '#/components/schemas/uint'
location:
title: Location in block
$ref: '#/components/schemas/Location'
BlockRange:
title: Block range
type: object
description: Inclusive range of blocks
required:
- firstBlock
- lastBlock
additionalProperties: false
properties:
firstBlock:
title: First block
description: Lowest block in the range
$ref: '#/components/schemas/BlockNumberOrTag'
lastBlock:
title: Last block
description: Highest block in the range
$ref: '#/components/schemas/BlockNumberOrTag'
17 changes: 17 additions & 0 deletions src/schemas/address.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Location:
title: Location in a block
description: A place an address appears within a block
oneOf:
- title: Transaction index
$ref: '#/components/schemas/uint64'
- title: Block field
$ref: '#/components/schemas/BlockField'
BlockField:
title: Block field
description: A block field. Alloc is a genesis block field.
type: string
enum:
- alloc
- miner
- uncles
- withdrawals
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
>> {"jsonrpc":"2.0","id":1,"method":"address_getAppearances","params":["0x0000639850b3ddeaaca4f06280aa751682f11382"]}
<< {"jsonrpc":"2.0","id":1,"result":[]}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
>> {"jsonrpc":"2.0","id":1,"method":"address_getAppearances","params":["0x30a4639850b3ddeaaca4f06280aa751682f11382"]}
<< {"id":1,"jsonrpc":"2.0","result":[{"blockNumber":"0xd63f51","location":"0xe6"},{"blockNumber":"0xd63f5a","location":"0x11b"},{"blockNumber":"0xd68154","location":"0x6"},{"blockNumber":"0xd69d4b","location":"0x3d"},{"blockNumber":"0xd69db2","location":"0x4b"},{"blockNumber":"0xd6de5e","location":"0x25"},{"blockNumber":"0xd6dedb","location":"0x73"},{"blockNumber":"0xd6ecfe","location":"0x66"},{"blockNumber":"0xe00b8c","location":"0x6b"},{"blockNumber":"0xe00b96","location":"0x78"},{"blockNumber":"0xe00b96","location":"0x79"},{"blockNumber":"0xe0ae21","location":"0x126"},{"blockNumber":"0xe2e9b7","location":"0x81"},{"blockNumber":"0xe2e9bd","location":"0x13c"},{"blockNumber":"0xec5518","location":"0xaf"},{"blockNumber":"0xec5569","location":"0x113"},{"blockNumber":"0xec5569","location":"0x11c"},{"blockNumber":"0xec556b","location":"0xa5"},{"blockNumber":"0xec5576","location":"0x125"},{"blockNumber":"0xec557b","location":"0x109"},{"blockNumber":"0xec5584","location":"0x72"},{"blockNumber":"0xec5612","location":"0x1a"},{"blockNumber":"0xf2ea24","location":"0x22"},{"blockNumber":"0xf2ea59","location":"0x95"},{"blockNumber":"0x1064b72","location":"0x54"},{"blockNumber":"0x1064b7a","location":"0x9e"},{"blockNumber":"0x1064f19","location":"0x67"},{"blockNumber":"0x1064f22","location":"0x88"},{"blockNumber":"0x1064fd9","location":"0x5f"},{"blockNumber":"0x1064fe9","location":"0x59"},{"blockNumber":"0x1065d79","location":"0x7d"},{"blockNumber":"0x1065da3","location":"0xa3"},{"blockNumber":"0x106c13f","location":"0x74"},{"blockNumber":"0x10c2127","location":"0x2b"}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
>> {"jsonrpc":"2.0","id":1,"method":"address_getAppearances","params":["0xd2090025857b9c7b24387741f120538e928a3a59",{"firstBlock":"0x1064fd9","lastBlock":"0x1064fe9"}]}
<< {"id":1,"jsonrpc":"2.0","result":[{"blockNumber":"0x1064fd9","location":"0x8"},{"blockNumber":"0x1064fd9","location":"0xcd"},{"blockNumber":"0x1064fd9","location":"miner"}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
>> {"jsonrpc":"2.0","id":1,"method":"address_getAppearances","params":["0x30a4639850b3ddeaaca4f06280aa751682f11382",{"firstBlock":"0x1064fd9","lastBlock":"0x1064fd9"}]}
<< {"id":1,"jsonrpc":"2.0","result":[{"blockNumber":"0x1064fd9","location":"0x5f"}]}
2 changes: 2 additions & 0 deletions tests/address_getAppearances/get-appearances-block-range.io
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
>> {"jsonrpc":"2.0","id":1,"method":"address_getAppearances","params":["0x30a4639850b3ddeaaca4f06280aa751682f11382",{"firstBlock":"0x1064fd9","lastBlock":"0x1064fe9"}]}
<< {"id":1,"jsonrpc":"2.0","result":[{"blockNumber":"0x1064fd9","location":"0x5f"},{"blockNumber":"0x1064fe9","location":"0x59"}]}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
>> {"jsonrpc":"2.0","id":1,"method":"address_getAppearances","params":["0x2d7C6B69175c2939173F2fd470538835336Df92b",{"firstBlock":"0x1064fd9","lastBlock":"0x1064fd9"}]}
<< {"id":1,"jsonrpc":"2.0","result":[{"blockNumber":"0x1064fd9","location":"0x67"},{"blockNumber":"0x1064fd9","location":"0xa3"},{"blockNumber":"0x1064fd9","location":"0xa9"},{"blockNumber":"0x1064fd9","location":"0xb3"},{"blockNumber":"0x1064fd9","location":"0xb6"}]}
1 change: 1 addition & 0 deletions wordlist.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
alloc
apis
attributesv
bodyv
Expand Down