-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Introduce a chain agnostic Head interface in the core Transaction Manager #8674
Changes from 57 commits
53a01fd
4422700
8cb32ca
248a535
6b4bcc5
f4a1437
97aadd4
08715d7
7c95323
ba27396
89c5571
cf8bbfe
8166f75
d03175f
bdc3f1a
1e3573c
23d0be7
13928c6
58796ad
eae70df
bea18e1
8471df7
15df148
510ceef
b10e528
a6d24dc
d15caa9
7db5b1d
6249aae
cd72f52
d9ad2d1
a949f0a
ea12d46
1d43f66
0db994d
b49420e
1390b5e
3f3e4dd
f71fb29
88f9231
c4cc209
99fa1ba
f5128e3
db75340
6fa173d
e4a8425
ba9636a
2c65e30
141a81b
08319ac
52593c2
26fc924
efd4350
b4899a2
58faa21
c30d8cb
f1d2594
4c64f50
2bc5c38
2206d7c
0a4c636
654d844
b441836
f6f7f31
cc207bc
1ae15c6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package types | ||
|
||
import "github.com/ethereum/go-ethereum/common" | ||
|
||
// Head provides access to a chain's head, as needed by the TxManager. | ||
// This is a generic interface which ALL chains will implement. | ||
// | ||
//go:generate mockery --quiet --name Head --output ./mocks/ --case=underscore | ||
type Head interface { | ||
// BlockNumber is the head's block number | ||
BlockNumber() int64 | ||
|
||
// ChainLength returns the length of the chain followed by recursively looking up parents | ||
ChainLength() uint32 | ||
|
||
// EarliestInChain traverses through parents until it finds the earliest one | ||
EarliestInChain() Head | ||
|
||
// Hash is the head's block hash | ||
BlockHash() common.Hash | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. now that Head doesn't use generic, how do we specify different hash types for different chains There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I didn't touch the Hash yet in this PR. The current Hash native type(common.Hash) is actually used by Txmgr. So have to see if we can do with a generic, or a common Hash interface. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are other chains just different length arrays? Could we use a byte slice in that case? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can it be an interface with some methods implemented? e.g. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I prefer an interface which allows serializing/deserializing, comparing, stringifying etc. But I don't want to bring that in this PR. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. why not do this change in the PR? seems easier to put everything together and finalize the interface There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just the to and fro we take, for finalizing the approach. Whether to implement Hash as an interface, or byte[], or generic. I want to keep changes isolated more. |
||
|
||
// Parent is the head's parent block | ||
GetParent() Head | ||
|
||
// HashAtHeight returns the hash of the block at the given height, if it is in the chain. | ||
// If not in chain, returns the zero hash | ||
HashAtHeight(blockNum int64) common.Hash | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same question here There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, in a follow-up PR |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package types | ||
|
||
import "context" | ||
|
||
// HeadTrackable is implemented by the core txm, | ||
// to be able to receive head events from any chain. | ||
// Chain implementations should notify head events to the core txm via this interface. | ||
// | ||
//go:generate mockery --quiet --name HeadTrackable --output ./mocks/ --case=underscore | ||
type HeadTrackable[H Head] interface { | ||
OnNewLongestChain(ctx context.Context, head H) | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
package evm | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/smartcontractkit/sqlx" | ||
|
||
evmclient "github.com/smartcontractkit/chainlink/core/chains/evm/client" | ||
evmconfig "github.com/smartcontractkit/chainlink/core/chains/evm/config" | ||
httypes "github.com/smartcontractkit/chainlink/core/chains/evm/headtracker/types" | ||
"github.com/smartcontractkit/chainlink/core/chains/evm/logpoller" | ||
"github.com/smartcontractkit/chainlink/core/chains/evm/txmgr" | ||
evmtypes "github.com/smartcontractkit/chainlink/core/chains/evm/types" | ||
"github.com/smartcontractkit/chainlink/core/logger" | ||
) | ||
|
||
var _ httypes.HeadTrackable = &evmTxm{} | ||
|
||
// evmTxm is an evm wrapper over the generic TxManager interface | ||
type evmTxm struct { | ||
httypes.HeadTrackable | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. is this redundant? TxManager already requires There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the whole There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks a lot Jordan! |
||
txmgr.TxManager | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should be able to use the TxManager struct embedded/anonymous.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @simsonraj I think the above doesn't work because you can't do this
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you cannot initialize evmTxm without creating the type alias GenericTxManager. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. hmm, i think you can directly call on the
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that part is fine. It actually complains on line 53. For more discussion on this topic, see this: https://chainlink-core.slack.com/archives/C03Q4FAGZFC/p1678327210251719 At first, I did what you are suggesting. When it kept failing, I sent this slack thread, and Jordan replied how to make it work. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh thanks for the context, ill check it out There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Another way of fixing without the type alias, but what you have here is good too 👍 , thanks I learned something new :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The failing case is trying to use the package in the field name. Won't it work with just the type? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where are the comments on lines 18 thru 21? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @samsondav , He changed it, it looks good now! |
||
|
||
func (e evmTxm) OnNewLongestChain(ctx context.Context, head *evmtypes.Head) { | ||
e.TxManager.OnNewLongestChain(ctx, head) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure why this is necessary but I believe you that it is. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. I don't know why it doesn't work without this, but if I remove this function, I see these errors: FAIL github.com/smartcontractkit/chainlink/core/chains/evm [build failed] github.com/smartcontractkit/chainlink/core/chains/evm [github.com/smartcontractkit/chainlink/core/chains/evm/client.test]./evm_txm.go:16:31: cannot use &evmTxm{} (value of type *evmTxm) as "github.com/smartcontractkit/chainlink/core/chains/evm/headtracker/types".HeadTrackable value in variable declaration: *evmTxm does not implement "github.com/smartcontractkit/chainlink/core/chains/evm/headtracker/types".HeadTrackable (missing method OnNewLongestChain) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Huh, weird. Could it have been a pointer issue? I'm surprised to see the receiver here is not a pointer. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't understand your question. evmTxm implements both interfaces:
I earlier assumed that in evmTxm, just letting the OnLongestChain method inheriting from TxManager would work, but it doesn't. I have to create above function to pass-through. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From my understanding of go, this shouldn't be necessary. Can we figure out why it's here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This method is not necessary. This is because the type assertion is generic instead of specifying There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Er, the concrete type with the same name is not connected to the generic one. This should be removable if they are derived from one another. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually, this whole type is not necessary: #8744 |
||
|
||
func newEvmTxm( | ||
db *sqlx.DB, | ||
cfg evmconfig.ChainScopedConfig, | ||
client evmclient.Client, | ||
lggr logger.Logger, | ||
logPoller logpoller.LogPoller, | ||
opts ChainSetOpts, | ||
) *evmTxm { | ||
chainID := cfg.ChainID() | ||
var txm txmgr.TxManager | ||
if !cfg.EVMRPCEnabled() { | ||
txm = &txmgr.NullTxManager{ErrMsg: fmt.Sprintf("Ethereum is disabled for chain %d", chainID)} | ||
} else if opts.GenTxManager == nil { | ||
checker := &txmgr.CheckerFactory{Client: client} | ||
txm = txmgr.NewTxm(db, client, cfg, opts.KeyStore, opts.EventBroadcaster, lggr, checker, logPoller) | ||
} else { | ||
txm = opts.GenTxManager(chainID) | ||
} | ||
return &evmTxm{TxManager: txm} | ||
} |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -159,7 +159,7 @@ func (ht *headTracker) Backfill(ctx context.Context, headWithChain *evmtypes.Hea | |
baseHeight = 0 | ||
} | ||
|
||
return ht.backfill(ctx, headWithChain.EarliestInChain(), baseHeight) | ||
return ht.backfill(ctx, headWithChain.EarliestInChain().(*evmtypes.Head), baseHeight) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we going to end up with typecasts everywhere like this now that head is more generic? That seems like a step backwards There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This was due to the fact that EarliestInChain() was already used by evm native code, and also needed for generic Txmgr, so i merged them to a single interface method, that returns interface Head, instead of native head. Changed it now. |
||
} | ||
|
||
func (ht *headTracker) LatestChain() *evmtypes.Head { | ||
|
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.
Is
int64
large enough for all 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.
Can't answer that right now. For EVM, it seems large enough, as it is already hard-coded in our codebase. Thus I didn't change it.
For future families, if they require uint256, we will have to convert it to that, or change this to a big.Int kind of interface.
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.
probably good enough for now - max int64 (assuming the block generation rate of solana 0.4s/block) would last 116e9 years