Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

clients/go: use existing RPC connection to retrieve calldata public key #422

Merged
merged 1 commit into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 43 additions & 0 deletions .github/workflows/ci-test-go.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: ci-test

on:
push:
branches:
- main
- stable/*
- rc/*
CedarMist marked this conversation as resolved.
Show resolved Hide resolved
pull_request:
branches:
- main
- stable/*
- rc/*

jobs:
test-client-go:
name: test-client-go
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./clients/go
services:
sapphire-localnet-ci:
image: ghcr.io/oasisprotocol/sapphire-localnet:latest
ports:
- 8545:8545
- 8546:8546
env:
OASIS_DEPOSIT_BINARY: /oasis-deposit -test-mnemonic -n 2
options: >-
--rm
--health-cmd="test -f /CONTAINER_READY"
--health-start-period=90s
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.22.x"

- name: Test
run: go test -v ./...
17 changes: 0 additions & 17 deletions .github/workflows/ci-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,20 +86,3 @@ jobs:

- name: Test JS client
run: pnpm test:unit

test-client-go:
name: test-client-go
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./clients/go
steps:
- uses: actions/checkout@v4

- name: Set up Go
uses: actions/setup-go@v5
with:
go-version: "1.22.x"

- name: Test
run: go test -v ./...
41 changes: 6 additions & 35 deletions clients/go/cipher.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,14 @@
package sapphire

import (
"bytes"
"context"
"crypto/cipher"
"crypto/rand"
"encoding/json"
"errors"
"fmt"
"net/http"

"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/ethclient"

"github.com/oasisprotocol/curve25519-voi/primitives/x25519"
"github.com/oasisprotocol/deoxysii"
Expand Down Expand Up @@ -262,44 +260,17 @@ func (c X25519DeoxysIICipher) DecryptEncoded(response []byte) ([]byte, error) {
}

// GetRuntimePublicKey fetches the runtime calldata public key from the default Sapphire gateway.
func GetRuntimePublicKey(chainID uint64) (*x25519.PublicKey, uint64, error) {
network, exists := Networks[chainID]
if !exists {
return nil, 0, fmt.Errorf("could not fetch public key for network with chain id %d", chainID)
}
request := Request{
Version: "2.0",
Method: "oasis_callDataPublicKey",
ID: 1,
}
rawReq, _ := json.Marshal(request)

req, err := http.NewRequestWithContext(context.Background(), http.MethodPost, network.DefaultGateway, bytes.NewBuffer(rawReq))
if err != nil {
return nil, 0, fmt.Errorf("failed to create request for runtime calldata public key: %w", err)
}
req.Header.Set("Content-Type", "application/json")

client := http.Client{}
res, err := client.Do(req)
if err != nil {
return nil, 0, fmt.Errorf("failed to request runtime calldata public key: %w", err)
}

decoder := json.NewDecoder(res.Body)
rpcRes := new(Response)
if err := decoder.Decode(&rpcRes); err != nil {
return nil, 0, fmt.Errorf("unexpected response to request for runtime calldata public key: %w", err)
}
res.Body.Close()

func GetRuntimePublicKey(c *ethclient.Client) (*x25519.PublicKey, uint64, error) {
var pubKey CallDataPublicKey
if err := json.Unmarshal(rpcRes.Result, &pubKey); err != nil {

if err := c.Client().Call(&pubKey, "oasis_callDataPublicKey"); err != nil {
return nil, 0, fmt.Errorf("invalid response when fetching runtime calldata public key: %w", err)
}

if len(pubKey.PublicKey) != x25519.PublicKeySize {
return nil, 0, fmt.Errorf("invalid public key length")
}

return (*x25519.PublicKey)(pubKey.PublicKey), pubKey.Epoch, nil
}

Expand Down
6 changes: 3 additions & 3 deletions clients/go/compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,8 @@ type WrappedBackend struct {
//
// If you use cipher over a longer period of time, you should create a new
// cipher instance every epoch to refresh the ParaTime's ephemeral key!
func NewCipher(chainID uint64) (Cipher, error) {
runtimePublicKey, epoch, err := GetRuntimePublicKey(chainID)
func NewCipher(c *ethclient.Client) (Cipher, error) {
runtimePublicKey, epoch, err := GetRuntimePublicKey(c)
if err != nil {
return nil, fmt.Errorf("failed to fetch runtime callata public key: %w", err)
}
Expand All @@ -151,7 +151,7 @@ func WrapClient(c *ethclient.Client, sign SignerFn) (*WrappedBackend, error) {
if err != nil {
return nil, fmt.Errorf("failed to fetch chain ID: %w", err)
}
cipher, err := NewCipher(chainID.Uint64())
cipher, err := NewCipher(c)
if err != nil {
return nil, err
}
Expand Down
62 changes: 62 additions & 0 deletions clients/go/compat_test.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
package sapphire

import (
"context"
"encoding/base64"
"encoding/json"
"log"
"math/big"
"testing"

"github.com/ethereum/go-ethereum"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto"

"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-sdk/client-sdk/go/modules/evm"

"github.com/ethereum/go-ethereum/ethclient"
)

func TestPackSignedCall(t *testing.T) {
Expand Down Expand Up @@ -89,3 +95,59 @@ func TestPackSignedCall(t *testing.T) {
t.Fatalf("err innerdata leash mismatch: expected %s got %s", leashOrig, leashDecoded)
}
}

func TestDial(t *testing.T) {
key, err := crypto.HexToECDSA("ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80")
if err != nil {
log.Fatal(err)
}
addr1 := crypto.PubkeyToAddress(key.PublicKey)

key2, err := crypto.GenerateKey()
if err != nil {
log.Fatal(err)
}
addr2 := crypto.PubkeyToAddress(key2.PublicKey)

SapphireChainID := uint64(0x5afd)
client, _ := ethclient.Dial(Networks[SapphireChainID].DefaultGateway)
backend, err := WrapClient(client, func(digest [32]byte) ([]byte, error) {
// Pass in a custom signing function to interact with the signer
return crypto.Sign(digest[:], key)
})
if err != nil {
t.Fatalf("failed to wrap client %v", err)
}

nonce, err := client.PendingNonceAt(context.Background(), addr1)
if err != nil {
t.Fatalf("failed to get pending nonce %v", err)
}

gasPrice, err := client.SuggestGasPrice(context.Background())
if err != nil {
t.Fatalf("failed to get gas price %v", err)
}

txOpts := backend.Transactor(addr1)

tx := types.NewTransaction(nonce, addr2, big.NewInt(1), uint64(100000), gasPrice, nil)
signedTx, err := txOpts.Signer(addr1, tx)
if err != nil {
t.Fatalf("failed to sign transaction %v", err)
}

err = client.SendTransaction(context.Background(), signedTx)
if err != nil {
t.Fatalf("failed to send transaction %v", err)
}

receipt, err := bind.WaitMined(context.Background(), client, signedTx)
if err != nil {
t.Fatalf("transaction failed! %v", err)
}

if receipt.Status != uint64(1) {
t.Fatalf("transaction failed! (status=%v)", receipt.Status)
}
}
Loading