diff --git a/README.md b/README.md index 0f2a58a04..86e0a726f 100644 --- a/README.md +++ b/README.md @@ -52,11 +52,12 @@ Let’s take a look at how you can request confidential computation through an e 1. Pick your favorite execution node. You’ll need its URL and wallet address. Note that the execution node is fully trusted to provide the result of your confidential computation. -2. Craft your confidential computation request. This is a regular Ethereum transaction, where you specify the desired contract address and its (public) calldata. I’m assuming you have found or deployed a smart contract which you intend to call. Don’t sign the transaction quite yet! +2. Craft your confidential computation record. This is a regular Ethereum transaction (fields are similar to `LegacyTx`), where you specify the desired contract address and its (public) calldata. I’m assuming you have found or deployed a smart contract which you intend to call. Don’t sign the transaction quite yet! ```go allowedPeekers := []common.Address{newBlockBidPeeker, newBundleBidPeeker, buildEthBlockPeeker} // express which contracts should have access to your data (by their addresses) - confidentialComputeRequestInner := &types.LegacyTx{ + confidentialComputeRecord := &types.ConfidentialComputeRecord{ + ExecutionNode: "0x4E2B0c0e428AE1CDE26d5BcF17Ba83f447068E5B", Nonce: suaveAccNonce, To: &newBundleBidAddress, Value: nil, @@ -66,20 +67,20 @@ Let’s take a look at how you can request confidential computation through an e } ``` -3. Wrap your regular transaction into the new `ConfidentialComputeRequest` transaction type, and specify the execution node’s wallet address as the `ExecutionNode` field. Sign the transaction with your wallet. +3. Wrap your compute record into a `ConfidentialComputeRequest` transaction type, and specify the confidential data. ```go + confidentialDataBytes := hexutil.Encode(ethBundle) confidentialComputeRequest := types.SignTx(types.NewTx(&types.ConfidentialComputeRequest{ - ExecutionNode: "0x4E2B0c0e428AE1CDE26d5BcF17Ba83f447068E5B", - Wrapped: *types.NewTx(&confidentialComputeRequestInner), + ConfidentialComputeRecord: confidentialComputeRecord, + ConfidentialInputs: confidentialDataBytes, }), suaveSigner, privKey) ``` -4. Request confidential computation by submitting your transaction along with your confidential data to the execution node you chose via `eth_sendRawTransaction`. +4. Request confidential computation by submitting your transaction to the execution node you chose via `eth_sendRawTransaction`. ```go - confidentialDataBytes := hexutil.Encode(ethBundle) - suaveClient.Call("eth_sendRawTransaction", confidentialComputeRequest, confidentialDataBytes) + suaveClient.Call("eth_sendRawTransaction", confidentialComputeRequest) ``` 5. All done! Once the execution node processes your computation request, the execution node will submit it as `SuaveTransaction` to the mempool. @@ -180,44 +181,69 @@ Other than ability to access new precompiles, the contracts aiming to be execute ### Confidential compute requests -We introduce two new transaction types: `ConfidentialComputeRequest`, serving as a request of confidential computation, and `SuaveTransaction` which is the result of a confidential computation. The new confidential computation transactions track the usage of gas during confidential computation, and contain (or reference) the result of the computation in a chain-friendly manner. +We introduce a few new transaction types. -![image](suave/docs/conf_comp_request_flow.png) +* `ConfidentialComputeRecord` -confidential compute requests (`ConfidentialComputeRequest`) are only intermediary messages between the user requesting confidential computation and the execution node, and are not currently propagated through the mempool or included in blocks. The results of those computations (`SuaveTransaction`) are treated as regular transactions. + This type serves as an onchain record of computation. It's a part of both the [Confidential Compute Request](#confidential-compute-request) and [Suave Transaction](#suave-transaction). -```go -type ConfidentialComputeRequest struct { - ExecutionNode common.Address - Wrapped Transaction -} -``` + ```go + type ConfidentialComputeRecord struct { + ExecutionNode common.Address + ConfidentialInputsHash common.Hash + + // LegacyTx fields + Nonce uint64 + GasPrice *big.Int + Gas uint64 + To *common.Address `rlp:"nil"` + Value *big.Int + Data []byte + + // Signature fields + } + ``` -`SuaveTransaction` transactions are propagated through the mempool and inserted into blocks as expected, unifying confidential computation with regular on-chain execution. +* `ConfidentialComputeRequest` -```go -type SuaveTransaction struct { - ExecutionNode common.Address - ConfidentialComputeRequest Transaction - ConfidentialComputeResult []byte - /* Execution node's signature fields */ -} -``` + This type facilitates users in interacting with the MEVM through the `eth_sendRawTransaction` method. After processing, the request's `ConfidentialComputeRecord` is embedded into `SuaveTransaction.ConfidentialComputeRequest` and serves as an onchain record of computation. -The confidential computation result is placed in the `ConfidentialComputeResult` field, which is further used instead of the original transaction's calldata for on-chain execution. + ```go + type ConfidentialComputeRequest struct { + ConfidentialComputeRecord + ConfidentialInputs []byte + } + ``` -The basic flow is as follows: +* `SuaveTransaction` -1. User crafts a usual legacy/dynamic transaction, which calls the contract of their liking -2. User crafts the confidential computation request (`ConfidentialComputeRequest`): - 1. User choses an execution node of their liking, that is an address whose signature over the confidential computation result will be trusted - 2. User embeds the transaction from (1.) into an `ConfidentialComputeRequest` together with the desired execution node's address - 3. User signs and sends the confidential computation request to an execution node via `eth_sendRawTransaction` (possibly passing in additional confidential data) -3. The execution node executes the transaction in the confidential mode, providing access to the usual confidential APIs -4. The execution node creates a `SuaveTransaction` using the confidential computation request and the result of its execution, the node then signs and submits the transaction into the mempool -5. The transaction makes its way into a block, by executing the `ConfidentialComputeResult` as calldata, as long as the execution node's signature matches the requested executor node in (2.1.) + A specialized transaction type that encapsulates the result of a confidential computation request. It includes the `ConfidentialComputeRequest`, signed by the user, which ensures that the result comes from the expected computor, as the `SuaveTransaction`'s signer must match the `ExecutionNode`. + + ```go + type SuaveTransaction struct { + ExecutionNode common.Address + ConfidentialComputeRequest ConfidentialComputeRecord + ConfidentialComputeResult []byte + /* Execution node's signature fields */ + } + ``` + +![image](suave/docs/conf_comp_request_flow.png) + + +The basic flow is as follows: -The user passes in any confidential data through the new `confidential_data` parameter of the `eth_sendRawTransaction` RPC method. The initial confidential computation has access to both the public and confidential data, but only the public data becomes part of the transaction propagated through the mempool. Any confidential data passed in by the user is discarded after the execution. +1. User crafts a confidential computation request (`ConfidentialComputeRequest`): + 1. Sets their GasPrice, GasLimit, To address and calldata as they would for a `LegacyTx` + 2. Choses an execution node of their liking, that is an address whose signature over the confidential computation result will be trusted + 3. The above becomes the `ConfidentialComputeRecord` that will eventually make its way onto the chain + 4. Sets the `ConfidentialInputs` of the request (if any) + 5. Signs and sends the confidential computation request (consisting of (3 and 4) to an execution node via `eth_sendRawTransaction` +2. The execution node executes the transaction in the confidential mode, providing access to the usual confidential APIs +3. The execution node creates a `SuaveTransaction` using the confidential computation request and the result of its execution, the node then signs and submits the transaction into the mempool +4. The transaction makes its way into a block, by executing the `ConfidentialComputeResult` as calldata, as long as the execution node's signature matches the requested executor node in (1.2.) + +The initial confidential computation has access to both the public and confidential data, but only the public data becomes part of the transaction propagated through the mempool. Any confidential data passed in by the user is discarded after the execution. Architecture reference ![image](suave/docs/execution_node_architecture.png) diff --git a/core/types/confidential.go b/core/types/confidential.go index 5a68de0db..1f38945d5 100644 --- a/core/types/confidential.go +++ b/core/types/confidential.go @@ -6,7 +6,7 @@ import ( "github.com/ethereum/go-ethereum/common" ) -type ConfidentialComputeRequest struct { +type ConfidentialComputeRecord struct { Nonce uint64 GasPrice *big.Int Gas uint64 @@ -14,20 +14,22 @@ type ConfidentialComputeRequest struct { Value *big.Int Data []byte - ExecutionNode common.Address + ExecutionNode common.Address + ConfidentialInputsHash common.Hash ChainID *big.Int V, R, S *big.Int } // copy creates a deep copy of the transaction data and initializes all fields. -func (tx *ConfidentialComputeRequest) copy() TxData { - cpy := &ConfidentialComputeRequest{ - Nonce: tx.Nonce, - To: copyAddressPtr(tx.To), - Data: common.CopyBytes(tx.Data), - Gas: tx.Gas, - ExecutionNode: tx.ExecutionNode, +func (tx *ConfidentialComputeRecord) copy() TxData { + cpy := &ConfidentialComputeRecord{ + Nonce: tx.Nonce, + To: copyAddressPtr(tx.To), + Data: common.CopyBytes(tx.Data), + Gas: tx.Gas, + ExecutionNode: tx.ExecutionNode, + ConfidentialInputsHash: tx.ConfidentialInputsHash, Value: new(big.Int), GasPrice: new(big.Int), @@ -60,6 +62,48 @@ func (tx *ConfidentialComputeRequest) copy() TxData { return cpy } +func (tx *ConfidentialComputeRecord) txType() byte { return ConfidentialComputeRecordTxType } +func (tx *ConfidentialComputeRecord) chainID() *big.Int { return tx.ChainID } +func (tx *ConfidentialComputeRecord) accessList() AccessList { return nil } +func (tx *ConfidentialComputeRecord) data() []byte { return tx.Data } +func (tx *ConfidentialComputeRecord) gas() uint64 { return tx.Gas } +func (tx *ConfidentialComputeRecord) gasPrice() *big.Int { return tx.GasPrice } +func (tx *ConfidentialComputeRecord) gasTipCap() *big.Int { return tx.GasPrice } +func (tx *ConfidentialComputeRecord) gasFeeCap() *big.Int { return tx.GasPrice } +func (tx *ConfidentialComputeRecord) value() *big.Int { return tx.Value } +func (tx *ConfidentialComputeRecord) nonce() uint64 { return tx.Nonce } +func (tx *ConfidentialComputeRecord) to() *common.Address { return tx.To } +func (tx *ConfidentialComputeRecord) blobGas() uint64 { return 0 } +func (tx *ConfidentialComputeRecord) blobGasFeeCap() *big.Int { return nil } +func (tx *ConfidentialComputeRecord) blobHashes() []common.Hash { return nil } + +func (tx *ConfidentialComputeRecord) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { + return dst.Set(tx.GasPrice) +} + +func (tx *ConfidentialComputeRecord) rawSignatureValues() (v, r, s *big.Int) { + return tx.V, tx.R, tx.S +} + +func (tx *ConfidentialComputeRecord) setSignatureValues(chainID, v, r, s *big.Int) { + tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s +} + +type ConfidentialComputeRequest struct { + ConfidentialComputeRecord + ConfidentialInputs []byte +} + +// copy creates a deep copy of the transaction data and initializes all fields. +func (tx *ConfidentialComputeRequest) copy() TxData { + cpy := &ConfidentialComputeRequest{ + ConfidentialComputeRecord: *(tx.ConfidentialComputeRecord.copy().(*ConfidentialComputeRecord)), + ConfidentialInputs: tx.ConfidentialInputs, + } + + return cpy +} + func (tx *ConfidentialComputeRequest) txType() byte { return ConfidentialComputeRequestTxType } func (tx *ConfidentialComputeRequest) chainID() *big.Int { return tx.ChainID } func (tx *ConfidentialComputeRequest) accessList() AccessList { return nil } @@ -88,9 +132,9 @@ func (tx *ConfidentialComputeRequest) setSignatureValues(chainID, v, r, s *big.I } type SuaveTransaction struct { - ExecutionNode common.Address `json:"executionNode" gencodec:"required"` - ConfidentialComputeRequest Transaction `json:"confidentialComputeRequest" gencodec:"required"` - ConfidentialComputeResult []byte `json:"confidentialComputeResult" gencodec:"required"` + ExecutionNode common.Address `json:"executionNode" gencodec:"required"` + ConfidentialComputeRequest ConfidentialComputeRecord `json:"confidentialComputeRequest" gencodec:"required"` + ConfidentialComputeResult []byte `json:"confidentialComputeResult" gencodec:"required"` // ExecutionNode's signature ChainID *big.Int @@ -103,7 +147,7 @@ type SuaveTransaction struct { func (tx *SuaveTransaction) copy() TxData { cpy := &SuaveTransaction{ ExecutionNode: tx.ExecutionNode, - ConfidentialComputeRequest: *NewTx(tx.ConfidentialComputeRequest.inner), + ConfidentialComputeRequest: tx.ConfidentialComputeRequest, ConfidentialComputeResult: common.CopyBytes(tx.ConfidentialComputeResult), ChainID: new(big.Int), V: new(big.Int), @@ -140,31 +184,31 @@ func (tx *SuaveTransaction) data() []byte { // Rest is carried over from wrapped tx func (tx *SuaveTransaction) chainID() *big.Int { return tx.ChainID } func (tx *SuaveTransaction) accessList() AccessList { - return tx.ConfidentialComputeRequest.inner.accessList() + return tx.ConfidentialComputeRequest.accessList() } -func (tx *SuaveTransaction) gas() uint64 { return tx.ConfidentialComputeRequest.inner.gas() } +func (tx *SuaveTransaction) gas() uint64 { return tx.ConfidentialComputeRequest.gas() } func (tx *SuaveTransaction) gasFeeCap() *big.Int { - return tx.ConfidentialComputeRequest.inner.gasFeeCap() + return tx.ConfidentialComputeRequest.gasFeeCap() } func (tx *SuaveTransaction) gasTipCap() *big.Int { - return tx.ConfidentialComputeRequest.inner.gasTipCap() + return tx.ConfidentialComputeRequest.gasTipCap() } func (tx *SuaveTransaction) gasPrice() *big.Int { - return tx.ConfidentialComputeRequest.inner.gasFeeCap() + return tx.ConfidentialComputeRequest.gasFeeCap() } -func (tx *SuaveTransaction) value() *big.Int { return tx.ConfidentialComputeRequest.inner.value() } -func (tx *SuaveTransaction) nonce() uint64 { return tx.ConfidentialComputeRequest.inner.nonce() } -func (tx *SuaveTransaction) to() *common.Address { return tx.ConfidentialComputeRequest.inner.to() } -func (tx *SuaveTransaction) blobGas() uint64 { return tx.ConfidentialComputeRequest.inner.blobGas() } +func (tx *SuaveTransaction) value() *big.Int { return tx.ConfidentialComputeRequest.value() } +func (tx *SuaveTransaction) nonce() uint64 { return tx.ConfidentialComputeRequest.nonce() } +func (tx *SuaveTransaction) to() *common.Address { return tx.ConfidentialComputeRequest.to() } +func (tx *SuaveTransaction) blobGas() uint64 { return tx.ConfidentialComputeRequest.blobGas() } func (tx *SuaveTransaction) blobGasFeeCap() *big.Int { - return tx.ConfidentialComputeRequest.inner.blobGasFeeCap() + return tx.ConfidentialComputeRequest.blobGasFeeCap() } func (tx *SuaveTransaction) blobHashes() []common.Hash { - return tx.ConfidentialComputeRequest.inner.blobHashes() + return tx.ConfidentialComputeRequest.blobHashes() } func (tx *SuaveTransaction) effectiveGasPrice(dst *big.Int, baseFee *big.Int) *big.Int { - return tx.ConfidentialComputeRequest.inner.effectiveGasPrice(dst, baseFee) + return tx.ConfidentialComputeRequest.effectiveGasPrice(dst, baseFee) } func (tx *SuaveTransaction) rawSignatureValues() (v, r, s *big.Int) { diff --git a/core/types/confidential_test.go b/core/types/confidential_test.go index 131d37e0f..b756e9f25 100644 --- a/core/types/confidential_test.go +++ b/core/types/confidential_test.go @@ -8,6 +8,45 @@ import ( "github.com/stretchr/testify/require" ) +func TestCCRequestToRecord(t *testing.T) { + testKey, err := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") + require.NoError(t, err) + + signer := NewSuaveSigner(new(big.Int)) + unsignedTx := NewTx(&ConfidentialComputeRequest{ + ConfidentialComputeRecord: ConfidentialComputeRecord{ + ExecutionNode: crypto.PubkeyToAddress(testKey.PublicKey), + }, + ConfidentialInputs: []byte{0x46}, + }) + signedTx, err := SignTx(unsignedTx, signer, testKey) + require.NoError(t, err) + + recoveredSender, err := signer.Sender(signedTx) + require.NoError(t, err) + + require.Equal(t, crypto.PubkeyToAddress(testKey.PublicKey), recoveredSender) + + marshalledTxBytes, err := signedTx.MarshalBinary() + require.NoError(t, err) + + unmarshalledTx := new(Transaction) + require.NoError(t, unmarshalledTx.UnmarshalBinary(marshalledTxBytes)) + + recoveredUnmarshalledSender, err := signer.Sender(unmarshalledTx) + require.NoError(t, err) + + require.Equal(t, crypto.PubkeyToAddress(testKey.PublicKey), recoveredUnmarshalledSender) + + signedRequestInner, ok := CastTxInner[*ConfidentialComputeRequest](unmarshalledTx) + require.True(t, ok) + + recoveredRecordSender, err := signer.Sender(NewTx(&signedRequestInner.ConfidentialComputeRecord)) + require.NoError(t, err) + + require.Equal(t, crypto.PubkeyToAddress(testKey.PublicKey), recoveredRecordSender) +} + func TestCCR(t *testing.T) { testKey, err := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") require.NoError(t, err) @@ -40,14 +79,17 @@ func TestSuaveTx(t *testing.T) { signer := NewSuaveSigner(new(big.Int)) - signedCCR, err := SignTx(NewTx(&ConfidentialComputeRequest{ + signedCCR, err := SignTx(NewTx(&ConfidentialComputeRecord{ ExecutionNode: crypto.PubkeyToAddress(testKey.PublicKey), }), signer, testKey) require.NoError(t, err) + signedInnerCCR, ok := CastTxInner[*ConfidentialComputeRecord](signedCCR) + require.True(t, ok) + unsignedTx := NewTx(&SuaveTransaction{ ExecutionNode: crypto.PubkeyToAddress(testKey.PublicKey), - ConfidentialComputeRequest: *signedCCR, + ConfidentialComputeRequest: *signedInnerCCR, }) signedTx, err := SignTx(unsignedTx, signer, testKey) require.NoError(t, err) diff --git a/core/types/transaction.go b/core/types/transaction.go index 85051fb14..98e85968c 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -46,8 +46,9 @@ const ( AccessListTxType = 0x01 DynamicFeeTxType = 0x02 BlobTxType = 0x03 - ConfidentialComputeRequestTxType = 0x42 - SuaveTxType = 0x43 + ConfidentialComputeRecordTxType = 0x42 + ConfidentialComputeRequestTxType = 0x43 + SuaveTxType = 0x50 ) // Transaction is an Ethereum transaction. diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 2aa05fbf2..20c41e697 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -43,7 +43,8 @@ type txJSON struct { AccessList *AccessList `json:"accessList,omitempty"` BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` ExecutionNode *common.Address `json:"executionNode,omitempty"` - ConfidentialInputsHash common.Hash `json:"confidentialInputsHash,omitempty"` + ConfidentialInputsHash *common.Hash `json:"confidentialInputsHash,omitempty"` + ConfidentialInputs *hexutil.Bytes `json:"confidentialInputs,omitempty"` Wrapped *json.RawMessage `json:"wrapped,omitempty"` ConfidentialComputeResult *hexutil.Bytes `json:"confidentialComputeResult,omitempty"` V *hexutil.Big `json:"v"` @@ -117,8 +118,24 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { enc.R = (*hexutil.Big)(itx.R.ToBig()) enc.S = (*hexutil.Big)(itx.S.ToBig()) + case *ConfidentialComputeRecord: + enc.ExecutionNode = &itx.ExecutionNode + enc.ConfidentialInputsHash = &itx.ConfidentialInputsHash + enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) + enc.To = tx.To() + enc.Gas = (*hexutil.Uint64)(&itx.Gas) + enc.GasPrice = (*hexutil.Big)(itx.GasPrice) + enc.Value = (*hexutil.Big)(itx.Value) + enc.Input = (*hexutil.Bytes)(&itx.Data) + enc.ChainID = (*hexutil.Big)(itx.ChainID) + enc.V = (*hexutil.Big)(itx.V) + enc.R = (*hexutil.Big)(itx.R) + enc.S = (*hexutil.Big)(itx.S) + case *ConfidentialComputeRequest: enc.ExecutionNode = &itx.ExecutionNode + enc.ConfidentialInputs = (*hexutil.Bytes)(&itx.ConfidentialInputs) + enc.ConfidentialInputsHash = &itx.ConfidentialInputsHash enc.Nonce = (*hexutil.Uint64)(&itx.Nonce) enc.To = tx.To() enc.Gas = (*hexutil.Uint64)(&itx.Gas) @@ -133,7 +150,7 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { case *SuaveTransaction: enc.ExecutionNode = &itx.ExecutionNode - wrapped, err := itx.ConfidentialComputeRequest.MarshalJSON() + wrapped, err := NewTx(&itx.ConfidentialComputeRequest).MarshalJSON() if err != nil { return nil, err } @@ -380,6 +397,65 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { } } + case ConfidentialComputeRecordTxType: + var itx ConfidentialComputeRequest + inner = &itx + + if dec.ExecutionNode == nil { + return errors.New("missing required field 'executionNode' in transaction") + } + itx.ExecutionNode = *dec.ExecutionNode + + if dec.ConfidentialInputsHash != nil { + itx.ConfidentialInputsHash = *dec.ConfidentialInputsHash + } + + if dec.Nonce == nil { + return errors.New("missing required field 'nonce' in transaction") + } + itx.Nonce = uint64(*dec.Nonce) + if dec.To != nil { + itx.To = dec.To + } + if dec.Gas == nil { + return errors.New("missing required field 'gas' in transaction") + } + itx.Gas = uint64(*dec.Gas) + if dec.GasPrice == nil { + return errors.New("missing required field 'gasPrice' in transaction") + } + itx.GasPrice = (*big.Int)(dec.GasPrice) + if dec.Value == nil { + return errors.New("missing required field 'value' in transaction") + } + itx.Value = (*big.Int)(dec.Value) + if dec.Input == nil { + return errors.New("missing required field 'input' in transaction") + } + itx.Data = *dec.Input + if dec.ChainID == nil { + return errors.New("missing required field 'chainId' in transaction") + } + itx.ChainID = (*big.Int)(dec.ChainID) + if dec.V == nil { + return errors.New("missing required field 'r' in transaction") + } + itx.V = (*big.Int)(dec.V) + if dec.R == nil { + return errors.New("missing required field 'r' in transaction") + } + itx.R = (*big.Int)(dec.R) + if dec.S == nil { + return errors.New("missing required field 's' in transaction") + } + itx.S = (*big.Int)(dec.S) + withSignature := itx.V.Sign() != 0 || itx.R.Sign() != 0 || itx.S.Sign() != 0 + if withSignature { + if err := sanityCheckSignature(itx.V, itx.R, itx.S, false); err != nil { + return err + } + } + case ConfidentialComputeRequestTxType: var itx ConfidentialComputeRequest inner = &itx @@ -389,6 +465,14 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { } itx.ExecutionNode = *dec.ExecutionNode + if dec.ConfidentialInputsHash != nil { + itx.ConfidentialInputsHash = *dec.ConfidentialInputsHash + } + + if dec.ConfidentialInputs != nil { + itx.ConfidentialInputs = *dec.ConfidentialInputs + } + if dec.Nonce == nil { return errors.New("missing required field 'nonce' in transaction") } @@ -455,7 +539,11 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return err } - itx.ConfidentialComputeRequest = wrappedTx + ccr, ok := CastTxInner[*ConfidentialComputeRecord](&wrappedTx) + if !ok { + return errors.New("wrapped tx not a ConfidentialComputeRecord") + } + itx.ConfidentialComputeRequest = *ccr if dec.ConfidentialComputeResult != nil { itx.ConfidentialComputeResult = ([]byte)(*dec.ConfidentialComputeResult) diff --git a/core/types/transaction_signing.go b/core/types/transaction_signing.go index 58015d97a..9386eed9c 100644 --- a/core/types/transaction_signing.go +++ b/core/types/transaction_signing.go @@ -102,6 +102,15 @@ func LatestSignerForChainID(chainID *big.Int) Signer { // SignTx signs the transaction using the given signer and private key. func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, error) { + if tx.Type() == ConfidentialComputeRequestTxType { + inner, ok := CastTxInner[*ConfidentialComputeRequest](tx) + if !ok { + return nil, errors.New("incorrect inner cast!") + } + inner.ConfidentialInputsHash = crypto.Keccak256Hash(inner.ConfidentialInputs) + tx = NewTx(inner) + } + h := s.Hash(tx) sig, err := crypto.Sign(h[:], prv) if err != nil { @@ -113,12 +122,7 @@ func SignTx(tx *Transaction, s Signer, prv *ecdsa.PrivateKey) (*Transaction, err // SignNewTx creates a transaction and signs it. func SignNewTx(prv *ecdsa.PrivateKey, s Signer, txdata TxData) (*Transaction, error) { tx := NewTx(txdata) - h := s.Hash(tx) - sig, err := crypto.Sign(h[:], prv) - if err != nil { - return nil, err - } - return tx.WithSignature(s, sig) + return SignTx(tx, s, prv) } // MustSignNewTx creates a transaction and signs it. @@ -264,14 +268,10 @@ func NewSuaveSigner(chainId *big.Int) Signer { // For confidential transaction, sender refers to the sender of the original transaction func (s suaveSigner) Sender(tx *Transaction) (common.Address, error) { - if tx.Type() != ConfidentialComputeRequestTxType && tx.Type() != SuaveTxType { - return s.londonSigner.Sender(tx) - } - - var ccr *Transaction = tx - if tx.Type() == SuaveTxType { // Verify ExecutionNode's signature - inner := tx.inner.(*SuaveTransaction) - ccr = &inner.ConfidentialComputeRequest + var ccr *ConfidentialComputeRecord + switch txdata := tx.inner.(type) { + case *SuaveTransaction: + ccr = &txdata.ConfidentialComputeRequest V, R, S := tx.RawSignatureValues() // DynamicFee txs are defined to use 0 and 1 as their recovery @@ -285,20 +285,31 @@ func (s suaveSigner) Sender(tx *Transaction) (common.Address, error) { return common.Address{}, err } - if recovered != inner.ExecutionNode { - return common.Address{}, fmt.Errorf("compute request %s signed by incorrect execution node %s, expected %s", tx.Hash().Hex(), recovered.Hex(), inner.ExecutionNode.Hex()) + if recovered != txdata.ExecutionNode { + return common.Address{}, fmt.Errorf("compute request %s signed by incorrect execution node %s, expected %s", tx.Hash().Hex(), recovered.Hex(), txdata.ExecutionNode.Hex()) + } + case *ConfidentialComputeRequest: + ccr = &txdata.ConfidentialComputeRecord + + if txdata.ConfidentialInputsHash != crypto.Keccak256Hash(txdata.ConfidentialInputs) { + return common.Address{}, errors.New("confidential inputs hash mismatch") } + case *ConfidentialComputeRecord: + ccr = txdata + default: + return s.londonSigner.Sender(tx) } - { // Verify wrapped tx's signature - V, R, S := ccr.RawSignatureValues() + { // Verify record tx's signature + ccrTx := NewTx(ccr) + V, R, S := ccrTx.RawSignatureValues() // DynamicFee txs are defined to use 0 and 1 as their recovery // id, add 27 to become equivalent to unprotected Homestead signatures. V = new(big.Int).Add(V, big.NewInt(27)) - if ccr.ChainId().Cmp(s.chainId) != 0 { - return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, ccr.ChainId(), s.chainId) + if ccrTx.ChainId().Cmp(s.chainId) != 0 { + return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, ccrTx.ChainId(), s.chainId) } - return recoverPlain(s.Hash(ccr), R, S, V, true) + return recoverPlain(s.Hash(ccrTx), R, S, V, true) } } @@ -309,14 +320,21 @@ func (s suaveSigner) Equal(s2 Signer) bool { func (s suaveSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) { switch txdata := tx.inner.(type) { - case *ConfidentialComputeRequest: + case *SuaveTransaction: if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 { return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) } R, S, _ = decodeSignature(sig) V = big.NewInt(int64(sig[64])) return R, S, V, nil - case *SuaveTransaction: + case *ConfidentialComputeRecord: + if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 { + return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) + } + R, S, _ = decodeSignature(sig) + V = big.NewInt(int64(sig[64])) + return R, S, V, nil + case *ConfidentialComputeRequest: if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 { return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId) } @@ -332,11 +350,20 @@ func (s suaveSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big. // It does not uniquely identify the transaction. func (s suaveSigner) Hash(tx *Transaction) common.Hash { switch txdata := tx.inner.(type) { - case *ConfidentialComputeRequest: + case *SuaveTransaction: return prefixedRlpHash( tx.Type(), []interface{}{ txdata.ExecutionNode, + s.Hash(NewTx(&txdata.ConfidentialComputeRequest)), + txdata.ConfidentialComputeResult, + }) + case *ConfidentialComputeRequest: + return prefixedRlpHash( + ConfidentialComputeRecordTxType, // Note: this is the same as the Record so that hashes match! + []interface{}{ + txdata.ExecutionNode, + txdata.ConfidentialInputsHash, tx.Nonce(), tx.GasPrice(), tx.Gas(), @@ -344,13 +371,18 @@ func (s suaveSigner) Hash(tx *Transaction) common.Hash { tx.Value(), tx.Data(), }) - case *SuaveTransaction: + case *ConfidentialComputeRecord: return prefixedRlpHash( tx.Type(), []interface{}{ txdata.ExecutionNode, - s.Hash(&txdata.ConfidentialComputeRequest), - txdata.ConfidentialComputeResult, + txdata.ConfidentialInputsHash, + tx.Nonce(), + tx.GasPrice(), + tx.Gas(), + tx.To(), + tx.Value(), + tx.Data(), }) default: return s.londonSigner.Hash(tx) diff --git a/core/vm/contracts_suave_test.go b/core/vm/contracts_suave_test.go index ac6675971..4aa863568 100644 --- a/core/vm/contracts_suave_test.go +++ b/core/vm/contracts_suave_test.go @@ -68,7 +68,9 @@ func newTextContext(t *testing.T) *SuaveContext { t.Cleanup(func() { confEngine.Stop() }) reqTx := types.NewTx(&types.ConfidentialComputeRequest{ - ExecutionNode: common.Address{}, + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: common.Address{}, + }, }) return &SuaveContext{ @@ -110,7 +112,8 @@ func TestSuave_BidWorkflow(t *testing.T) { for _, c := range cases { bids, err := fetchBids.Do(suaveContext, c.cond, c.namespace) require.NoError(t, err) - require.Equal(t, c.bids, bids) + + require.ElementsMatch(t, c.bids, bids) } } diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 4f4b5b77e..46065f8a3 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1048,12 +1048,7 @@ func DoCall(ctx context.Context, b Backend, args TransactionArgs, blockNrOrHash SkipAccountChecks: true, } - var confidentialInputs []byte - if args.ConfidentialInputs != nil { - confidentialInputs = []byte(*args.ConfidentialInputs) - } - - _, result, finalize, err := runMEVM(ctx, b, state, header, tx, msg, confidentialInputs) + _, result, finalize, err := runMEVM(ctx, b, state, header, tx, msg) if err := finalize(); err != suave.ErrUnsignedFinalize { return nil, err } @@ -1374,6 +1369,7 @@ type RPCTransaction struct { ChainID *hexutil.Big `json:"chainId,omitempty"` ExecutionNode *common.Address `json:"executionNode,omitempty"` ConfidentialInputsHash *common.Hash `json:"confidentialInputsHash,omitempty"` + ConfidentialInputs *hexutil.Bytes `json:"confidentialInputs,omitempty"` RequestRecord *json.RawMessage `json:"requestRecord,omitempty"` ConfidentialComputeResult *hexutil.Bytes `json:"confidentialComputeResult,omitempty"` V *hexutil.Big `json:"v"` @@ -1431,6 +1427,21 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber } else { result.GasPrice = (*hexutil.Big)(tx.GasFeeCap()) } + case types.ConfidentialComputeRecordTxType: + inner, ok := types.CastTxInner[*types.ConfidentialComputeRequest](tx) + if !ok { + log.Error("could not marshal rpc transaction: tx did not cast correctly") + return nil + } + + result.ExecutionNode = &inner.ExecutionNode + + // if a legacy transaction has an EIP-155 chain id, include it explicitly + if id := tx.ChainId(); id.Sign() != 0 { + result.ChainID = (*hexutil.Big)(id) + } + result.ConfidentialInputsHash = &inner.ConfidentialInputsHash + result.ChainID = (*hexutil.Big)(tx.ChainId()) case types.ConfidentialComputeRequestTxType: inner, ok := types.CastTxInner[*types.ConfidentialComputeRequest](tx) if !ok { @@ -1444,6 +1455,9 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber if id := tx.ChainId(); id.Sign() != 0 { result.ChainID = (*hexutil.Big)(id) } + result.ConfidentialInputs = (*hexutil.Bytes)(&inner.ConfidentialInputs) + result.ConfidentialInputsHash = &inner.ConfidentialInputsHash + result.ChainID = (*hexutil.Big)(tx.ChainId()) case types.SuaveTxType: inner, ok := types.CastTxInner[*types.SuaveTransaction](tx) if !ok { @@ -1454,7 +1468,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber result.ExecutionNode = &inner.ExecutionNode // TODO: should be rpc marshaled - rrBytes, err := inner.ConfidentialComputeRequest.MarshalJSON() + rrBytes, err := types.NewTx(&inner.ConfidentialComputeRequest).MarshalJSON() if err != nil { log.Error("could not marshal rpc transaction", "err", err) return nil @@ -1862,12 +1876,7 @@ func (s *TransactionAPI) SendTransaction(ctx context.Context, args TransactionAr return common.Hash{}, err } - var confidentialInputs []byte - if confidential != nil { - confidentialInputs = []byte(*confidential) - } - - ntx, _, finalize, err := runMEVM(ctx, s.b, state, header, signed, msg, confidentialInputs) + ntx, _, finalize, err := runMEVM(ctx, s.b, state, header, signed, msg) if err != nil { return common.Hash{}, err } @@ -1900,13 +1909,13 @@ func (s *TransactionAPI) FillTransaction(ctx context.Context, args TransactionAr // SendRawTransaction will add the signed transaction to the transaction pool. // The sender is responsible for signing the transaction and using the correct nonce. -func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes, confidential *hexutil.Bytes) (common.Hash, error) { +func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.Bytes) (common.Hash, error) { tx := new(types.Transaction) if err := tx.UnmarshalBinary(input); err != nil { return common.Hash{}, err } - if tx.Type() == types.ConfidentialComputeRequestTxType { + if _, ok := types.CastTxInner[*types.ConfidentialComputeRequest](tx); ok { state, header, err := s.b.StateAndHeaderByNumber(ctx, rpc.LatestBlockNumber) if state == nil || err != nil { return common.Hash{}, err @@ -1917,12 +1926,7 @@ func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.B return common.Hash{}, err } - var confidentialInputs []byte - if confidential != nil { - confidentialInputs = []byte(*confidential) - } - - ntx, _, finalize, err := runMEVM(ctx, s.b, state, header, tx, msg, confidentialInputs) + ntx, _, finalize, err := runMEVM(ctx, s.b, state, header, tx, msg) if err != nil { return tx.Hash(), err } @@ -1937,7 +1941,7 @@ func (s *TransactionAPI) SendRawTransaction(ctx context.Context, input hexutil.B } // TODO: should be its own api -func runMEVM(ctx context.Context, b Backend, state *state.StateDB, header *types.Header, tx *types.Transaction, msg *core.Message, confidentialInputs []byte) (*types.Transaction, *core.ExecutionResult, func() error, error) { +func runMEVM(ctx context.Context, b Backend, state *state.StateDB, header *types.Header, tx *types.Transaction, msg *core.Message) (*types.Transaction, *core.ExecutionResult, func() error, error) { var cancel context.CancelFunc ctx, cancel = context.WithCancel(ctx) defer cancel() @@ -1959,7 +1963,7 @@ func runMEVM(ctx context.Context, b Backend, state *state.StateDB, header *types suaveCtx := vm.SuaveContext{ ConfidentialComputeRequestTx: tx, - ConfidentialInputs: confidentialInputs, + ConfidentialInputs: confidentialRequestTx.ConfidentialInputs, } evm, storeFinalize, vmError := b.GetMEVM(ctx, msg, state, header, &vm.Config{IsConfidential: true}, &blockCtx, &suaveCtx) @@ -1981,7 +1985,7 @@ func runMEVM(ctx context.Context, b Backend, state *state.StateDB, header *types return nil, nil, nil, fmt.Errorf("execution aborted") } if err != nil { - return tx, nil, nil, fmt.Errorf("err: %w (supplied gas %d)", err, msg.GasLimit) + return nil, nil, nil, fmt.Errorf("err: %w (supplied gas %d)", err, msg.GasLimit) } if err := vmError(); err != nil { return nil, nil, nil, err @@ -2003,7 +2007,7 @@ func runMEVM(ctx context.Context, b Backend, state *state.StateDB, header *types computeResult = result.ReturnData // Or should it be nil maybe in this case? } - suaveResultTxData := &types.SuaveTransaction{ExecutionNode: confidentialRequestTx.ExecutionNode, ConfidentialComputeRequest: *tx, ConfidentialComputeResult: computeResult} + suaveResultTxData := &types.SuaveTransaction{ExecutionNode: confidentialRequestTx.ExecutionNode, ConfidentialComputeRequest: confidentialRequestTx.ConfidentialComputeRecord, ConfidentialComputeResult: computeResult} signed, err := wallet.SignTx(account, types.NewTx(suaveResultTxData), tx.ChainId()) if err != nil { diff --git a/internal/ethapi/transaction_args.go b/internal/ethapi/transaction_args.go index 3e4b576f5..4de8bfe30 100644 --- a/internal/ethapi/transaction_args.go +++ b/internal/ethapi/transaction_args.go @@ -35,19 +35,18 @@ import ( // TransactionArgs represents the arguments to construct a new transaction // or a message call. type TransactionArgs struct { - From *common.Address `json:"from"` - To *common.Address `json:"to"` - Gas *hexutil.Uint64 `json:"gas"` - GasPrice *hexutil.Big `json:"gasPrice"` - MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` - MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` - Value *hexutil.Big `json:"value"` - IsConfidential bool `json:"IsConfidential"` - ExecutionNode *common.Address `json:"executionNode"` - ConfidentialInputsHash *common.Hash `json:"confidentialInputsHash"` // TODO: testme - ConfidentialInputs *hexutil.Bytes `json:"confidentialInputs"` // TODO: testme - ConfidentialResult *hexutil.Bytes `json:"ConfidentialResult"` // TODO: testme - Nonce *hexutil.Uint64 `json:"nonce"` + From *common.Address `json:"from"` + To *common.Address `json:"to"` + Gas *hexutil.Uint64 `json:"gas"` + GasPrice *hexutil.Big `json:"gasPrice"` + MaxFeePerGas *hexutil.Big `json:"maxFeePerGas"` + MaxPriorityFeePerGas *hexutil.Big `json:"maxPriorityFeePerGas"` + Value *hexutil.Big `json:"value"` + IsConfidential bool `json:"IsConfidential"` + ExecutionNode *common.Address `json:"executionNode"` + ConfidentialInputs *hexutil.Bytes `json:"confidentialInputs"` // TODO: testme + ConfidentialResult *hexutil.Bytes `json:"ConfidentialResult"` // TODO: testme + Nonce *hexutil.Uint64 `json:"nonce"` // We accept "data" and "input" for backwards-compatibility reasons. // "input" is the newer name and should be preferred by clients. @@ -330,24 +329,39 @@ func (args *TransactionArgs) toTransaction() *types.Transaction { confResult = []byte(*args.ConfidentialResult) } + var ccr types.ConfidentialComputeRecord + confidentialComputeRequest, ok := types.CastTxInner[*types.ConfidentialComputeRecord](requestArgs.toTransaction()) + if ok { + ccr = *confidentialComputeRequest + } else { + log.Debug("could not cast compute record!") + } + data = &types.SuaveTransaction{ ExecutionNode: executionNode, ChainID: (*big.Int)(args.ChainID), - ConfidentialComputeRequest: *requestArgs.toTransaction(), + ConfidentialComputeRequest: ccr, ConfidentialComputeResult: confResult, } case args.ExecutionNode != nil: - ccrData := &types.ConfidentialComputeRequest{ - ExecutionNode: executionNode, - To: args.To, - Nonce: uint64(*args.Nonce), - Gas: uint64(*args.Gas), - GasPrice: (*big.Int)(args.GasPrice), - Value: (*big.Int)(args.Value), - Data: args.data(), + var confidentialInputs []byte + if args.ConfidentialInputs != nil { + confidentialInputs = *args.ConfidentialInputs } - data = ccrData + data = &types.ConfidentialComputeRequest{ + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: executionNode, + // TODO: hashme + To: args.To, + Nonce: uint64(*args.Nonce), + Gas: uint64(*args.Gas), + GasPrice: (*big.Int)(args.GasPrice), + Value: (*big.Int)(args.Value), + Data: args.data(), + }, + ConfidentialInputs: confidentialInputs, + } default: data = &types.LegacyTx{ To: args.To, diff --git a/suave/backends/redis_backends_test.go b/suave/backends/redis_backends_test.go index a1ebe3a1b..6c9ed81ad 100644 --- a/suave/backends/redis_backends_test.go +++ b/suave/backends/redis_backends_test.go @@ -84,7 +84,9 @@ func TestEngineOnRedis(t *testing.T) { testKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") dummyCreationTx, err := types.SignTx(types.NewTx(&types.ConfidentialComputeRequest{ - ExecutionNode: common.Address{}, + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: common.Address{}, + }, }), types.NewSuaveSigner(new(big.Int)), testKey) require.NoError(t, err) diff --git a/suave/backends/transactional_store_test.go b/suave/backends/transactional_store_test.go index a5cbc874a..251b5d90a 100644 --- a/suave/backends/transactional_store_test.go +++ b/suave/backends/transactional_store_test.go @@ -16,7 +16,9 @@ func TestTransactionalStore(t *testing.T) { testKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") dummyCreationTx, err := types.SignTx(types.NewTx(&types.ConfidentialComputeRequest{ - ExecutionNode: common.Address{0x42}, + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: common.Address{0x42}, + }, }), types.NewSuaveSigner(new(big.Int)), testKey) require.NoError(t, err) diff --git a/suave/cmd/suavecli/sendBuildShareBlock.go b/suave/cmd/suavecli/sendBuildShareBlock.go index 92a2814f0..a0803396f 100644 --- a/suave/cmd/suavecli/sendBuildShareBlock.go +++ b/suave/cmd/suavecli/sendBuildShareBlock.go @@ -175,13 +175,15 @@ func sendBuildShareBlockTx( RequireNoErrorf(err, "could not pack buildMevShare args: %v", err) wrappedTxData := &types.ConfidentialComputeRequest{ - ExecutionNode: executionNodeAddress, - Nonce: suaveAccNonce, - To: &blockSenderAddr, - Value: nil, - Gas: 1000000, - GasPrice: big.NewInt(33000000000), - Data: calldata, + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: executionNodeAddress, + Nonce: suaveAccNonce, + To: &blockSenderAddr, + Value: nil, + Gas: 1000000, + GasPrice: big.NewInt(33000000000), + Data: calldata, + }, } confidentialRequestTx, err := types.SignTx(types.NewTx(wrappedTxData), suaveSigner, privKey) diff --git a/suave/cmd/suavecli/sendBundle.go b/suave/cmd/suavecli/sendBundle.go index 2538c4aaf..b02415dac 100644 --- a/suave/cmd/suavecli/sendBundle.go +++ b/suave/cmd/suavecli/sendBundle.go @@ -124,12 +124,14 @@ func cmdSendBundle() { RequireNoErrorf(err, "could not call eth_gasPrice on suave: %v", err) confidentialInnerTxTemplate := &types.ConfidentialComputeRequest{ - Nonce: suaveAccNonce, // will be incremented later on - To: &newBundleBidAddress, - Value: nil, - Gas: 1000000, - GasPrice: (*big.Int)(&suaveGp), - Data: nil, // FillMe! + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + Nonce: suaveAccNonce, // will be incremented later on + To: &newBundleBidAddress, + Value: nil, + Gas: 1000000, + GasPrice: (*big.Int)(&suaveGp), + Data: nil, // FillMe! + }, } suaveTxHashes := []common.Hash{} @@ -238,13 +240,15 @@ func cmdSendBundle() { suaveAccNonce = uint64(suaveAccNonceBytes) wrappedTxData := &types.ConfidentialComputeRequest{ - ExecutionNode: executionNodeAddress, - Nonce: suaveAccNonce, - To: &newBlockBidAddress, - Value: nil, - Gas: 1000000, - GasPrice: (*big.Int)(&suaveGp), - Data: calldata, + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: executionNodeAddress, + Nonce: suaveAccNonce, + To: &newBlockBidAddress, + Value: nil, + Gas: 1000000, + GasPrice: (*big.Int)(&suaveGp), + Data: calldata, + }, } confidentialRequestTx, err := types.SignTx(types.NewTx(wrappedTxData), suaveSigner, privKey) diff --git a/suave/cmd/suavecli/sendMevShareBundle.go b/suave/cmd/suavecli/sendMevShareBundle.go index 442470c9a..9f9fd5e25 100644 --- a/suave/cmd/suavecli/sendMevShareBundle.go +++ b/suave/cmd/suavecli/sendMevShareBundle.go @@ -175,13 +175,15 @@ func prepareEthBundle( func prepareMevShareBidTx(suaveSigner types.Signer, privKey *ecdsa.PrivateKey, executionNodeAddr common.Address, suaveAccNonce uint64, calldata []byte, mevShareAddr common.Address) (*types.Transaction, hexutil.Bytes, error) { wrappedTxData := &types.ConfidentialComputeRequest{ - ExecutionNode: executionNodeAddr, - Nonce: suaveAccNonce, - To: &mevShareAddr, - Value: nil, - Gas: 10000000, - GasPrice: big.NewInt(33000000000), - Data: calldata, + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: executionNodeAddr, + Nonce: suaveAccNonce, + To: &mevShareAddr, + Value: nil, + Gas: 10000000, + GasPrice: big.NewInt(33000000000), + Data: calldata, + }, } confidentialRequestTx, err := types.SignTx(types.NewTx(wrappedTxData), suaveSigner, privKey) diff --git a/suave/cmd/suavecli/sendMevShareMatch.go b/suave/cmd/suavecli/sendMevShareMatch.go index 72da51692..81149f704 100644 --- a/suave/cmd/suavecli/sendMevShareMatch.go +++ b/suave/cmd/suavecli/sendMevShareMatch.go @@ -174,13 +174,15 @@ func prepareEthBackrunBundle( func prepareMevBackrunBidTx(suaveSigner types.Signer, privKey *ecdsa.PrivateKey, executionNodeAddr common.Address, suaveAccNonce uint64, calldata []byte, mevShareAddr common.Address) (*types.Transaction, hexutil.Bytes, error) { wrappedTxData := &types.ConfidentialComputeRequest{ - ExecutionNode: executionNodeAddr, - Nonce: suaveAccNonce, - To: &mevShareAddr, - Value: nil, - Gas: 10000000, - GasPrice: big.NewInt(33000000000), - Data: calldata, + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: executionNodeAddr, + Nonce: suaveAccNonce, + To: &mevShareAddr, + Value: nil, + Gas: 10000000, + GasPrice: big.NewInt(33000000000), + Data: calldata, + }, } confidentialRequestTx, err := types.SignTx(types.NewTx(wrappedTxData), suaveSigner, privKey) diff --git a/suave/core/engine_test.go b/suave/core/engine_test.go index c095e0bbc..9466d2e41 100644 --- a/suave/core/engine_test.go +++ b/suave/core/engine_test.go @@ -68,7 +68,9 @@ func TestOwnMessageDropping(t *testing.T) { testKey, _ := crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") // testKeyAddress := crypto.PubkeyToAddress(testKey.PublicKey) dummyCreationTx, err := types.SignTx(types.NewTx(&types.ConfidentialComputeRequest{ - ExecutionNode: common.Address{0x42}, + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: common.Address{0x42}, + }, }), types.NewSuaveSigner(new(big.Int)), testKey) require.NoError(t, err) diff --git a/suave/docs/conf_comp_request_flow.png b/suave/docs/conf_comp_request_flow.png index 8792262d5..0964c1400 100644 Binary files a/suave/docs/conf_comp_request_flow.png and b/suave/docs/conf_comp_request_flow.png differ diff --git a/suave/e2e/workflow_test.go b/suave/e2e/workflow_test.go index 867e2baaf..0b21ba569 100644 --- a/suave/e2e/workflow_test.go +++ b/suave/e2e/workflow_test.go @@ -66,7 +66,11 @@ func TestMempool(t *testing.T) { { targetBlock := uint64(16103213) - creationTx := types.NewTx(&types.ConfidentialComputeRequest{ExecutionNode: fr.ExecutionNode()}) + creationTx := types.NewTx(&types.ConfidentialComputeRequest{ + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: fr.ExecutionNode(), + }, + }) bid1, err := fr.ConfidentialEngine().InitializeBid(types.Bid{ Salt: suave.RandomBidId(), @@ -388,7 +392,9 @@ func TestBlockBuildingPrecompiles(t *testing.T) { // function buildEthBlock(BuildBlockArgs memory blockArgs, BidId bid) internal view returns (bytes memory, bytes memory) { dummyCreationTx, err := types.SignNewTx(testKey, signer, &types.ConfidentialComputeRequest{ - ExecutionNode: fr.ExecutionNode(), + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: fr.ExecutionNode(), + }, }) require.NoError(t, err) diff --git a/suave/genesis/genesis_test.go b/suave/genesis/genesis_test.go index 1325c7271..f6ad6b593 100644 --- a/suave/genesis/genesis_test.go +++ b/suave/genesis/genesis_test.go @@ -7,7 +7,7 @@ import ( ) func TestGenesis(t *testing.T) { - _, err := Load("rigil") + _, err := Load("test") require.NoError(t, err) _, err = Load("./fixtures/genesis-test.json") diff --git a/suave/sdk/sdk.go b/suave/sdk/sdk.go index 987d8f073..20465f39d 100644 --- a/suave/sdk/sdk.go +++ b/suave/sdk/sdk.go @@ -128,13 +128,16 @@ func (c *Contract) SendTransaction(method string, args []interface{}, confidenti } computeRequest, err := types.SignTx(types.NewTx(&types.ConfidentialComputeRequest{ - ExecutionNode: c.client.execNode, - Nonce: nonce, - To: &c.addr, - Value: nil, - GasPrice: gasPrice, - Gas: 1000000, - Data: calldata, + ConfidentialComputeRecord: types.ConfidentialComputeRecord{ + ExecutionNode: c.client.execNode, + Nonce: nonce, + To: &c.addr, + Value: nil, + GasPrice: gasPrice, + Gas: 1000000, + Data: calldata, + }, + ConfidentialInputs: confidentialDataBytes, }), signer, c.client.key) if err != nil { return nil, err @@ -146,7 +149,7 @@ func (c *Contract) SendTransaction(method string, args []interface{}, confidenti } var hash common.Hash - if err = c.client.rpc.Client().Call(&hash, "eth_sendRawTransaction", hexutil.Encode(computeRequestBytes), hexutil.Encode(confidentialDataBytes)); err != nil { + if err = c.client.rpc.Client().Call(&hash, "eth_sendRawTransaction", hexutil.Encode(computeRequestBytes)); err != nil { return nil, err }