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

Wasm precompile engine #93

Draft
wants to merge 6 commits into
base: main
Choose a base branch
from
Draft
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
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,12 @@ suavedevtools:
./suave/scripts/contracts.sh build
go run ./suave/gen/main.go -write

wasm:
GOOS=wasip1 GOARCH=wasm go build -o core/vm/suave_wasm/store_retrieve.wasm core/vm/suave_wasm/store_retrieve/main.go
GOOS=wasip1 GOARCH=wasm go build -o core/vm/suave_wasm/store_put.wasm core/vm/suave_wasm/store_put/main.go
GOOS=wasip1 GOARCH=wasm go build -o core/vm/suave_wasm/extract_hint.wasm core/vm/suave_wasm/extract_hint/main.go
GOOS=wasip1 GOARCH=wasm go build -o core/vm/suave_wasm/suavexec.wasm core/vm/suave_wasm/suavexec/main.go

devnet-up:
docker-compose -f ./suave/devenv/docker-compose.yml up -d --build

Expand Down
25 changes: 25 additions & 0 deletions core/types/suave.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package types

import "github.com/ethereum/go-ethereum/common"

type EngineBid struct {
Id BidId
Salt BidId
DecryptionCondition uint64
AllowedPeekers []common.Address
AllowedStores []common.Address
Version string
CreationTx *Transaction
Signature []byte
}

