Onchain P-Chain Transaction Generation #74
Replies: 3 comments 4 replies
-
Love the idea. I would be a bit more specific on the type SubnetValidatorUpdate struct {
NodeID ids.NodeID `serialize:"true"`
Start uint64 `serialize:"true"`
End uint64 `serialize:"true"`
Weight uint64 `serialize:"true"`
Signer signer.Signer `serialize:"true"`
Memo []byte `serialize:"true"`
}
type SubnetOperation struct {
SubnetID ids.ID `serialize:"true"`
Nonce uint64 `serialize:"true"`
ValidatorUpdates []SubnetValidatorUpdate `serialize:"true"`
} |
Beta Was this translation helpful? Give feedback.
-
One thing that's missing from the description here is how Bob gets the nonce. On the C-chain, he can always retrieve the nonce by transaction-count. Are we also proposing add an RPC call to get a I'm not sure about all the internals of a P-chain validator, but it might be less of a deviation to use the UTXO-style transaction, but limit the number of inputs to 1 for a |
Beta Was this translation helpful? Give feedback.
-
One issue with using nonces like this is that a relayer cannot submit any of the issued I agree that it is desirable to separate the issuance of the Alternatively, we could transition the P-Chain to a different model where the incentives would be simpler (eg, one time fee paid for storage of data for X time) |
Beta Was this translation helpful? Give feedback.
-
Onchain P-Chain Transaction Generation
In order to implement Subnet Driven Validator Sets as proposed in Discussion 68, we need to activate support for Warp Addressed Transactions on the P-Chain and enable onchain programs to issue P-Chain transactions.
ACP-73 already proposes to enable Warp Addressed Transactions on the P-Chain for any transaction type. In conjunction with ACP-73, we need to ensure that onchain programs can sign P-Chain transaction types. This means that we need to support the entire flow of transaction generation, issuance, and confirmation from an onchain program.
This discussion will walk through different options of how this could be implemented and potential changes to the P-Chain to simplify the transaction issuance flow for onchain programs.
Background
Transaction issuance includes the following components:
Additionally, transactions may fail or stall for a number of reasons (increase in dynamic fees, blocks are full, or an unexpected bug). This means that onchain programs need to be able to reason about failed or stalled transactions and ensure that it can handle re-issuance as needed.
UTXO Model
The UTXO (Unspent Transaction Output) model defines how transactions are structured and verified. In the UTXO model, each transaction output is treated as a separate, spendable entity, similar to a $5 bill. For example, if a user receives 5 AVAX in one transaction and 10 AVAX in another, they would have two UTXOs (5 AVAX and 10 AVAX). You can think of it like a $5 bill and a $10 bill; you can spend them in combination with each other and if you want to use an amount less than their sum, you'll need to make change. If you're spending cash, you'll need a counterparty that can make exact change. For example, if you want to buy a sandwich worth $12, with a $5 and $10 bill, you'll need the counterparty to give you $3 back, which could be made up of any assortment of smaller bills or coins. If you're spending UTXOs in a transaction, you can break up the outputs arbitrarily and the blockchain will verify that you've made change correctly. These leftover funds are typically sent back to an address controlled by the sender and conveniently referred to as a "change output."
The UTXO model has the added benefit of deleting spent UTXOs from the active state, which provides natural garbage collection of no longer useful state.
For the UTXO model tx issuance generally follows the flow:
Account Model
In the account model, users have balances directly tied to their addresses. For example, if Bob has 10 AVAX, it's stored directly on his account address. When creating a transaction, Bob specifies a recipient, amount, and a nonce and signs the transaction using his private key. When the blockchain verifies the transaction, it derives Bob's onchain address from the signature and deducts the required fees and funds for the transaction from the account balance. After the transaction is executed, it updates the account's nonce onchain to provide replay protection. After Bob verifies the transaction has been accepted, he can issue his next transaction with the next nonce.
If Bob wants to send multiple transactions without confirming them one at a time, he can issue a sequence of transactions consuming a corresponding sequence of nonces.
The account model simplifies transaction generation in comparison to the UTXO model since there it removes the need to select and track a UTXO set.
Account Abstraction
Account abstraction is a new, very popular concept for decoupling an account from an individual cryptographic key. There's a wide number of variants and writeups with better descriptions than I could manage, so I'll leave to readers to do their own deep dive on this topic.
At a high level and for the purpsoes of this discussion, account abstraction decoupled an account from a single key and typically provides a way for a modifiable program to handle access control of a specific account.
Account abstraction also frequently includes a separation between the account that authorizes a specific action onchain and authorization to pay for the fees associated with a transaction. For example, account abstraction providers frequently ask users to sign a "metatransaction" and then wrap it with an actual transaction where they will pay the full execution gas cost.
Onchain Transaction Generation
In all of these models, transactions are typically generated, issued, and confirmed, by some offchain entity (wallet, bot, etc.). Sending Warp Addressed Transactions from an onchain program requires moving the entire flow onchain as well and comes with a variety of tradeoffs in each of these models.
UTXO vs. Account Model
Theoretically, the UTXO and account models involve a very similar workflow. Both require specifying an input (UTXOs vs a nonce), specifying the desired operation, issuing/confirming the transaction, and updating the set of available inputs that it tracks.
The UTXO model seems to be more complex to implement purely because it involves tracking many inputs and outputs rather than a single nonce.
This makes adding some version of the account model to the P-Chain very appealing when trying to support simple onchain programs capable of handling the entire flow.
Account Abstraction
Account abstraction is an appealing option, but it was not immediately obvious to me what a simple version of account abstraction might look like on the P-Chain.
Since Warp Addressed Transactions would need to pay for their own gas costs, separating paying for fees from the actual update that should be authorized could help simplify the flow considerably.
By decoupling fee payment from authorization, a Subnet could generate a signature over ONLY the update that it wants to perform. After generating a Warp signature authorizing that update, any Subnet validator or a separate offchain component could handle issuance on the P-Chain.
This is not currently possible to implement on the P-Chain because all signatures are over the full transaction hash as opposed to for an individually authorized operation.
A simpler alternative to this would be to sign a single Subnet operation's hash, which can be included within a wrapper transaction. This way the Subnet only needs to produce, parse, and verify the Subnet operations. The details of the wrapper transaction and the required fee payments that go along with it can be left out completely.
For example, the Subnet operation may look like:
By decoupling fee payment and Subnet updates, the Subnet could generate a signature to authorize the update, which could then be wrapped by any validator or offchain entity. This would reduce the number of types that an onchain program needs to reason about from potentially all P-Chain transaction types to a single general purpose operation.
SubnetUpdate
includes a Memo so that the wrapper transaction can specify where a reward for transaction execution should be deliveredTransaction Issuance
Transaction issuance is relatively straightforward and can be accomplished in a variety of ways with a different set of tradeoffs. The transaction issuance process is unlikely to result in any change in the required onchain behavior, so I'll keep this section short to go through some potential options, which we could choose from and could even be mix and matched if one solutions is preferred over another.
Offchain Relayer
The simplest solution is to add an offchain relayer. Assuming that we use the account abstraction flow, an offchain relayer would package the SubnetOperation into a wrapped transaction that covers the AVAX fee. The offchain relayer would issue the transaction to the P-Chain and handle re-issuance as needed if the fees changed as planned in #69.
Validators
If the Subnet generates a fully formed and signed transaction (with fee payment), the validators could directly issue it to the P-Chain. This could be executed either via an API call to a known endpoint (public API nodes), or it could issue a direct cross-chain request to a P-Chain validator (potentially on a different host).
If taking the account abstraction approach, then the validators would need to manage some AVAX in order to generate and issue the wrapper transction.
Transaction Confirmation
For a Subnet to confirm a transaction, it will need to verify a consensus proof from the P-Chain.
The specification of a consensus proof on top of Snow is out of scope here and will be fully specified in a separate ACP. However, the high level idea is that validators will run Snow consensus and produce a Warp signature over blocks AFTER they have been accepted by Snow. Assuming that Snow holds, this guarantees that correct nodes produce Warp signatures for a block iff the block is accepted by the network. Assuming a threshold of honest nodes, this produces a valid multi-signature that can be verified deterministically (in contrast to Snow in isolation).
In addition, Subnets will need an easy way to verify onchain what Subnet validator set updates were included in a P-Chain block. To make this work, I suggest adding an event root to the P-Chain block format similar to the
ReceiptHash
in Ethereum blocks. The event root will be the root of a merkle trie where the inserted key-value pairs encode the Subnet validator set updates included in the block.I'd suggest the schema for these key-value pairs to follow the format:
When a Subnet client receives a consensus proof, it can then verify all of the relevant validator set updates onchain.
Note: another feature that may be highly requested is to define a "Subnet Staking Request" standard. The goal of such a standard would be to define a standard method for becoming a staker on any chain from any other chain and asking for staking rewards to be sent back to the original source. This should be a separate proposal, but including this note since it may be of significant interest to the teams that are likely to be interested in using onchain P-Chain transaction generation.
Beta Was this translation helpful? Give feedback.
All reactions