-
Notifications
You must be signed in to change notification settings - Fork 44
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(gas outputs): Add Height and ActorName #270
Conversation
Gas outputs are very important for many base-fee and gas-usage related views. The table has no height, which means it needs to be joined with blocks all the time on something like state_root to get a timestamp. This is likely innefficient. Additionally, it needs to be joined with actors to get the actor code. Since we are "deriving" and already include redundant info, we might also get this one. This allows easy filtering of messages by actor type and method.
@@ -12,6 +12,7 @@ import ( | |||
|
|||
type GasOutputs struct { | |||
tableName struct{} `pg:"derived_gas_outputs"` //nolint: structcheck,unused | |||
Height int64 `pg:",pk,use_zero,notnull"` |
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.
We will need to backfill the value for this column.
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.
The value corresponds to the height of the message I think (not that of the receipts).
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.
Yes, it's the height of the message. Backfilling is a problem. With the current version it will take some time. With the new in-order processing it takes <1s per tipset, but that's still ~211000 seconds = ~2.4 days unless we shard the processing.
An alternative is to figure out a query that can update this table by joining with messages. That will still be slow to run, several hours at least.
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.
Custom in-order processing that just does messages and just updates this should be faster (?). That said, 2.4 days should be ok.
child, err := node.ChainGetTipSetByHeight(ctx, abi.ChainEpoch(item.Height+1), types.NewTipSetKey()) | ||
if err != nil { | ||
return xerrors.Errorf("Failed to load child tipset: %w", err) | ||
} | ||
|
||
st, err := state.LoadStateTree(node.Store(), child.ParentState()) | ||
if err != nil { | ||
return xerrors.Errorf("load state tree when gas outputs for %s: %w", item.Cid, err) | ||
} | ||
|
||
dstAddr, err := address.NewFromString(item.To) | ||
if err != nil { | ||
return xerrors.Errorf("parse to address failed for gas outputs in %s: %w", item.Cid, err) | ||
} | ||
|
||
var dstActorCode cid.Cid | ||
dstActor, err := st.GetActor(dstAddr) | ||
if err != nil { | ||
if !errors.Is(err, types.ErrActorNotFound) { | ||
return xerrors.Errorf("get destination actor for gas outputs %s failed: %w", item.Cid, err) | ||
} | ||
} else { | ||
dstActorCode = dstActor.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.
I wish there was a better way, but this should be ok if the state is cached at some layer.
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.
#249 is much more efficient but will be a few days before it's ready. Currently checking that the data it produces matches the existing data.
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, still need to support it in the "standard" way which I trust will become way faster with store improvement and block caching at some point.
Can we drop the message size column? Is it useful? |
I haven't used it for anything, but it seems like it could give an interesting metric. |
ALTER TABLE public.derived_gas_outputs ADD COLUMN height bigint; | ||
ALTER TABLE public.derived_gas_outputs ADD COLUMN actor_name text; |
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 believe constraints need to be added for these new columns since neither are null-able, and height
is a primary key.
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.
Do you mean height
should be made primary key along with cid
?
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.
Please have a look to the latest commits because I am not sure I know what I'm doing with the migrations..
// Note: this item will only be processed if there are receipts for | ||
// it, which means there should be a tipset at height+1. This is only | ||
// used to get the destination actor code, so we don't care about side | ||
// chains. |
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.
Perhaps its worth adding a check to ensure child != item
? Alternatively, null rounds can be handled via: https://github.com/filecoin-project/sentinel-visor/pull/214/files#diff-a771f3c826cfe5ebe05c1a003873af47456ee3e16188c1e5d0a1162c0b3e27acR40
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.
Given that I just want to extract the dstActorCode, is it a problem if child == parent? The actor code will be the same even if it comes from a slightly wrong state. But maybe I'm missing something?
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 believe the destination actor may no exist in child
(when child == parent) if this is the first message being sent to the destination actor. But based on the below code maybe that isn't an issue -- We just won't know the designation actor code if the actor is created in a block preceding a null round.
up := batch(` | ||
ALTER TABLE public.derived_gas_outputs ADD COLUMN height bigint NOT NULL; | ||
ALTER TABLE public.derived_gas_outputs ADD COLUMN actor_name text NOT NULL; | ||
ALTER TABLE public.derived_gas_outputs ADD PRIMARY KEY (height); |
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.
✔️
// Note: this item will only be processed if there are receipts for | ||
// it, which means there should be a tipset at height+1. This is only | ||
// used to get the destination actor code, so we don't care about side | ||
// chains. |
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 believe the destination actor may no exist in child
(when child == parent) if this is the first message being sent to the destination actor. But based on the below code maybe that isn't an issue -- We just won't know the designation actor code if the actor is created in a block preceding a null round.
ALTER TABLE public.derived_gas_outputs ADD PRIMARY KEY (cid, height); | ||
`) |
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.
@iand can shall we leave like this, or add state_root too?
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.
let's add state_root - I'll do it
up := batch(` | ||
ALTER TABLE public.derived_gas_outputs ADD COLUMN height bigint NOT NULL; | ||
ALTER TABLE public.derived_gas_outputs ADD COLUMN actor_name text NOT NULL; | ||
ALTER TABLE public.derived_gas_outputs DROP CONSTRAINT derived_gas_outputs_pkey; |
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 also see in other migrations we do _pk
instead of _pkey
, should I change that?
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.
pkey is the convention used by postgres when you create a primary key
Gas outputs are very important for many base-fee and gas-usage related views.
The table has no height, which means it needs to be joined with blocks all the
time on something like state_root to get a timestamp. This is likely
innefficient.
Additionally, it needs to be joined with actors to get the actor code. Since
we are "deriving" and already include redundant info, we might also get this
one. This allows easy filtering of messages by actor type and method.