func (b *EngineBid) ToInnerBid() Bid {
return Bid{
Id: b.Id,
Salt: b.Salt,
DecryptionCondition: b.DecryptionCondition,
AllowedPeekers: b.AllowedPeekers,
AllowedStores: b.AllowedStores,
Version: b.Version,
}
}
13 changes: 8 additions & 5 deletions core/vm/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,12 +91,15 @@ var PrecompiledContractsSuave = map[common.Address]SuavePrecompiledContract{
isConfidentialAddress: &isConfidentialPrecompile{},
confidentialInputsAddress: &confidentialInputsPrecompile{},

confStoreStoreAddress: newConfStoreStore(),
confStoreRetrieveAddress: newConfStoreRetrieve(),
confStoreStoreAddress: newConfStoreStore(),

newBidAddress: newNewBid(),
fetchBidsAddress: newFetchBids(),
extractHintAddress: &extractHint{},
// confStoreRetrieveAddress: newConfStoreRetrieve(),
confStoreRetrieveAddress: &WasiPrecompileWrapper{bytecode: wasmRetrieveBytecode},

newBidAddress: newNewBid(),
fetchBidsAddress: newFetchBids(),
//extractHintAddress: &extractHint{},
extractHintAddress: &WasiPrecompileWrapper{bytecode: helloworld},

signEthTransactionAddress: &signEthTransaction{},
simulateBundleAddress: &simulateBundle{},
Expand Down
1 change: 1 addition & 0 deletions core/vm/contracts_suave_eth.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package vm
import (
"bytes"
"context"
_ "embed"
"encoding/json"
"errors"
"fmt"
Expand Down
4 changes: 2 additions & 2 deletions core/vm/suave.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,10 @@ func (p *SuavePrecompiledContractWrapper) Run(input []byte) ([]byte, error) {
ret, err = (&confidentialInputsPrecompile{}).RunConfidential(p.suaveContext, input)

case confStoreStoreAddress:
ret, err = stub.confidentialStoreStore(input)
ret, err = (&WasiPrecompileWrapper{bytecode: wasmStorePutBytecode}).RunConfidential(p.suaveContext, input)

case confStoreRetrieveAddress:
ret, err = stub.confidentialStoreRetrieve(input)
ret, err = (&WasiPrecompileWrapper{bytecode: wasmRetrieveBytecode}).RunConfidential(p.suaveContext, input)

case newBidAddress:
ret, err = stub.newBid(input)
Expand Down
Binary file added core/vm/suave_wasm/extract_hint.wasm
Binary file not shown.
52 changes: 52 additions & 0 deletions core/vm/suave_wasm/extract_hint/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package main

import (
"bytes"
"encoding/json"
"io"
"os"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/suave/artifacts"

suave_lib "github.com/ethereum/go-ethereum/core/vm/suave_wasm/lib"
)

func main() {
unpacked, err := suave_lib.UnpackInputs(artifacts.SuaveAbi.Methods["extractHint"].Inputs)
if err != nil {
suave_lib.Fail(err)
}

bundleBytes := unpacked[0].([]byte)

bundle := struct {
Txs types.Transactions `json:"txs"`
RevertingHashes []common.Hash `json:"revertingHashes"`
RefundPercent int `json:"percent"`
MatchId types.BidId `json:"MatchId"`
}{}

err = json.Unmarshal(bundleBytes, &bundle)
if err != nil {
io.Copy(os.Stdout, bytes.NewBuffer([]byte(err.Error())))
os.Exit(2)
}

tx := bundle.Txs[0]
hint := struct {
To common.Address
Data []byte
}{
To: *tx.To(),
Data: tx.Data(),
}

hintBytes, err := json.Marshal(hint)
if err != nil {
suave_lib.Fail(err)
}

suave_lib.ReturnBytes(hintBytes)
}
86 changes: 86 additions & 0 deletions core/vm/suave_wasm/lib/suave_lib.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package lib

import (
"encoding/json"
"fmt"
"unsafe"

"github.com/ethereum/go-ethereum/core/types"
suave_wasi "github.com/ethereum/go-ethereum/suave/wasi"
)

type hostJsonFn = func(inputOffset, inputSize, outputOffset, outputSize, n uint32) uint32

func call_hostFn[In any, Out any](data In, fn hostJsonFn) (Out, error) {
var out Out

jsonInputBytes, err := json.Marshal(data)
if err != nil {
return out, fmt.Errorf("failed to marshal: %w", err)
}

inputBidOffset := bytesToPointer(jsonInputBytes)
inputBidSize := uint32(len(jsonInputBytes))

bufOffset := bytesToPointer(dataBuf)
bufSize := uint32(len(dataBuf))

n := uint32(0)
nOffset := uint32(uintptr(unsafe.Pointer(&n)))

errno := fn(inputBidOffset, inputBidSize, bufOffset, bufSize, nOffset)
if errno != 0 {
return out, fmt.Errorf("host function failed: %s", string(dataBuf[:n]))
}

err = json.Unmarshal(dataBuf[:n], &out)
if err != nil {
return out, fmt.Errorf("failed to unmarshal: %w", err)
}

return out, nil
}

func InitializeBid(rawBid types.Bid) (types.Bid, error) {
return call_hostFn[types.Bid, types.Bid](rawBid, initializeBid)
}

func Store(bidId types.BidId, key string, value []byte) (types.EngineBid, error) {
return call_hostFn[suave_wasi.StoreHostFnArgs, types.EngineBid](suave_wasi.StoreHostFnArgs{bidId, key, value}, storePut)
}

func StoreRetrieve(bidId types.BidId, key string) ([]byte, error) {
return call_hostFn[suave_wasi.RetrieveHostFnArgs, []byte](suave_wasi.RetrieveHostFnArgs{bidId, key}, storeRetrieve)
}

func FetchBidById(bidId types.BidId) (types.EngineBid, error) {
return call_hostFn[types.BidId, types.EngineBid](bidId, fetchBidById)
}

func FetchBidsByProtocolAndBlock(blockNumber uint64, namespace string) ([]types.EngineBid, error) {
return call_hostFn[suave_wasi.FetchBidByProtocolFnArgs, []types.EngineBid](suave_wasi.FetchBidByProtocolFnArgs{blockNumber, namespace}, fetchBidsByProtocolAndBlock)
}

var (
dataBuf = make([]byte, 1024*256) // max 256KB (TODO!)
)

//go:wasmimport suavexec initializeBid
//go:noescape
func initializeBid(inputOffset, inputSize, outputOffset, outputSize, n uint32) uint32

//go:wasmimport suavexec storePut
//go:noescape
func storePut(inputOffset, inputSize, outputOffset, outputSize, n uint32) uint32

//go:wasmimport suavexec storeRetrieve
//go:noescape
func storeRetrieve(inputOffset, inputSize, outputOffset, outputSize, n uint32) uint32

//go:wasmimport suavexec fetchBidById
//go:noescape
func fetchBidById(inputOffset, inputSize, outputOffset, outputSize, n uint32) uint32

//go:wasmimport suavexec fetchBidsByProtocolAndBlock
//go:noescape
func fetchBidsByProtocolAndBlock(inputOffset, inputSize, outputOffset, outputSize, n uint32) uint32
51 changes: 51 additions & 0 deletions core/vm/suave_wasm/lib/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package lib

import (
"bytes"
"fmt"
"io"
"os"
"unsafe"

"github.com/ethereum/go-ethereum/accounts/abi"
)

func UnpackInputs(argSpec abi.Arguments) ([]interface{}, error) {
inputBuf := bytes.NewBuffer([]byte{})
io.Copy(inputBuf, os.Stdin)

unpacked, err := argSpec.Unpack(inputBuf.Bytes())
if err != nil {
return nil, err
}

return unpacked, nil
}

func ReturnPackedArgs(argSpec abi.Arguments, args ...interface{}) {
packed, err := argSpec.Pack(args...)
if err != nil {
Fail(fmt.Errorf("could not pack output: %w", err))
}

ReturnBytes(packed)
}

func Fail(err error) {
io.Copy(os.Stdout, bytes.NewBufferString(err.Error()))
os.Exit(1)
}

func ReturnBytes(data []byte) {
io.Copy(os.Stdout, bytes.NewReader(data))
}

//go:inline
func bytesToPointer(b []byte) uint32 {
return uint32(uintptr(unsafe.Pointer(unsafe.SliceData(b))))
}

//go:inline
func stringToPointer(s string) uint32 {
return uint32(uintptr(unsafe.Pointer(unsafe.StringData(s))))
}
Binary file added core/vm/suave_wasm/store_put.wasm
Binary file not shown.
25 changes: 25 additions & 0 deletions core/vm/suave_wasm/store_put/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package main

import (
"github.com/ethereum/go-ethereum/suave/artifacts"

suave_lib "github.com/ethereum/go-ethereum/core/vm/suave_wasm/lib"
)

func main() {
unpacked, err := suave_lib.UnpackInputs(artifacts.SuaveAbi.Methods["confidentialStoreStore"].Inputs)
if err != nil {
suave_lib.Fail(err)
}

bidId := unpacked[0].([16]byte)
key := unpacked[1].(string)
value := unpacked[2].([]byte)

_, err = suave_lib.Store(bidId, key, value)
if err != nil {
suave_lib.Fail(err)
}

// no return
}
Binary file added core/vm/suave_wasm/store_retrieve.wasm
Binary file not shown.
24 changes: 24 additions & 0 deletions core/vm/suave_wasm/store_retrieve/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"github.com/ethereum/go-ethereum/suave/artifacts"

suave_lib "github.com/ethereum/go-ethereum/core/vm/suave_wasm/lib"
)

func main() {
unpacked, err := suave_lib.UnpackInputs(artifacts.SuaveAbi.Methods["confidentialStoreRetrieve"].Inputs)
if err != nil {
suave_lib.Fail(err)
}

bidId := unpacked[0].([16]byte)
key := unpacked[1].(string)

data, err := suave_lib.StoreRetrieve(bidId, key)
if err != nil {
suave_lib.Fail(err)
}

suave_lib.ReturnBytes(data)
}
Binary file added core/vm/suave_wasm/suavexec.wasm
Binary file not shown.
24 changes: 24 additions & 0 deletions core/vm/suave_wasm/suavexec/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package main

import (
"bytes"
"io"
"os"

"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm/suave_wasm/lib"
)

var (
bid = types.BidId{0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef}
key = "someKey"
)

func main() {
data, err := lib.StoreRetrieve(bid, key)
if err != nil {
os.Exit(1)
}

io.Copy(os.Stdout, bytes.NewReader(data[:]))
}
Binary file added core/vm/suave_wasm/suavexec/main.wasm
Binary file not shown.
Loading