-
Notifications
You must be signed in to change notification settings - Fork 4
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
Support for pre-Damask runtime rounds #362
Conversation
17e0ed1
to
c80694f
Compare
c80694f
to
f1081e5
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good; mostly minor comments. The runtime block processing looks cleaner now, thanks
Erc20Transfer = "erc20.transfer" | ||
Erc20Approval = "erc20.approval" | ||
Erc20Transfer = "Transfer" | ||
Erc20Approval = "Approval" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was there a specific reason for this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah what did these erc20.
prefixes used to do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm pretty sure we just accidentally mis-named these when introducing them. We use these as event names for ERC-20 tokens, and the Transfer
and Approval
names are prescribed by ERC-20. We don't read these names from the ABI currently, but we will, and if we did now, these are the names that would come out of there.
Not related to the rest of the PR, just a drive-by bugfix. It doesn't affect anything, other than how we tag ERC-20 events in our output. @lukaw3d @csillag @buberdds FYI - these are the new values you'll see in evm_log_name once this change deploys. IDK if you depend on the old values in any way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not clear that having the erc20.
prefix was wrong. this system of evm log "names" is completely our own invention. removing the prefix actually seems a little lossy. I just looked, and we use these values as the evm_log_name
column. that looks like it's our substitute for the topic id, which the event name doesn't fully convey (it also hashes the parameter types). with the "erc20." we had at least a fighting chance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Log/event names are not our invention. The topic of the event is derived from the name and the types of its params, see e.g. "Topics in Ethereum Log Records" here, or how the event API/ABI defines the name here.
We do expose the topic (which is what we'll eventually want to support filtering on, presumably), but it's a little hidden, in the untyped JSON body
field. Example from indexer DB:
runtime | emerald
round | 2784
tx_index | 0
tx_hash | e415d067861d27a50331bc1ba66097af6cc034b53d1c379c07be858815cc778c
type | evm.log
body | {"address":"oXu9ULEcodbSP5Ca5AxBNNghrF4=","topics":["3fJSrRviyJtpwrBo/DeNqpUrp/FjxKEWKPVaTfUjs+8=","AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=","AAAAAAAAAAAAAAAAisMZWuyjmKrHiCUg3RnTx8XmnkY="],"data":"AAAAAAAAAAAAAAAAAAAAAAAAAAAAUrfS3MgM0uQAAAA="}
evm_log_name | Transfer
evm_log_signature | 3fJSrRviyJtpwrBo/DeNqpUrp/FjxKEWKPVaTfUjs+8=
evm_log_params | [{"name": "from", "value": "0x0000000000000000000000000000000000000000", "evm_type": "address"}, {"name": "to", "value": "0x8ac3195aeca398aac7882520dd19d3c7c5e69e46", "evm_type": "address"}, {"name": "value", "value": "100000000000000000000000000", "evm_type": "uint256"}]
related_accounts | {oasis1qqm0rpeswnu8a5p0rphkppg2zulwrg57zskpxp0j,oasis1qqctk3c8a2ualcwufcxn337hchdflyjurgdmqt3e}
I'm open to eventually surfacing the topic(s) (or maybe just the first one, and only for non-anonymous events? i.e. the topic that represents the event signature/type) in a dedicated field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's a different "name," originating from solidity code. EVM logs don't have a name, only topic. as the page describes, solidity contracts in particular derive the topic from a name and parameter types.
We do expose the topic (which is what we'll eventually want to support filtering on, presumably)
oh in body, great. hadn't noticed that
// Implementation of `RuntimeApiLite` that supports all versions of the node ABI | ||
// and all versions of the oasis-sdk ABI. (SDK events are CBOR-encoded according |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just curious - there's just a single node ABI used here right? But the resulting grpc.RawMessage
is then decoded into one of two possible sdk ABIs? (cobalt/damask)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm perhaps splitting hairs here. All I wanted to say was that this struct works with all versions of everything. It speaks two node ABIs (cobalt and damask, although technically those are not ABI version names, and ABI changes just happen to coincide with launching a new dump-restore chain). See GetBlockHeader() to see two versions being supported; for the other calls, i.e. GetTransactionsWithResults() and GetEventsRaw() and SimulateCall(), damask and cobalt use the same ABI and so we just pretend everything is damask and use the damask SDK.
By SDK decoding and ABIs, I meant how events are encoded. Those are decoded with support for all versions in https://github.com/oasisprotocol/oasis-indexer/blob/90968f1819dcf486c74df323d52b48f081a7ebfb/analyzer/runtime/decode_events.go#L14-L14; note the use of unmarshalSingleOrArray
. I think all of this decoding should really happen in nodeapi so that nodeapi can present a unified internal type to the indexer, but I didn't want to refactor more than I had to in this PR.
continue | ||
} | ||
// Iterate over all networks and find the one that contains the runtime. | ||
// Any network will do; we assume that paratime IDs are unique across networks. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
paratime IDs are chosen by the entity that registers them
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oooh! A potential for some malarkey then. Very good to know, thanks.
I just left a TODO/note of this; once we sort out how to merge this with your #352, this hacky approach will hopefully not be needed any more.
Actually, we'll need to tweak/expand DefaultChains
from #352 a little so that they include some runtime info. The existing DefaultNetworks
from oasis-sdk assign a paratime to a specific chaincontext, but really with dump-restores they can be assigned to a "metachain", i.e. to all of the chaincontexts that comprise(d) mainnet.
We could do that inference programmatically, but I think it will be much more readable to just copy paste a li'l more info over into DefaultChains
and then use it here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah actually your PR intentionally limits its scope to consensus only. Added a task to https://github.com/oasisprotocol/oasis-indexer/pull/352/files#r1152431146 where I previously started discussing follow-ups.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, and that DefaultNetworks lookup also gets complicated by the custom chains used for testing etc.
api/v1/types/util.go
Outdated
@@ -2,9 +2,11 @@ package types | |||
|
|||
import "fmt" | |||
|
|||
// Hardcoded event names emitted by ERC-20 contracts. | |||
// TODO: Remove these once we are able to query the ABI of the contract. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh we have the ABI checked in now. it's in the analyzer directory tho. evmabi.ERC20
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, we could extract them from the ABI already. It's just that it's only one ABI that we have, so it was easier to hardcode than to implement "properly", the way we'll have to once we support arbitrary contracts/ABIs/events. I reworded the TODO. I'm not implementing it here though if that's what you meant; it's completely out of scope for the PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just looked at the abi structures, and it's all Events map[string]Event
, so we wouldn't be able to get it from a constant anyway
// unmarshalSingleOrArray tries to interpret `data` as an array of `T`. | ||
// Failing that, it interprets it as a single `T`, and returns a slice | ||
// of size 1 containing that `T`. | ||
func unmarshalSingleOrArray[T any](data []byte, dst *[]T) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow our first generic code
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
being dragged kicking and screaming into the Century of the Fruitbat :)
(obscure reference, move along)
analyzer/runtime/extract.go
Outdated
// Inaccurate: Treat as not using any gas. | ||
// TODO: Decode the tx; if it failed with "out of gas", assume it used all the gas. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe we should treat transactions that came before the GasUsed event as always using all the gas unless the authentication failed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eh let's discuss that outside of this pr
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Possibly. Or we could do what I described in the comment, or something even more complex, like your suggestion from Slack:
in that case we can do
auth failed -> no gas used
insufficient balance (outside evm) -> no gas used
most things within evm -> all gas used
Or we could leave things as-is, which I argued for in slack (but didn't update this TODO afterwards):
I tried charging full gas_limit to all txs, and the fallout took me a while to figure out ...
It turns out that some failed txs have a huge gas_limit; for example, I hit one with MAX_INT64. When you add other txs' gas limits to it, the block gas limit overflows int64 (and could easily overflow uint64). So that blows up in other places that expect total block gas to not exceed uint64; the db even uses int64. [GitHub edit: Maybe we'd avoid this with the full three-pronged approach above, but I have no impulse to play around more; see also below.]
Long story short, I'm leaving failed txs with no GasUsed event as-is, meaning we estimate them to have used 0 gas.
I also like this product-wise. If the gas we show is going to be a little wrong (and it always will be, no matter how we refine our heuristic), it should at least be easy to explain on the rare occasion when we have to acknowledge the discrepancy.
So -- removing the TODO.
0c4f7be
to
7a221cb
Compare
…e yet. No support for very early blocks.
…m internal struct
…not from internal struct
… in a single list
7a221cb
to
72ad55f
Compare
@@ -45,24 +48,6 @@ func (rc *RuntimeClient) EVMSimulateCall(ctx context.Context, round uint64, gasP | |||
return rc.nodeApi.EVMSimulateCall(ctx, round, gasPrice, gasLimit, caller, address, value, data) | |||
} | |||
|
|||
// Name returns the name of the client, for the RuntimeSourceStorage interface. | |||
func (rc *RuntimeClient) Name() string { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😈 goodbye name
blockData.Size += blockTransactionData.Size | ||
} | ||
return &blockData, nil | ||
} | ||
|
||
func extractEvents(blockData *BlockData, relatedAccountAddresses map[apiTypes.Address]bool, eventsRaw []*nodeapi.RuntimeEvent) (*extractEventResult, error) { | ||
func sumGasUsed(events []*EventData) (sum uint64, foundGasUsedEvent bool) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there aren't really multiple though, are there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
reviewed
This PR brings support for indexing "old" runtime blocks. Changes:
roothash
app) for the runtime block info. And its API has changed going from Cobalt to Damask.Testing:
reindex_and_run.sh
for 100 rounds in Damask.