Skip to content

Commit

Permalink
Merge pull request #422 from oasisprotocol/CedarMist/clients/go-fix-c…
Browse files Browse the repository at this point in the history
…alldatapublickey

clients/go: use existing RPC connection to retrieve calldata public key
  • Loading branch information
CedarMist authored Sep 30, 2024
2 parents 0187da9 + f4d7bc7 commit 155a524
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 55 deletions.
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/*
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)
}
}

0 comments on commit 155a524

Please sign in to comment.