You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently, go-nitro accepts a chainPk (chain private key) through its CLI entrypoint. This is used to construct an EthChainService which is (in turn) injected into the node constructor.. The EthChainService will bind an internal txSigner variable to that chainPk, so has the ability to sign transactions with that key.
This way, when go-nitro decides it is safe to launch an on-chain transaction, a side effect will be generated by a protocol / objective "crank", routed to the chain service, signed and launched to the blockchain by the chain service.
Problem
Users may not want to trust go-nitro to sign and send transactions with their layer 1 blockchain private key.
Solution
An alternative pattern we could support is having go-nitro prepare a transaction and send on or return to the user to sign and submit.
We would like to be able to preserve the current behaviour, and switch depending on a command line parameter / toml config.
Detail
The existing ChainService interface implies a blend of:
"free" contract calls (no signing required)
transaction preparation / knowledge of smart contract API
It should be optional to set a nonzero chain pk throughout the stack (from rpc, node and ethchainservice). I suggest a nil key should imply "do not send transactions, but return them over the API". Whether we do it that way or with more explicit options / flags, it must be clearly documented.
We should replace the txSigner with a txCaller where appropriate inside the eth chain service. The only place where tx are signed will be within the SendTransaction method.
We use automatically generated Go bindings (using abigen to send transactions). This makes it difficult to split out the transaction preparation from the signing and sending. So we are probably forced to craft the "raw transactions" ourselves and to not lean on the go bindings at all 😬 . Hopefully not too difficult because we can copypasta code from the existing go bindings.
The engine.executeSideEffects function will always call PrepareTransaction, but depending on the config (discussed above), will immediately call SendTransaction (existing behaviour) or route the unsigned transaction back to the user.
"routing the unsigned transaction back to the user" can be achieved as follows:
add a TransactionsToSign field to the EngineEvent struct:
Should go-nitro accept signed transactions so it can send them? Or do we assume the caller can send them (e.g. through metamask).
Proof
We should do a manual integration test between two go-nitro nodes. One can run headless and manage its own chainPk. The other is run headful using the go-nitro GUI, which should be wired up to route transactions to metamask through the browser (like so). If we can open and fund a ledger channel between those two nodes, we will have achieved our aim.
The text was updated successfully, but these errors were encountered:
Instead of rewriting the code which is currently autogenerated by abigen, we could instead pass a different tx.Opts.Signer function. This would encapsulate sending the raw transaction back to the user and having the user return a signed transaction. This would mean go-nitro is still responsible for sending the transaction. This might be a bit messy when it comes to managing concurrency / not blocking
The real advantage is that breaking changes to our solidity code API will flag immediately in the go-nitro codebase as a compiler error.
The alternative is to hand-roll transaction preparation. It's not difficult, and in fact we are already doing something like this when parsing events (of course it has the same downsides #1417).
If the transaction is to be prepared by go-nitro and then signed by the consumer, it is not obvious which party is responsible for setting gas costs and account nonces. If the consumer ultimately is using some wallet like metamask, then metamask will overwrite these values anyway. I think probably go-nitro should leave these fields null / blank for the consumer to fill in.
Context
Currently,
go-nitro
accepts achainPk
(chain private key) through its CLI entrypoint. This is used to construct anEthChainService
which is (in turn) injected into thenode
constructor.. TheEthChainService
will bind an internaltxSigner
variable to thatchainPk
, so has the ability to sign transactions with that key.This way, when
go-nitro
decides it is safe to launch an on-chain transaction, a side effect will be generated by a protocol / objective "crank", routed to the chain service, signed and launched to the blockchain by the chain service.Problem
Users may not want to trust go-nitro to sign and send transactions with their layer 1 blockchain private key.
Solution
An alternative pattern we could support is having go-nitro prepare a transaction and send on or return to the user to sign and submit.
We would like to be able to preserve the current behaviour, and switch depending on a command line parameter / toml config.
Detail
The existing
ChainService
interface implies a blend of:go-nitro/node/engine/chainservice/chainservice.go
Lines 85 to 98 in 2b0bc7c
I propose that will split up the interface to have prepare transaction and send transaction:
Happily, we already have some abstract transaction types which are "without signatures":
go-nitro/protocols/interfaces.go
Lines 29 to 32 in 2b0bc7c
rpc
,node
andethchainservice
). I suggest a nil key should imply "do not send transactions, but return them over the API". Whether we do it that way or with more explicit options / flags, it must be clearly documented.txSigner
with atxCaller
where appropriate inside the eth chain service. The only place where tx are signed will be within theSendTransaction
method.abigen
to send transactions). This makes it difficult to split out the transaction preparation from the signing and sending. So we are probably forced to craft the "raw transactions" ourselves and to not lean on the go bindings at all 😬 . Hopefully not too difficult because we can copypasta code from the existing go bindings.engine.executeSideEffects
function will always callPrepareTransaction
, but depending on the config (discussed above), will immediately callSendTransaction
(existing behaviour) or route the unsigned transaction back to the user.TransactionsToSign
field to theEngineEvent
struct:go-nitro/node/engine/engine.go
Lines 93 to 105 in 2b0bc7c
executeSideEffects
can return anEngineEvent
which should be merged with other events generated inside the engine handler functionsgo-nitro/node/node.go
Line 94 in 2b0bc7c
node.transactionsToSign chan types.Transaction
( a newchan
which needs to be added).go-nitro/rpc/client.go
Line 220 in 8c35780
Unknowns
Should
go-nitro
accept signed transactions so it can send them? Or do we assume the caller can send them (e.g. through metamask).Proof
We should do a manual integration test between two go-nitro nodes. One can run headless and manage its own chainPk. The other is run headful using the go-nitro GUI, which should be wired up to route transactions to metamask through the browser (like so). If we can open and fund a ledger channel between those two nodes, we will have achieved our aim.
The text was updated successfully, but these errors were encountered: