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

feat(specs): add spec for address Appearance #456

Open
wants to merge 6 commits into
base: main
Choose a base branch
from

Conversation

perama-v
Copy link
Contributor

Adds a specification of an address "appearance".

Motivation

Appearance are a common concept used by different proposed methods (eth_getAddressesInblock, address_getAppearances)

Extraction of the definition as a separate PR simplifies those efforts.

Overview

If a transaction is an appearance for a particular address, it implies that the transaction may be "of interest" for
that address. An inventory of such transactions represents a set of transactions relevant to an address.

The concept is originally introduced by the UnchainedIndex https://github.com/TrueBlocks/trueblocks-core.

@tjayrush
Copy link

tjayrush commented Aug 11, 2023

I'll copy in my responses from our discord chat:

How does UnchainedIndex handle an appearance that is not part of a transaction? E.g., uncle reward.

I expect that it does not differentiate between appearing in the first transaction and appearing in a non-transaction

So an appearance for: (block_number, transaction_index=0) implies that when one looks over that transaction to find the appearance, one must also look in the non-transaction locations. If so, I think this is good behaviour, as an address can always appear in non transaction locations in addition to a transaction. For example (block_number, transaction_index=23) does not preclude that address also being the block reward recipient (or uncle reward, or withdrawals recipient).

tjayrush | TrueBlocks.io — Today at 5:37 PM
Excellent question. There's four (I think, maybe five) places where an address can appear in non-transactions. Mining reward, uncle reward (although, I guess this no longer exists), withdrawals (thanks to you I am now aware of this), self-destruct receipients, prefund (block zero) txs. We do something weird. Since we have a fixed width record for each appearance (which makes reading the file astonishingly fast) we store nine-digits for the block number and five digits for the transaction id in some parts of our code. For non-transactions, we start at 99999 and move backward for each of these five types. So uncles are 99998, etc. (To be honest, it's not well thought out...) and we're totally open to discussion here. Thanks for asking such an amazing questions.
We don't use index zero for non-transactions as transaction id zero is a valid id and it's easier to use a number that won't conflict.
And, yes, you're right. An address can appear uniquely in each of those five places in a single block.
I expect that it does not differentiate between appearing in the first transaction and appearing in a non-transaction

It actually does. It has to. We use 99999 and move backwards for non-transactions appearances. Not perfect, but we didn't want to grow the data by adding another field.

So what I am thinking is that rather than having the get_addressesInBlock return an empty list for an address that only appears in non-transactions. Example (dummy) data
{"address":"0x00000000000000adc04c56bf30ac9d3c0aaf14dc","indices":["0xbc","0xc6"]},
{"address":"0x000000000000012f9f5834e18ae9de5bb945fcbc","indices":[]},

Index 0 is used instead
{"address":"0x00000000000000adc04c56bf30ac9d3c0aaf14dc","indices":["0xbc","0xc6"]},
{"address":"0x000000000000012f9f5834e18ae9de5bb945fcbc","indices":["0x0"]},

The use of index 0 simplifies the definition of an "appearance": it always has a block number and transaction index (rather than block number and optional index). This is relevant for node client implementations that store transaction identifiers as global indices. So an appearance can always be represented as a transaction identifier in a database.

tjayrush | TrueBlocks.io — Today at 5:43 PM
Don't do this. This is a bad idea. Also, don't make it optional. Both of those things require special (and weird) processing. Use a sentinel value (as you are by using 0) but make the sentinel unique. We use 99999 because our field size of five wide in some of our processing and reading a file with fixed length records is SUPER fast. It's very important.

All the benefits you point to (an appearance always having both block number and transaction id, globally (at least per-chain) uniqueness, small size, etc.) is preserved with a sentinal like 99999. (Or some other sentinal known not to clash with transaction id for regular transactions.)

@perama-v
Copy link
Contributor Author

The use of sentinel values is compelling and tentatively looks viable for client implementations.

an address can appear in non-transactions. Mining reward, uncle reward (although, I guess this no longer exists), withdrawals (thanks to you I am now aware of this), self-destruct receipients, prefund (block zero) txs.

Spec has been updated to include "miner", "uncles", "withdrawals" and "alloc" (for prefund/genesis) as valid values for extra-transaction appearances.

Self-destruct included as an intra-transaction appearance (SELFDESTRUCT opcode "address" field). The rationale is that while destruction occurs at the end of the transaction, it is still activated in the EVM.

@perama-v
Copy link
Contributor Author

perama-v commented Aug 13, 2023

A note for implementation if transactions are represented with a global counter across all blocks:

Suppose each transaction is a u32, the upper bits can be used for extra-block appearances.

# transaction 0 in block 55555
00000......01234567
# transaction 0 and block withdrawal in block 55555
11000......01234567
#  block withdrawal in block 55555
01000......01234567

Bits could indicate: intra-transaction, withdrawals, miner, uncles, alloc. If flags are used but the first bit is unset, then no-intra-transaction appearance occurred. This is just an example not part of the spec or implementation.

Edit: alloc (genesis address recipient) is always in the first block, so a field is not likely to be required.

@tjayrush
Copy link

tjayrush commented Aug 13, 2023

The use of sentinel values is compelling and tentatively looks viable for client implementations.

an address can appear in non-transactions. Mining reward, uncle reward (although, I guess this no longer exists), withdrawals (thanks to you I am now aware of this), self-destruct receipients, prefund (block zero) txs.

Spec has been updated to include "miner", "uncles", "withdrawals" and "alloc" (for prefund/genesis) as valid values for extra-transaction appearances.

Self-destruct included as an intra-transaction appearance (SELFDESTRUCT opcode "address" field). The rationale is that while destruction occurs at the end of the transaction, it is still activated in the EVM.

I may be mis-remembering, but at one point I thought a transaction like this:

curl http://localhost:23456 -X POST -H "Content-Type: application/json" --data '{"method":"trace_transaction","params":["0x343ba476313771d4431018d7d2e935eba2bfe26d5be3e6cb84af6817fd0e4309"],"id":1,"jsonrpc":"2.0"}' 

(This has both the creation of and the self destruction of a contract in the same transaction.)

Did something weird like send the funds to the smart contract to itself. I'm not sure this is correct, but I remember something.

@perama-v
Copy link
Contributor Author

Yes that is a good example. The addresses involved in this transaction would both be considered to appear.

The appearance is transaction 5 block 2608034. So this can safely be classified as intra-transaction.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants