diff --git a/core/types/confidential.go b/core/types/confidential.go index aeb802298..b617f040a 100644 --- a/core/types/confidential.go +++ b/core/types/confidential.go @@ -4,6 +4,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" ) type ConfidentialComputeRecord struct { @@ -131,9 +132,16 @@ func (tx *ConfidentialComputeRequest) setSignatureValues(chainID, v, r, s *big.I tx.ChainID, tx.V, tx.R, tx.S = chainID, v, r, s } +type SuaveLog struct { + Topics []common.Hash `json:"topics"` + Data hexutil.Bytes `json:"data"` + Address common.Address `json:"address" ` +} + type SuaveTransaction struct { ConfidentialComputeRequest ConfidentialComputeRecord `json:"confidentialComputeRequest" gencodec:"required"` ConfidentialComputeResult []byte `json:"confidentialComputeResult" gencodec:"required"` + Logs []*SuaveLog `json:"logs" gencodec:"required"` // request KettleAddress's signature ChainID *big.Int @@ -167,6 +175,16 @@ func (tx *SuaveTransaction) copy() TxData { cpy.S.Set(tx.S) } + // copy logs + cpy.Logs = make([]*SuaveLog, len(tx.Logs)) + for i, log := range tx.Logs { + cpy.Logs[i] = &SuaveLog{ + Topics: append([]common.Hash{}, log.Topics...), + Data: common.CopyBytes(log.Data), + Address: log.Address, + } + } + return cpy } diff --git a/core/types/transaction_marshalling.go b/core/types/transaction_marshalling.go index 1855b2e6b..e94640393 100644 --- a/core/types/transaction_marshalling.go +++ b/core/types/transaction_marshalling.go @@ -51,6 +51,9 @@ type txJSON struct { R *hexutil.Big `json:"r"` S *hexutil.Big `json:"s"` + // Suave-specific fields + Logs []*SuaveLog `json:"logs,omitempty"` + // Only used for encoding: Hash common.Hash `json:"hash"` } @@ -154,7 +157,7 @@ func (tx *Transaction) MarshalJSON() ([]byte, error) { } enc.RequestRecord = (*json.RawMessage)(&requestRecord) - + enc.Logs = itx.Logs enc.ChainID = (*hexutil.Big)(itx.ChainID) enc.ConfidentialComputeResult = (*hexutil.Bytes)(&itx.ConfidentialComputeResult) enc.V = (*hexutil.Big)(itx.V) @@ -564,6 +567,9 @@ func (tx *Transaction) UnmarshalJSON(input []byte) error { return err } } + if dec.Logs != nil { + itx.Logs = dec.Logs + } default: return ErrTxTypeNotSupported diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 8d91df548..d344196ef 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1378,6 +1378,9 @@ type RPCTransaction struct { V *hexutil.Big `json:"v"` R *hexutil.Big `json:"r"` S *hexutil.Big `json:"s"` + + // Suave-specific fields + Logs []*types.SuaveLog `json:"logs,omitempty"` } // newRPCTransaction returns a transaction that will serialize to the RPC @@ -1475,6 +1478,7 @@ func newRPCTransaction(tx *types.Transaction, blockHash common.Hash, blockNumber return nil } + result.Logs = inner.Logs result.RequestRecord = (*json.RawMessage)(&rrBytes) result.ConfidentialComputeResult = (*hexutil.Bytes)(&inner.ConfidentialComputeResult) result.ChainID = (*hexutil.Big)(tx.ChainId()) @@ -2003,7 +2007,21 @@ 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{ConfidentialComputeRequest: confidentialRequest.ConfidentialComputeRecord, ConfidentialComputeResult: computeResult} + logs := state.Logs() + suaveLogs := make([]*types.SuaveLog, len(logs)) + for i, l := range logs { + suaveLogs[i] = &types.SuaveLog{ + Address: l.Address, + Topics: append([]common.Hash{}, l.Topics...), + Data: append([]byte{}, l.Data...), + } + } + + suaveResultTxData := &types.SuaveTransaction{ + ConfidentialComputeRequest: confidentialRequest.ConfidentialComputeRecord, + ConfidentialComputeResult: computeResult, + Logs: suaveLogs, + } signed, err := wallet.SignTx(account, types.NewTx(suaveResultTxData), tx.ChainId()) if err != nil { diff --git a/suave/artifacts/example.sol/ExampleEthCallSource.json b/suave/artifacts/example.sol/ExampleEthCallSource.json index fa5d8e502..3d272abb4 100644 --- a/suave/artifacts/example.sol/ExampleEthCallSource.json +++ b/suave/artifacts/example.sol/ExampleEthCallSource.json @@ -16,6 +16,19 @@ "name": "PeekerReverted", "type": "error" }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "uint64", + "name": "num", + "type": "uint64" + } + ], + "name": "Event", + "type": "event" + }, { "inputs": [ { @@ -33,12 +46,25 @@ "outputs": [], "stateMutability": "nonpayable", "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint64", + "name": "numLogs", + "type": "uint64" + } + ], + "name": "emitEvent", + "outputs": [], + "stateMutability": "payable", + "type": "function" } ], "deployedBytecode": { - "object": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c806348bce06414610030575b600080fd5b61004361003e366004610183565b610045565b005b6040805160048152602481019091526020810180516001600160e01b0316631b53398f60e21b17905260009061007c9084906100b2565b905060008180602001905181019061009491906101bb565b67ffffffffffffffff1690508281146100ac57600080fd5b50505050565b606060008063421000036001600160a01b031685856040516020016100d8929190610210565b60408051601f19818403018152908290526100f291610252565b600060405180830381855afa9150503d806000811461012d576040519150601f19603f3d011682016040523d82523d6000602084013e610132565b606091505b509150915081610166576342100003816040516375fff46760e01b815260040161015d929190610210565b60405180910390fd5b8080602001905181019061017a9190610284565b95945050505050565b6000806040838503121561019657600080fd5b82356001600160a01b03811681146101ad57600080fd5b946020939093013593505050565b6000602082840312156101cd57600080fd5b815167ffffffffffffffff811681146101e557600080fd5b9392505050565b60005b838110156102075781810151838201526020016101ef565b50506000910152565b60018060a01b0383168152604060208201526000825180604084015261023d8160608501602087016101ec565b601f01601f1916919091016060019392505050565b600082516102648184602087016101ec565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561029657600080fd5b815167ffffffffffffffff808211156102ae57600080fd5b818401915084601f8301126102c257600080fd5b8151818111156102d4576102d461026e565b604051601f8201601f19908116603f011681019083821181831017156102fc576102fc61026e565b8160405282815287602084870101111561031557600080fd5b6103268360208301602088016101ec565b97965050505050505056fea164736f6c6343000813000a" + "object": "0x6080604052600436106100295760003560e01c806326819d161461002e57806348bce06414610043575b600080fd5b61004161003c36600461022c565b610063565b005b34801561004f57600080fd5b5061004161005e366004610250565b6100d5565b60005b8167ffffffffffffffff168167ffffffffffffffff1610156100d15760405167ffffffffffffffff821681527f907b6183af8dff6c3ccd5a6e356d2950ee5261d1de2d382d1d2d32eebf1d1c1b9060200160405180910390a1806100c981610288565b915050610066565b5050565b6040805160048152602481019091526020810180516001600160e01b0316631b53398f60e21b17905260009061010c908490610142565b905060008180602001905181019061012491906102bd565b67ffffffffffffffff16905082811461013c57600080fd5b50505050565b606060008063421000036001600160a01b031685856040516020016101689291906102fe565b60408051601f198184030181529082905261018291610340565b600060405180830381855afa9150503d80600081146101bd576040519150601f19603f3d011682016040523d82523d6000602084013e6101c2565b606091505b5091509150816101f6576342100003816040516375fff46760e01b81526004016101ed9291906102fe565b60405180910390fd5b8080602001905181019061020a9190610372565b95945050505050565b67ffffffffffffffff8116811461022957600080fd5b50565b60006020828403121561023e57600080fd5b813561024981610213565b9392505050565b6000806040838503121561026357600080fd5b82356001600160a01b038116811461027a57600080fd5b946020939093013593505050565b600067ffffffffffffffff8083168181036102b357634e487b7160e01b600052601160045260246000fd5b6001019392505050565b6000602082840312156102cf57600080fd5b815161024981610213565b60005b838110156102f55781810151838201526020016102dd565b50506000910152565b60018060a01b0383168152604060208201526000825180604084015261032b8160608501602087016102da565b601f01601f1916919091016060019392505050565b600082516103528184602087016102da565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561038457600080fd5b815167ffffffffffffffff8082111561039c57600080fd5b818401915084601f8301126103b057600080fd5b8151818111156103c2576103c261035c565b604051601f8201601f19908116603f011681019083821181831017156103ea576103ea61035c565b8160405282815287602084870101111561040357600080fd5b6104148360208301602088016102da565b97965050505050505056fea164736f6c6343000813000a" }, "bytecode": { - "object": "0x608060405234801561001057600080fd5b5061033e806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c806348bce06414610030575b600080fd5b61004361003e366004610183565b610045565b005b6040805160048152602481019091526020810180516001600160e01b0316631b53398f60e21b17905260009061007c9084906100b2565b905060008180602001905181019061009491906101bb565b67ffffffffffffffff1690508281146100ac57600080fd5b50505050565b606060008063421000036001600160a01b031685856040516020016100d8929190610210565b60408051601f19818403018152908290526100f291610252565b600060405180830381855afa9150503d806000811461012d576040519150601f19603f3d011682016040523d82523d6000602084013e610132565b606091505b509150915081610166576342100003816040516375fff46760e01b815260040161015d929190610210565b60405180910390fd5b8080602001905181019061017a9190610284565b95945050505050565b6000806040838503121561019657600080fd5b82356001600160a01b03811681146101ad57600080fd5b946020939093013593505050565b6000602082840312156101cd57600080fd5b815167ffffffffffffffff811681146101e557600080fd5b9392505050565b60005b838110156102075781810151838201526020016101ef565b50506000910152565b60018060a01b0383168152604060208201526000825180604084015261023d8160608501602087016101ec565b601f01601f1916919091016060019392505050565b600082516102648184602087016101ec565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561029657600080fd5b815167ffffffffffffffff808211156102ae57600080fd5b818401915084601f8301126102c257600080fd5b8151818111156102d4576102d461026e565b604051601f8201601f19908116603f011681019083821181831017156102fc576102fc61026e565b8160405282815287602084870101111561031557600080fd5b6103268360208301602088016101ec565b97965050505050505056fea164736f6c6343000813000a" + "object": "0x608060405234801561001057600080fd5b5061042c806100206000396000f3fe6080604052600436106100295760003560e01c806326819d161461002e57806348bce06414610043575b600080fd5b61004161003c36600461022c565b610063565b005b34801561004f57600080fd5b5061004161005e366004610250565b6100d5565b60005b8167ffffffffffffffff168167ffffffffffffffff1610156100d15760405167ffffffffffffffff821681527f907b6183af8dff6c3ccd5a6e356d2950ee5261d1de2d382d1d2d32eebf1d1c1b9060200160405180910390a1806100c981610288565b915050610066565b5050565b6040805160048152602481019091526020810180516001600160e01b0316631b53398f60e21b17905260009061010c908490610142565b905060008180602001905181019061012491906102bd565b67ffffffffffffffff16905082811461013c57600080fd5b50505050565b606060008063421000036001600160a01b031685856040516020016101689291906102fe565b60408051601f198184030181529082905261018291610340565b600060405180830381855afa9150503d80600081146101bd576040519150601f19603f3d011682016040523d82523d6000602084013e6101c2565b606091505b5091509150816101f6576342100003816040516375fff46760e01b81526004016101ed9291906102fe565b60405180910390fd5b8080602001905181019061020a9190610372565b95945050505050565b67ffffffffffffffff8116811461022957600080fd5b50565b60006020828403121561023e57600080fd5b813561024981610213565b9392505050565b6000806040838503121561026357600080fd5b82356001600160a01b038116811461027a57600080fd5b946020939093013593505050565b600067ffffffffffffffff8083168181036102b357634e487b7160e01b600052601160045260246000fd5b6001019392505050565b6000602082840312156102cf57600080fd5b815161024981610213565b60005b838110156102f55781810151838201526020016102dd565b50506000910152565b60018060a01b0383168152604060208201526000825180604084015261032b8160608501602087016102da565b601f01601f1916919091016060019392505050565b600082516103528184602087016102da565b9190910192915050565b634e487b7160e01b600052604160045260246000fd5b60006020828403121561038457600080fd5b815167ffffffffffffffff8082111561039c57600080fd5b818401915084601f8301126103b057600080fd5b8151818111156103c2576103c261035c565b604051601f8201601f19908116603f011681019083821181831017156103ea576103ea61035c565b8160405282815287602084870101111561040357600080fd5b6104148360208301602088016102da565b97965050505050505056fea164736f6c6343000813000a" } } diff --git a/suave/e2e/workflow_test.go b/suave/e2e/workflow_test.go index 8c4e97dd5..9a6395c9f 100644 --- a/suave/e2e/workflow_test.go +++ b/suave/e2e/workflow_test.go @@ -1105,6 +1105,30 @@ func TestE2EKettleAddressEndpoint(t *testing.T) { require.NotEmpty(t, addrs) } +func TestE2EEventLogs(t *testing.T) { + fr := newFramework(t) + defer fr.Close() + + clt := fr.NewSDKClient() + + // We reuse the same address for both the source and target contract + contractAddr := common.Address{0x3} + sourceContract := sdk.GetContract(contractAddr, exampleCallSourceContract.Abi, clt) + + numEvents := 10 + + res, err := sourceContract.SendTransaction("emitEvent", []interface{}{uint64(numEvents)}, nil) + require.NoError(t, err) + + tx, _, err := ethclient.NewClient(fr.suethSrv.RPCNode()).TransactionByHash(context.Background(), res.Hash()) + require.NoError(t, err) + require.Equal(t, tx.Type(), uint8(types.SuaveTxType)) + + suaveTxn, ok := types.CastTxInner[*types.SuaveTransaction](tx) + require.True(t, ok) + require.Len(t, suaveTxn.Logs, numEvents) +} + type clientWrapper struct { t *testing.T diff --git a/suave/sol/standard_peekers/example.sol b/suave/sol/standard_peekers/example.sol index 7a1906e1f..2f4144f3b 100644 --- a/suave/sol/standard_peekers/example.sol +++ b/suave/sol/standard_peekers/example.sol @@ -8,6 +8,14 @@ contract ExampleEthCallSource { (uint256 num) = abi.decode(output, (uint64)); require(num == expected); } + + event Event(uint64 num); + + function emitEvent(uint64 numLogs) public payable { + for (uint64 i = 0; i < numLogs; i++) { + emit Event(i); + } + } } contract ExampleEthCallTarget {