Skip to content
This repository was archived by the owner on May 13, 2022. It is now read-only.

Commit 60a86d3

Browse files
author
Silas Davis
authored
Merge pull request #1422 from hyperledger/wasm-call
Implement cross-engine call dispatch for eWASM
2 parents 86b3b7b + 7782261 commit 60a86d3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+1768
-1012
lines changed

Makefile

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ solidity: $(patsubst %.sol, %.sol.go, $(wildcard ./execution/solidity/*.sol)) bu
193193

194194
# Solang fixtures
195195
.PHONY: solang
196-
solang: $(patsubst %.solang, %.solang.go, $(wildcard ./execution/wasm/*.solang)) build_burrow
196+
solang: $(patsubst %.solang, %.solang.go, $(wildcard ./execution/solidity/*.solang) $(wildcard ./execution/wasm/*.solang)) build_burrow
197197

198198
%.solang.go: %.solang
199199
@burrow compile --wasm $^
@@ -210,7 +210,7 @@ test_js:
210210
@cd ${BURROW_TS_PATH} && yarn test
211211

212212
.PHONY: test
213-
test: check bin/solc
213+
test: check bin/solc bin/solang
214214
@tests/scripts/bin_wrapper.sh go test ./... ${GO_TEST_ARGS}
215215

216216
.PHONY: test_keys
@@ -255,6 +255,11 @@ bin/solc: ./tests/scripts/deps/solc.sh
255255
@tests/scripts/deps/solc.sh bin/solc
256256
@touch bin/solc
257257

258+
bin/solang: ./tests/scripts/deps/solang.sh
259+
@mkdir -p bin
260+
@tests/scripts/deps/solang.sh bin/solang
261+
@touch bin/solang
262+
258263
# test burrow with checks for race conditions
259264
.PHONY: test_race
260265
test_race: build_race

binary/integer.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,24 @@ func SignExtend(x *big.Int, n uint) *big.Int {
6767
}
6868
}
6969

70+
// Reverse bytes in-place
71+
func reverse(bs []byte) []byte {
72+
n := len(bs) - 1
73+
for i := 0; i < len(bs)/2; i++ {
74+
bs[i], bs[n-i] = bs[n-i], bs[i]
75+
}
76+
return bs
77+
}
78+
79+
// Note: this function destructively reverses its input slice - pass a copy if the original is used elsewhere
80+
func BigIntFromLittleEndianBytes(bs []byte) *big.Int {
81+
return new(big.Int).SetBytes(reverse(bs))
82+
}
83+
84+
func BigIntToLittleEndianBytes(x *big.Int) []byte {
85+
return reverse(x.Bytes())
86+
}
87+
7088
func andMask(n uint) *big.Int {
7189
x := new(big.Int)
7290
return x.Sub(x.Lsh(big1, n), big1)

binary/integer_test.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,13 @@ func TestSignExtend(t *testing.T) {
133133
"0000 0000 0000 0000 0000 0000 0000 0000 0001 0000 1000 0000 1101 0011 1001 0000")
134134
}
135135

136+
func TestLittleEndian(t *testing.T) {
137+
x, ok := new(big.Int).SetString("234890234579042368982348972347234789897", 10)
138+
require.True(t, ok)
139+
y := BigIntFromLittleEndianBytes(BigIntToLittleEndianBytes(x))
140+
require.Equal(t, x.Cmp(y), 0)
141+
}
142+
136143
func assertSignExtend(t *testing.T, extendedBits int, embeddedBits uint, inputString, expectedString string) bool {
137144
input := intFromString(t, extendedBits, inputString)
138145
expected := intFromString(t, extendedBits, expectedString)

cmd/burrow/commands/compile.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func Compile(output Output) func(cmd *cli.Cmd) {
4040
}
4141

4242
if resp.Warning != "" {
43-
output.Fatalf(resp.Warning)
43+
output.Printf(resp.Warning)
4444
}
4545

4646
f, err := os.Create(solfile + ".go")

deploy/def/jobs.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,8 @@ type Build struct {
317317
Instance string `mapstructure:"instance" json:"instance" yaml:"instance" toml:"instance"`
318318
// (Optional) Path to store an extra copy of the bin file
319319
Store string `mapstructure:"store" json:"store" yaml:"store" toml:"store"`
320+
// (Optional) Use solang to compile to wasm
321+
Wasm bool `mapstructure:"wasm" json:"wasm" yaml:"wasm" toml:"wasm"`
320322
}
321323

322324
func (job *Build) Validate() error {
@@ -361,6 +363,8 @@ type Deploy struct {
361363
Variables []*abi.Variable
362364
// (Optional) Path to store an extra copy of the bin file
363365
Store string `mapstructure:"store" json:"store" yaml:"store" toml:"store"`
366+
// (Optional) Use solang to compile to wasm
367+
Wasm bool `mapstructure:"wasm" json:"wasm" yaml:"wasm" toml:"wasm"`
364368
}
365369

366370
func (job *Deploy) Validate() error {

deploy/jobs/job_manager.go

Lines changed: 19 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ const (
2222
type solidityCompilerWork struct {
2323
contractName string
2424
workDir string
25+
wasm bool
2526
}
2627

2728
type compilerJob struct {
@@ -31,33 +32,28 @@ type compilerJob struct {
3132
done chan struct{}
3233
}
3334

34-
func solcRunner(jobs chan *compilerJob, logger *logging.Logger) {
35+
func solidityRunner(jobs chan *compilerJob, logger *logging.Logger) {
3536
for {
3637
job, ok := <-jobs
3738
if !ok {
38-
break
39+
return
3940
}
40-
resp, err := compilers.EVM(job.work.contractName, false, job.work.workDir, nil, logger)
41-
(*job).compilerResp = resp
42-
(*job).err = err
43-
close(job.done)
44-
}
45-
}
41+
if job.work.wasm {
42+
resp, err := compilers.WASM(job.work.contractName, job.work.workDir, logger)
43+
(*job).compilerResp = resp
44+
(*job).err = err
45+
46+
} else {
47+
resp, err := compilers.EVM(job.work.contractName, false, job.work.workDir, nil, logger)
48+
(*job).compilerResp = resp
49+
(*job).err = err
4650

47-
func solangRunner(jobs chan *compilerJob, logger *logging.Logger) {
48-
for {
49-
job, ok := <-jobs
50-
if !ok {
51-
return
5251
}
53-
resp, err := compilers.WASM(job.work.contractName, job.work.workDir, logger)
54-
(*job).compilerResp = resp
55-
(*job).err = err
5652
close(job.done)
5753
}
5854
}
5955

60-
func queueCompilerWork(job *def.Job, playbook *def.Playbook, jobs chan *compilerJob) error {
56+
func queueCompilerWork(job *def.Job, playbook *def.Playbook, jobs chan *compilerJob, forceWasm bool) error {
6157
payload, err := job.Payload()
6258
if err != nil {
6359
return fmt.Errorf("could not get Job payload: %v", payload)
@@ -71,6 +67,7 @@ func queueCompilerWork(job *def.Job, playbook *def.Playbook, jobs chan *compiler
7167
work: solidityCompilerWork{
7268
contractName: job.Build.Contract,
7369
workDir: playbook.Path,
70+
wasm: job.Build.Wasm || forceWasm,
7471
},
7572
}
7673
job.Intermediate = &intermediate
@@ -82,21 +79,22 @@ func queueCompilerWork(job *def.Job, playbook *def.Playbook, jobs chan *compiler
8279
work: solidityCompilerWork{
8380
contractName: job.Deploy.Contract,
8481
workDir: playbook.Path,
82+
wasm: job.Deploy.Wasm || forceWasm,
8583
},
8684
}
8785
job.Intermediate = &intermediate
8886
jobs <- &intermediate
8987
}
9088
case *def.Proposal:
9189
for _, job := range job.Proposal.Jobs {
92-
err = queueCompilerWork(job, playbook, jobs)
90+
err = queueCompilerWork(job, playbook, jobs, forceWasm)
9391
if err != nil {
9492
return err
9593
}
9694
}
9795
case *def.Meta:
9896
for _, job := range job.Meta.Playbook.Jobs {
99-
err = queueCompilerWork(job, playbook, jobs)
97+
err = queueCompilerWork(job, playbook, jobs, forceWasm)
10098
if err != nil {
10199
return err
102100
}
@@ -318,15 +316,11 @@ func ExecutePlaybook(args *def.DeployArgs, playbook *def.Playbook, client *def.C
318316
defer close(jobs)
319317

320318
for i := 0; i < concurrentSolc; i++ {
321-
if args.Wasm {
322-
go solangRunner(jobs, logger)
323-
} else {
324-
go solcRunner(jobs, logger)
325-
}
319+
go solidityRunner(jobs, logger)
326320
}
327321

328322
for _, job := range playbook.Jobs {
329-
queueCompilerWork(job, playbook, jobs)
323+
queueCompilerWork(job, playbook, jobs, args.Wasm)
330324
}
331325

332326
err = doJobs(playbook, args, client, logger)

execution/config.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ package execution
33
import (
44
"fmt"
55

6+
"github.com/hyperledger/burrow/execution/engine"
7+
68
"github.com/hyperledger/burrow/execution/evm"
79
)
810

@@ -36,16 +38,16 @@ func DefaultExecutionConfig() *ExecutionConfig {
3638

3739
type Option func(*executor)
3840

39-
func VMOptions(vmOptions evm.Options) func(*executor) {
41+
func VMOptions(vmOptions engine.Options) func(*executor) {
4042
return func(exe *executor) {
4143
exe.vmOptions = vmOptions
4244
}
4345
}
4446

4547
func (ec *ExecutionConfig) ExecutionOptions() ([]Option, error) {
4648
var exeOptions []Option
47-
vmOptions := evm.Options{
48-
MemoryProvider: evm.DefaultDynamicMemoryProvider,
49+
vmOptions := engine.Options{
50+
MemoryProvider: engine.DefaultDynamicMemoryProvider,
4951
CallStackMaxDepth: ec.CallStackMaxDepth,
5052
DataStackInitialCapacity: ec.DataStackInitialCapacity,
5153
DataStackMaxDepth: ec.DataStackMaxDepth,

execution/contexts/call_context.go

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,16 @@ package contexts
22

33
import (
44
"fmt"
5+
"math/big"
6+
7+
"github.com/hyperledger/burrow/execution/vms"
58

69
"github.com/hyperledger/burrow/acm"
710
"github.com/hyperledger/burrow/acm/acmstate"
811
"github.com/hyperledger/burrow/crypto"
912
"github.com/hyperledger/burrow/execution/engine"
1013
"github.com/hyperledger/burrow/execution/errors"
11-
"github.com/hyperledger/burrow/execution/evm"
1214
"github.com/hyperledger/burrow/execution/exec"
13-
"github.com/hyperledger/burrow/execution/native"
14-
"github.com/hyperledger/burrow/execution/wasm"
1515
"github.com/hyperledger/burrow/logging"
1616
"github.com/hyperledger/burrow/logging/structure"
1717
"github.com/hyperledger/burrow/txs/payload"
@@ -21,7 +21,7 @@ import (
2121
const GasLimit = uint64(1000000)
2222

2323
type CallContext struct {
24-
EVM *evm.EVM
24+
VMS *vms.VirtualMachines
2525
State acmstate.ReaderWriter
2626
MetadataState acmstate.MetadataReaderWriter
2727
Blockchain engine.Blockchain
@@ -135,7 +135,7 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error
135135
callee = crypto.NewContractAddress(caller, ctx.txe.TxHash)
136136
code = ctx.tx.Data
137137
wcode = ctx.tx.WASM
138-
err := native.CreateAccount(txCache, callee)
138+
err := engine.CreateAccount(txCache, callee)
139139
if err != nil {
140140
return err
141141
}
@@ -144,7 +144,7 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error
144144
"init_code", code)
145145

146146
// store abis
147-
err = native.UpdateContractMeta(txCache, metaCache, callee, ctx.tx.ContractMeta)
147+
err = engine.UpdateContractMeta(txCache, metaCache, callee, ctx.tx.ContractMeta)
148148
if err != nil {
149149
return err
150150
}
@@ -184,19 +184,20 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error
184184
var ret []byte
185185
var err error
186186
txHash := ctx.txe.Envelope.Tx.Hash()
187-
gas := ctx.tx.GasLimit
187+
gas := new(big.Int).SetUint64(ctx.tx.GasLimit)
188188

189189
params := engine.CallParams{
190190
Origin: caller,
191191
Caller: caller,
192192
Callee: callee,
193193
Input: ctx.tx.Data,
194-
Value: value,
195-
Gas: &gas,
194+
Value: *new(big.Int).SetUint64(value),
195+
Gas: gas,
196196
}
197197

198198
if len(wcode) != 0 {
199-
ret, err = wasm.RunWASM(txCache, params, wcode)
199+
// TODO: accept options
200+
ret, err = ctx.VMS.WVM.Execute(txCache, ctx.Blockchain, ctx.txe, params, wcode)
200201
if err != nil {
201202
// Failure. Charge the gas fee. The 'value' was otherwise not transferred.
202203
ctx.Logger.InfoMsg("Error on WASM execution",
@@ -206,7 +207,7 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error
206207
} else {
207208
ctx.Logger.TraceMsg("Successful execution")
208209
if createContract {
209-
err := native.InitWASMCode(txCache, callee, ret)
210+
err := engine.InitWASMCode(txCache, callee, ret)
210211
if err != nil {
211212
return err
212213
}
@@ -218,10 +219,10 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error
218219
}
219220
} else {
220221
// EVM
221-
ctx.EVM.SetNonce(txHash)
222-
ctx.EVM.SetLogger(ctx.Logger.With(structure.TxHashKey, txHash))
222+
ctx.VMS.EVM.SetNonce(txHash)
223+
ctx.VMS.EVM.SetLogger(ctx.Logger.With(structure.TxHashKey, txHash))
223224

224-
ret, err = ctx.EVM.Execute(txCache, ctx.Blockchain, ctx.txe, params, code)
225+
ret, err = ctx.VMS.EVM.Execute(txCache, ctx.Blockchain, ctx.txe, params, code)
225226

226227
if err != nil {
227228
// Failure. Charge the gas fee. The 'value' was otherwise not transferred.
@@ -233,7 +234,7 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error
233234
} else {
234235
ctx.Logger.TraceMsg("Successful execution")
235236
if createContract {
236-
err := native.InitEVMCode(txCache, callee, ret)
237+
err := engine.InitEVMCode(txCache, callee, ret)
237238
if err != nil {
238239
return err
239240
}
@@ -245,7 +246,8 @@ func (ctx *CallContext) Deliver(inAcc, outAcc *acm.Account, value uint64) error
245246
}
246247
ctx.CallEvents(err)
247248
}
248-
ctx.txe.Return(ret, ctx.tx.GasLimit-gas)
249+
// Gas starts life as a uint64 and should only been reduced (used up) over a transaction so .Uint64() is safe
250+
ctx.txe.Return(ret, ctx.tx.GasLimit-gas.Uint64())
249251
// Create a receipt from the ret and whether it erred.
250252
ctx.Logger.TraceMsg("VM Call complete",
251253
"caller", caller,

execution/defaults/options.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package defaults
2+
3+
import (
4+
"github.com/hyperledger/burrow/execution/engine"
5+
"github.com/hyperledger/burrow/execution/native"
6+
"github.com/hyperledger/burrow/logging"
7+
)
8+
9+
func CompleteOptions(options engine.Options) engine.Options {
10+
// Set defaults
11+
if options.MemoryProvider == nil {
12+
options.MemoryProvider = engine.DefaultDynamicMemoryProvider
13+
}
14+
if options.Logger == nil {
15+
options.Logger = logging.NewNoopLogger()
16+
}
17+
if options.Natives == nil {
18+
options.Natives = native.MustDefaultNatives()
19+
}
20+
return options
21+
}

0 commit comments

Comments
 (0)