-
Notifications
You must be signed in to change notification settings - Fork 141
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
Technical design: Logs and events #728
Comments
edit: hm. Wrong issue. |
On bloom filters, we should revisit that decision from first principles.
From that, I'd say we should:
Where to put them... I'd prefer to hang them off the block (treat them like receipts), we should talk with the core implementers to see how difficult this would be. For example, we could change If not, storing them in an actor isn't the end of the world. However:
|
Resolution from the discussion today:
Specifically, something like: type BlockHeader struct {
Miner address.Address // 0 unique per block/miner
// ...
ParentArtifacts cid.Cid
}
type ExecutionArtifacts struct { // name TBD
// A variable-sized bloom filter to quickly tell what events may exist.
EventBloomFilter []byte
// An AMT of all events.
Events cid.Cid
// A HAMT indexing events mapping index keys to indices in the Events AMT.
EventIndex cid.Cid
} Design rational:
Drawbacks:
Open Questions:
|
@raulk we should probably discuss the open questions in standup before continuing here. |
Next step: Write up a series of use-cases to better understand the problem. |
Use cases include:
|
We will need to associate the logs to the concrete messages that emitted them. Ethereum does this by embedding the logs in the receipt (including a bloom filter, which I don't know if it's scoped to the logs in that message, or the cumulative bloom filter up until then; I'd imagine the former). One idea is to have a top level structure vector structure collecting all logs from the tipset, and receipts would contain bitfields addressing the emitted logs via their index into the vector. However, this makes producing inclusion proofs harder (I think), and it makes the message receipts less useful by themselves. |
@Stebalien what is "index keys" that are the keys of the HAMT? I agree that logs/events need to be referenced from the message receipts in order to be most useful to light clients, UIs etc. If we put such structure in the message receipts, then do we need the events and index in the block at all? They're committed via the receipts root CID. |
TBD. We want to make it possible for a light client to get a succinct (and cheap) proof that some event did or did not happen in any given block. Likely:
But I'm a bit concerned that the HAMT could grow large.
Unfortunately, light clients would have to download all messages and receipts (including top-level return values) for that to work. We'd like light clients to be able to download just:
Then, if their event is in the bloom filter:
|
Concrete proposal:
fn log(count: u32, topics: *const u8, value: BlockId) Where:
Define an event object of the type: struct Event {
actor: ActorID,
topics: Vec<u8>,
value: cid.Cid,
} When an event is logged:
When creating a message receipt, pack all events into an AMT in-order and include the AMT root in the receipt. Decisions
|
Notes from sync design meeting + concrete proposals Descoping indicesWe are moving the indexes out of the scope of this solution. Right now we want to focus on the simplest, extensible solution that: (a) is not overengineered for what we need now, (b) does not back us into a design corner now without sufficient information, (c) is easily extensible in the future. Storing raw eventsFor now, we will be storing the raw events only, allowing clients to experiment and generate indexes client side entirely. The schema of an event is as follows:
During execution, the Call Manager adds emitted events to the blockstore and populates an AMT tracking the Cids of those event objects. Commitment on chainWe extend the pub struct Receipt {
// existing fields
exit_code: ExitCode,
return_data: RawBytes,
gas_used: i64,
// new field
events: Cid,
} When the message is finalized, we return the Receipt with the events field populated. Patterns of accessWhile the protocol does not mandate this, clients may wish to cache events in a local database for efficient access. With the structure above, it's possible to access events for a given message or all events for a tipset by returning events from all receipts. Ethereum JSON-RPC compatibilityAt this stage, we do not track logs blooms and we definitely do not track Ethereum formatted blooms (fixed size keccak256 based hashing). The Ethereum JSON-RPC API will need to recreate the bloom filters on demand (or implementations could choose to do something different if they wish to optimise for faster bloom query). |
Draft FIP at filecoin-project/FIPs#483. |
We can consider the technical design phase to have finished, culminating with the FIP draft at filecoin-project/FIPs#483. Closing this issue. |
Context
The Ethereum blockchain has the concept of logs, which are events emitted from smart contracts during execution. Logs contain arbitrary data, and are annotated with zero to four 32-byte topics depending on the opcode used (LOG0..LOG4). The fields from logs (topics, data, emitting address) are added to a 2048-bit bloom filter which is then incorporated to the block header.
The bloom filter is important because it is used by:
eth_getLogs
,eth_getFilterLogs
,eth_getFilterChanges
); either in a streaming or polling fashion. Filter support implies tracking state at the node level.AFAIK logs in Ethereum are not part of the world state, i.e. they are not stored in the state tree (we need to double check this). They are just emitted during execution and consensus is arrived to through the bloom filter, gas used, and other outputs.
Requirements
The EVM compatiblity in Filecoin will need to support Ethereum logs at the protocol level and the JSON-RPC level.
We should avoid overfitting to Ethereum's needs -- this feature should be available to native actors too and should be generally usable and accessible.
Possible design direction
At this stage, we do not plan on introducing modifications to the chain data structures, so populating an aggregation of logs in block headers is a no-go. That leaves us with three options:
GetLogsBloom(height)
to return it. We'd need to add a cron job to prune LogActor entries and limit them to the current finality. Getting the logs would require re-execution and introspection of call parameters through execution traces.Light client operation
In Ethereum, light clients monitor block headers containing event bloom filters to determine whether they want to act on a block.
Since Filecoin does not include the logs blooms in a chain structure, Filecoin light clients would operate by receiving the current bloom in the system actor accompanied by a merkle inclusion proof.
The text was updated successfully, but these errors were encountered: