Skip to content

Commit

Permalink
go/oasis-test-runner: Add encrypt/decrypt txs to test client scenarios
Browse files Browse the repository at this point in the history
Transactions for encryption and decryption within the simple key-value
runtime are valuable for testing public key methods.
  • Loading branch information
peternose committed Oct 12, 2023
1 parent a2fc009 commit 0a1f95c
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 12 deletions.
1 change: 1 addition & 0 deletions .changelog/5398.feature.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
go/oasis-test-runner: Add encrypt/decrypt txs to test client scenarios
135 changes: 123 additions & 12 deletions go/oasis-test-runner/scenario/e2e/runtime/test_client.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
package runtime

import (
"bytes"
"context"
"crypto"
"fmt"
"math/rand"

beacon "github.com/oasisprotocol/oasis-core/go/beacon/api"
"github.com/oasisprotocol/oasis-core/go/common"
"github.com/oasisprotocol/oasis-core/go/common/cbor"
"github.com/oasisprotocol/oasis-core/go/common/crypto/drbg"
Expand Down Expand Up @@ -157,6 +159,33 @@ func (cli *TestClient) submit(ctx context.Context, req interface{}, rng rand.Sou
return fmt.Errorf("response does not have expected value (got: '%v', expected: '%v')", rsp, req.Response)
}

case EncryptDecryptTx:
ciphertext, err := cli.sc.submitKeyValueRuntimeEncryptTx(
ctx,
KeyValueRuntimeID,
rng.Uint64(),
req.Epoch,
req.KeyPairID,
req.Message,
)
if err != nil {
return fmt.Errorf("failed to encrypt message: %w", err)
}
plaintext, err := cli.sc.submitKeyValueRuntimeDecryptTx(
ctx,
KeyValueRuntimeID,
rng.Uint64(),
req.Epoch,
req.KeyPairID,
ciphertext,
)
if err != nil {
return fmt.Errorf("failed to decrypt ciphertext: %w", err)
}
if !bytes.Equal(plaintext, req.Message) {
return fmt.Errorf("decrypted message does not have expected value (got: '%v', expected: '%v')", plaintext, req.Message)
}

case InsertKeyValueTx:
rsp, err := cli.sc.submitKeyValueRuntimeInsertTx(
ctx,
Expand Down Expand Up @@ -252,26 +281,108 @@ func NewTestClient() *TestClient {
}
}

func (sc *Scenario) submitAndDecodeRuntimeTx(
func (sc *Scenario) submitRuntimeTxAndDecode(
ctx context.Context,
id common.Namespace,
nonce uint64,
method string,
args interface{},
) (string, error) {
rsp interface{},
) error {
rawRsp, err := sc.submitRuntimeTx(ctx, id, nonce, method, args)
if err != nil {
return "", fmt.Errorf("failed to submit %s tx to runtime: %w", method, err)
return fmt.Errorf("failed to submit %s tx to runtime: %w", method, err)
}

if err = cbor.Unmarshal(rawRsp, rsp); err != nil {
return fmt.Errorf("failed to unmarshal %s tx response from runtime: %w", method, err)
}

return nil
}

func (sc *Scenario) submitRuntimeTxAndDecodeString(
ctx context.Context,
id common.Namespace,
nonce uint64,
method string,
args interface{},
) (string, error) {
var rsp string
if err = cbor.Unmarshal(rawRsp, &rsp); err != nil {
return "", fmt.Errorf("failed to unmarshal %s tx response from runtime: %w", method, err)
if err := sc.submitRuntimeTxAndDecode(ctx, id, nonce, method, args, &rsp); err != nil {
return "", err
}
return rsp, nil
}

func (sc *Scenario) submitRuntimeTxAndDecodeByteSlice(
ctx context.Context,
id common.Namespace,
nonce uint64,
method string,
args interface{},
) ([]byte, error) {
var rsp []byte
if err := sc.submitRuntimeTxAndDecode(ctx, id, nonce, method, args, &rsp); err != nil {
return nil, err
}
return rsp, nil
}

func (sc *Scenario) submitKeyValueRuntimeEncryptTx(
ctx context.Context,
id common.Namespace,
nonce uint64,
epoch beacon.EpochTime,
keyPairID string,
plaintext []byte,
) ([]byte, error) {
sc.Logger.Info("encrypting",
"epoch", epoch,
"key_pair_id", keyPairID,
"plaintext", plaintext,
)

args := struct {
Epoch beacon.EpochTime `json:"epoch"`
KeyPairID string `json:"key_pair_id"`
Plaintext []byte `json:"plaintext"`
}{
Epoch: epoch,
KeyPairID: keyPairID,
Plaintext: plaintext,
}

return sc.submitRuntimeTxAndDecodeByteSlice(ctx, id, nonce, "encrypt", args)
}

func (sc *Scenario) submitKeyValueRuntimeDecryptTx(
ctx context.Context,
id common.Namespace,
nonce uint64,
epoch beacon.EpochTime,
keyPairID string,
ciphertext []byte,
) ([]byte, error) {
sc.Logger.Info("decrypting",
"epoch", epoch,
"key_pair_id", keyPairID,
"ciphertext", ciphertext,
)

args := struct {
Epoch beacon.EpochTime `json:"epoch"`
KeyPairID string `json:"key_pair_id"`
Ciphertext []byte `json:"ciphertext"`
}{
Epoch: epoch,
KeyPairID: keyPairID,
Ciphertext: ciphertext,
}

return sc.submitRuntimeTxAndDecodeByteSlice(ctx, id, nonce, "decrypt", args)
}

func (sc *Scenario) submitKeyValueRuntimeInsertTx(
ctx context.Context,
id common.Namespace,
Expand All @@ -298,9 +409,9 @@ func (sc *Scenario) submitKeyValueRuntimeInsertTx(
}

if encrypted {
return sc.submitAndDecodeRuntimeTx(ctx, id, nonce, "enc_insert", args)
return sc.submitRuntimeTxAndDecodeString(ctx, id, nonce, "enc_insert", args)
}
return sc.submitAndDecodeRuntimeTx(ctx, id, nonce, "insert", args)
return sc.submitRuntimeTxAndDecodeString(ctx, id, nonce, "insert", args)
}

func (sc *Scenario) submitKeyValueRuntimeGetTx(
Expand All @@ -326,9 +437,9 @@ func (sc *Scenario) submitKeyValueRuntimeGetTx(
}

if encrypted {
return sc.submitAndDecodeRuntimeTx(ctx, id, nonce, "enc_get", args)
return sc.submitRuntimeTxAndDecodeString(ctx, id, nonce, "enc_get", args)
}
return sc.submitAndDecodeRuntimeTx(ctx, id, nonce, "get", args)
return sc.submitRuntimeTxAndDecodeString(ctx, id, nonce, "get", args)
}

func (sc *Scenario) submitKeyValueRuntimeRemoveTx(
Expand All @@ -354,9 +465,9 @@ func (sc *Scenario) submitKeyValueRuntimeRemoveTx(
}

if encrypted {
return sc.submitAndDecodeRuntimeTx(ctx, id, nonce, "enc_remove", args)
return sc.submitRuntimeTxAndDecodeString(ctx, id, nonce, "enc_remove", args)
}
return sc.submitAndDecodeRuntimeTx(ctx, id, nonce, "remove", args)
return sc.submitRuntimeTxAndDecodeString(ctx, id, nonce, "remove", args)
}

func (sc *Scenario) submitKeyValueRuntimeGetRuntimeIDTx(
Expand All @@ -366,7 +477,7 @@ func (sc *Scenario) submitKeyValueRuntimeGetRuntimeIDTx(
) (string, error) {
sc.Logger.Info("retrieving runtime ID")

rsp, err := sc.submitAndDecodeRuntimeTx(ctx, id, nonce, "get_runtime_id", nil)
rsp, err := sc.submitRuntimeTxAndDecodeString(ctx, id, nonce, "get_runtime_id", nil)
if err != nil {
return "", fmt.Errorf("failed to query remote runtime ID: %w", err)
}
Expand Down
10 changes: 10 additions & 0 deletions go/oasis-test-runner/scenario/e2e/runtime/test_client_scenario.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package runtime

import (
"fmt"

beacon "github.com/oasisprotocol/oasis-core/go/beacon/api"
)

var (
Expand Down Expand Up @@ -124,6 +126,14 @@ type KeyValueQuery struct {
Round uint64
}

// EncryptDecryptTx encrypts and decrypts a message while verifying if the original message
// matches the decrypted result.
type EncryptDecryptTx struct {
Message []byte
KeyPairID string
Epoch beacon.EpochTime
}

// InsertKeyValueTx inserts a key/value pair to the database, and verifies that the response
// (previous value) contains the expected data.
type InsertKeyValueTx struct {
Expand Down

0 comments on commit 0a1f95c

Please sign in to comment.