diff --git a/integration/obscurogateway/events_contract.sol b/integration/obscurogateway/events_contract.sol new file mode 100644 index 0000000000..f67a5a7350 --- /dev/null +++ b/integration/obscurogateway/events_contract.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: MIT +// Specify the Solidity version +pragma solidity ^0.8.0; + +contract SimpleMessageContract { + + // State variable to store the message + string public message; + string public message2; + + // Event declaration + event MessageUpdatedWithAddress(string newMessage, address indexed sender); + event Message2Updated(string newMessage); + + // Constructor to initialize the message + constructor() { + message = ""; + message2 = ""; + } + + // Function to set a new message + function setMessage(string memory newMessage) public { + message = newMessage; + emit MessageUpdatedWithAddress(newMessage, msg.sender); // Emit the event (only sender can see it) + } + + function setMessage2(string memory newMessage) public { + message2 = newMessage; + emit Message2Updated(newMessage); // Emit the event (everyone can see it) + } +} \ No newline at end of file diff --git a/integration/obscurogateway/obscurogateway_test.go b/integration/obscurogateway/obscurogateway_test.go index 02d1967878..0c3d874c11 100644 --- a/integration/obscurogateway/obscurogateway_test.go +++ b/integration/obscurogateway/obscurogateway_test.go @@ -2,7 +2,11 @@ package faucet import ( "context" + "crypto/ecdsa" + "encoding/hex" "fmt" + "github.com/ethereum/go-ethereum/crypto" + "io" "math/big" "net/http" "strings" @@ -45,7 +49,7 @@ const ( ) func TestObscuroGateway(t *testing.T) { - t.Skip("Commented it out until more testing is driven from this test") + //t.Skip("Commented it out until more testing is driven from this test") startPort := integration.StartPortObscuroGatewayUnitTest wallets := createObscuroNetwork(t, startPort) @@ -103,6 +107,201 @@ func TestObscuroGateway(t *testing.T) { assert.NoError(t, err) } +func TestObscuroGatewaySubscriptionsWithMultipleAccounts(t *testing.T) { + //t.Skip("Commented it out until more testing is driven from this test") + startPort := integration.StartPortObscuroGatewayUnitTest + wallets := createObscuroNetwork(t, startPort) + + obscuroGatewayConf := config.Config{ + WalletExtensionHost: "127.0.0.1", + WalletExtensionPortHTTP: startPort + integration.DefaultObscuroGatewayHTTPPortOffset, + WalletExtensionPortWS: startPort + integration.DefaultObscuroGatewayWSPortOffset, + NodeRPCHTTPAddress: fmt.Sprintf("127.0.0.1:%d", startPort+integration.DefaultHostRPCHTTPOffset), + NodeRPCWebsocketAddress: fmt.Sprintf("127.0.0.1:%d", startPort+integration.DefaultHostRPCWSOffset), + LogPath: "sys_out", + VerboseFlag: false, + } + + obscuroGwContainer := container.NewWalletExtensionContainerFromConfig(obscuroGatewayConf, testlog.Logger()) + go func() { + err := obscuroGwContainer.Start() + if err != nil { + fmt.Printf("error stopping WE - %s", err) + } + }() + + // wait for the msg bus contract to be deployed + time.Sleep(5 * time.Second) + + // make sure the server is ready to receive requests + serverAddress := fmt.Sprintf("http://%s:%d", obscuroGatewayConf.WalletExtensionHost, obscuroGatewayConf.WalletExtensionPortHTTP) + + // make sure the server is ready to receive requests + err := waitServerIsReady(serverAddress) + require.NoError(t, err) + + // Server is now ready and we can create requests + + w := wallets.L2FaucetWallet // TODO: Check what is this FaucetWallet? + + // join Obscuro Gateway as three different users (user0, user1, user2) + // user0 deploys smart contracts + userID0, err := joinObscuroGateway(serverAddress) + require.NoError(t, err) + fmt.Println(fmt.Sprintf("user0 joined Obscuro Gateway with userID: %s", userID0)) + + userID1, err := joinObscuroGateway(serverAddress) + require.NoError(t, err) + fmt.Println(fmt.Sprintf("user1 joined Obscuro Gateway with userID: %s", userID1)) + + userID2, err := joinObscuroGateway(serverAddress) + require.NoError(t, err) + fmt.Println(fmt.Sprintf("user2 joined Obscuro Gateway with userID: %s", userID2)) + + // register your addresses + // register one address with user0 + pk := w.PrivateKey() + address := w.Address().Hex() + resp, err := registerAccount(serverAddress, userID0, pk, address) + require.NoError(t, err) + fmt.Printf("Successfully registered address %s for user: %s with response: %s \n", address, userID0, resp) + + // register two addresses with user1 + pkU1A0 := w.PrivateKey() + addressU1A0 := w.Address().Hex() + resp, err = registerAccount(serverAddress, userID1, pkU1A0, addressU1A0) + require.NoError(t, err) + fmt.Printf("Successfully registered address %s for user: %s with response: %s \n", addressU1A0, userID1, resp) + + pkU1A1 := w.PrivateKey() + addressU1A1 := w.Address().Hex() + resp, err = registerAccount(serverAddress, userID1, pkU1A1, addressU1A1) + require.NoError(t, err) + fmt.Printf("Successfully registered address %s for user: %s with response: %s \n", addressU1A1, userID1, resp) + + // register two addresses with user2 + pkU2A0 := w.PrivateKey() + addressU2A0 := w.Address().Hex() + resp, err = registerAccount(serverAddress, userID2, pkU2A0, addressU2A0) + require.NoError(t, err) + fmt.Printf("Successfully registered address %s for user: %s with response: %s \n", addressU2A0, userID2, resp) + + pkU2A1 := w.PrivateKey() + addressU2A1 := w.Address().Hex() + resp, err = registerAccount(serverAddress, userID1, pkU2A1, addressU2A1) + require.NoError(t, err) + fmt.Printf("Successfully registered address %s for user: %s with response: %s \n", addressU2A1, userID2, resp) + + // Deploy a contract that emits events (with user0) + bytecode := `60806040523480156200001157600080fd5b506040518060200160405280600081525060009081620000329190620002d4565b506040518060200160405280600081525060019081620000539190620002d4565b50620003bb565b600081519050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b60006002820490506001821680620000dc57607f821691505b602082108103620000f257620000f162000094565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026200015c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff826200011d565b6200016886836200011d565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b6000620001b5620001af620001a98462000180565b6200018a565b62000180565b9050919050565b6000819050919050565b620001d18362000194565b620001e9620001e082620001bc565b8484546200012a565b825550505050565b600090565b62000200620001f1565b6200020d818484620001c6565b505050565b5b81811015620002355762000229600082620001f6565b60018101905062000213565b5050565b601f82111562000284576200024e81620000f8565b62000259846200010d565b8101602085101562000269578190505b6200028162000278856200010d565b83018262000212565b50505b505050565b600082821c905092915050565b6000620002a96000198460080262000289565b1980831691505092915050565b6000620002c4838362000296565b9150826002028217905092915050565b620002df826200005a565b67ffffffffffffffff811115620002fb57620002fa62000065565b5b620003078254620000c3565b6200031482828562000239565b600060209050601f8311600181146200034c576000841562000337578287015190505b620003438582620002b6565b865550620003b3565b601f1984166200035c86620000f8565b60005b8281101562000386578489015182556001820191506020850194506020810190506200035f565b86831015620003a65784890151620003a2601f89168262000296565b8355505b6001600288020188555050505b505050505050565b6107ee80620003cb6000396000f3fe608060405234801561001057600080fd5b506004361061004c5760003560e01c8063368b877214610051578063c2d366581461006d578063c5ced0361461008b578063e21f37ce146100a7575b600080fd5b61006b600480360381019061006691906103e6565b6100c5565b005b610075610126565b60405161008291906104ae565b60405180910390f35b6100a560048036038101906100a091906103e6565b6101b4565b005b6100af6101fe565b6040516100bc91906104ae565b60405180910390f35b80600090816100d491906106e6565b503373ffffffffffffffffffffffffffffffffffffffff167fe31c2ad953ded70272b94617f9181f8cc33755f1b40f4c706660f6ee0dfb634a8260405161011b91906104ae565b60405180910390a250565b60018054610133906104ff565b80601f016020809104026020016040519081016040528092919081815260200182805461015f906104ff565b80156101ac5780601f10610181576101008083540402835291602001916101ac565b820191906000526020600020905b81548152906001019060200180831161018f57829003601f168201915b505050505081565b80600190816101c391906106e6565b507f4fcdf2659dcf2254d2bce07af2baaf0c6ddf6da052dd241b2445a2f6398ae575816040516101f391906104ae565b60405180910390a150565b6000805461020b906104ff565b80601f0160208091040260200160405190810160405280929190818152602001828054610237906104ff565b80156102845780601f1061025957610100808354040283529160200191610284565b820191906000526020600020905b81548152906001019060200180831161026757829003601f168201915b505050505081565b6000604051905090565b600080fd5b600080fd5b600080fd5b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6102f3826102aa565b810181811067ffffffffffffffff82111715610312576103116102bb565b5b80604052505050565b600061032561028c565b905061033182826102ea565b919050565b600067ffffffffffffffff821115610351576103506102bb565b5b61035a826102aa565b9050602081019050919050565b82818337600083830152505050565b600061038961038484610336565b61031b565b9050828152602081018484840111156103a5576103a46102a5565b5b6103b0848285610367565b509392505050565b600082601f8301126103cd576103cc6102a0565b5b81356103dd848260208601610376565b91505092915050565b6000602082840312156103fc576103fb610296565b5b600082013567ffffffffffffffff81111561041a5761041961029b565b5b610426848285016103b8565b91505092915050565b600081519050919050565b600082825260208201905092915050565b60005b8381101561046957808201518184015260208101905061044e565b60008484015250505050565b60006104808261042f565b61048a818561043a565b935061049a81856020860161044b565b6104a3816102aa565b840191505092915050565b600060208201905081810360008301526104c88184610475565b905092915050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b6000600282049050600182168061051757607f821691505b60208210810361052a576105296104d0565b5b50919050565b60008190508160005260206000209050919050565b60006020601f8301049050919050565b600082821b905092915050565b6000600883026105927fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82610555565b61059c8683610555565b95508019841693508086168417925050509392505050565b6000819050919050565b6000819050919050565b60006105e36105de6105d9846105b4565b6105be565b6105b4565b9050919050565b6000819050919050565b6105fd836105c8565b610611610609826105ea565b848454610562565b825550505050565b600090565b610626610619565b6106318184846105f4565b505050565b5b818110156106555761064a60008261061e565b600181019050610637565b5050565b601f82111561069a5761066b81610530565b61067484610545565b81016020851015610683578190505b61069761068f85610545565b830182610636565b50505b505050565b600082821c905092915050565b60006106bd6000198460080261069f565b1980831691505092915050565b60006106d683836106ac565b9150826002028217905092915050565b6106ef8261042f565b67ffffffffffffffff811115610708576107076102bb565b5b61071282546104ff565b61071d828285610659565b600060209050601f831160018114610750576000841561073e578287015190505b61074885826106ca565b8655506107b0565b601f19841661075e86610530565b60005b8281101561078657848901518255600182019150602085019450602081019050610761565b868310156107a3578489015161079f601f8916826106ac565b8355505b6001600288020188555050505b50505050505056fea2646970667358221220e4e772e2ddf401fe8b1b737e3e4e3852532ce880f04bb28f41e4d17d4ae8227964736f6c63430008120033` + + abi := ` + [ + { + "inputs": [], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "newMessage", + "type": "string" + } + ], + "name": "Message2Updated", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "string", + "name": "newMessage", + "type": "string" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + } + ], + "name": "MessageUpdatedWithAddress", + "type": "event" + }, + { + "inputs": [], + "name": "message", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "message2", + "outputs": [ + { + "internalType": "string", + "name": "", + "type": "string" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "newMessage", + "type": "string" + } + ], + "name": "setMessage", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "string", + "name": "newMessage", + "type": "string" + } + ], + "name": "setMessage2", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + } +] + ` + + contractAddress, err := deployContract(bytecode, abi, userID0) + assert.NoError(t, err) + fmt.Printf("Deployed contract address is: %s \n", contractAddress) + + // subscribe to events with both user1 and user2 + + // Interact with deployed contract + + // Gracefully shutdown + err = obscuroGwContainer.Stop() + assert.NoError(t, err) +} + func transferRandomAddr(t *testing.T, authClient *obsclient.AuthObsClient, w wallet.Wallet) common.TxHash { ctx := context.Background() toAddr := datagenerator.RandomAddress() @@ -197,3 +396,57 @@ func waitServerIsReady(serverAddr string) error { } return fmt.Errorf("timed out before server was ready") } + +func joinObscuroGateway(url string) (string, error) { + statusCode, userID, err := fasthttp.Get(nil, fmt.Sprintf("%s/v1/join/", url)) + if err != nil || statusCode != 200 { + return "", fmt.Errorf(fmt.Sprintf("Failed to get userID. Status code: %d, err: %s", statusCode, err)) + } + return string(userID), nil +} + +func registerAccount(url string, userID string, pk *ecdsa.PrivateKey, hexAddress string) ([]byte, error) { + payload := prepareRegisterPayload(userID, pk, hexAddress) + + req, err := http.NewRequestWithContext( + context.Background(), + http.MethodPost, + url+"/v1/authenticate/?u="+userID, + strings.NewReader(payload), + ) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", "application/json; charset=UTF-8") + + client := &http.Client{} + response, err := client.Do(req) + if err != nil { + return nil, err + } + + defer response.Body.Close() + return io.ReadAll(response.Body) +} + +func prepareRegisterPayload(userID string, pk *ecdsa.PrivateKey, hexAddress string) string { + message := fmt.Sprintf("Register %s for %s", userID, strings.ToLower(hexAddress)) + prefixedMessage := fmt.Sprintf("\u0019Ethereum Signed Message:\n%d%s", len(message), message) + messageHash := crypto.Keccak256([]byte(prefixedMessage)) + sig, err := crypto.Sign(messageHash, pk) + if err != nil { + fmt.Printf("Failed to sign message: %v\n", err) + } + sig[64] += 27 + signature := "0x" + hex.EncodeToString(sig) + payload := fmt.Sprintf("{\"signature\": \"%s\", \"message\": \"%s\"}", signature, message) + return payload +} + +func deployContract(bytecode string, abi string, userID string) (string, error) { + fmt.Println("Deploying new contract..") + // TODO: How to deploy a contract? + // authClient := obsclient.NewAuthObsClient(client) was created in tx_tests, but it works only with old we endpoints + + return "", nil +}