1
1
package wasm
2
2
3
3
import (
4
+ "encoding/binary"
4
5
"fmt"
5
6
6
7
"github.com/hyperledger/burrow/acm/acmstate"
7
8
burrow_binary "github.com/hyperledger/burrow/binary"
8
9
"github.com/hyperledger/burrow/crypto"
10
+ "github.com/hyperledger/burrow/execution/engine"
9
11
"github.com/hyperledger/burrow/execution/errors"
10
12
"github.com/perlin-network/life/exec"
11
13
)
12
14
13
15
type execContext struct {
14
16
errors.Maybe
15
- address crypto.Address
16
- input []byte
17
- output []byte
18
- state acmstate.ReaderWriter
17
+ code []byte
18
+ output []byte
19
+ returnData []byte
20
+ params engine.CallParams
21
+ state acmstate.ReaderWriter
19
22
}
20
23
21
24
// Implements ewasm, see https://github.com/ewasm/design
22
25
23
26
// RunWASM creates a WASM VM, and executes the given WASM contract code
24
- func RunWASM (state acmstate.ReaderWriter , address crypto. Address , createContract bool , wasm , input []byte ) (output []byte , cerr error ) {
27
+ func RunWASM (state acmstate.ReaderWriter , params engine. CallParams , wasm []byte ) (output []byte , cerr error ) {
25
28
const errHeader = "ewasm"
26
29
defer func () {
27
30
if r := recover (); r != nil {
@@ -32,14 +35,14 @@ func RunWASM(state acmstate.ReaderWriter, address crypto.Address, createContract
32
35
// WASM
33
36
config := exec.VMConfig {
34
37
DisableFloatingPoint : true ,
35
- MaxMemoryPages : 2 ,
36
- DefaultMemoryPages : 2 ,
38
+ MaxMemoryPages : 16 ,
39
+ DefaultMemoryPages : 16 ,
37
40
}
38
41
39
42
execContext := execContext {
40
- address : address ,
41
- state : state ,
42
- input : input ,
43
+ params : params ,
44
+ code : wasm ,
45
+ state : state ,
43
46
}
44
47
45
48
// panics in ResolveFunc() will be recovered for us, no need for our own
@@ -72,7 +75,7 @@ func (e *execContext) ResolveFunc(module, field string) exec.FunctionImport {
72
75
switch field {
73
76
case "getCallDataSize" :
74
77
return func (vm * exec.VirtualMachine ) int64 {
75
- return int64 (len (e .input ))
78
+ return int64 (len (e .params . Input ))
76
79
}
77
80
78
81
case "callDataCopy" :
@@ -82,7 +85,43 @@ func (e *execContext) ResolveFunc(module, field string) exec.FunctionImport {
82
85
dataLen := int (uint32 (vm .GetCurrentFrame ().Locals [2 ]))
83
86
84
87
if dataLen > 0 {
85
- copy (vm .Memory [destPtr :], e .input [dataOffset :dataOffset + dataLen ])
88
+ copy (vm .Memory [destPtr :], e .params .Input [dataOffset :dataOffset + dataLen ])
89
+ }
90
+
91
+ return 0
92
+ }
93
+
94
+ case "getReturnDataSize" :
95
+ return func (vm * exec.VirtualMachine ) int64 {
96
+ return int64 (len (e .returnData ))
97
+ }
98
+
99
+ case "returnDataCopy" :
100
+ return func (vm * exec.VirtualMachine ) int64 {
101
+ destPtr := int (uint32 (vm .GetCurrentFrame ().Locals [0 ]))
102
+ dataOffset := int (uint32 (vm .GetCurrentFrame ().Locals [1 ]))
103
+ dataLen := int (uint32 (vm .GetCurrentFrame ().Locals [2 ]))
104
+
105
+ if dataLen > 0 {
106
+ copy (vm .Memory [destPtr :], e .returnData [dataOffset :dataOffset + dataLen ])
107
+ }
108
+
109
+ return 0
110
+ }
111
+
112
+ case "getCodeSize" :
113
+ return func (vm * exec.VirtualMachine ) int64 {
114
+ return int64 (len (e .code ))
115
+ }
116
+
117
+ case "codeCopy" :
118
+ return func (vm * exec.VirtualMachine ) int64 {
119
+ destPtr := int (uint32 (vm .GetCurrentFrame ().Locals [0 ]))
120
+ dataOffset := int (uint32 (vm .GetCurrentFrame ().Locals [1 ]))
121
+ dataLen := int (uint32 (vm .GetCurrentFrame ().Locals [2 ]))
122
+
123
+ if dataLen > 0 {
124
+ copy (vm .Memory [destPtr :], e .code [dataOffset :dataOffset + dataLen ])
86
125
}
87
126
88
127
return 0
@@ -97,7 +136,7 @@ func (e *execContext) ResolveFunc(module, field string) exec.FunctionImport {
97
136
98
137
copy (key [:], vm .Memory [keyPtr :keyPtr + 32 ])
99
138
100
- e .Void (e .state .SetStorage (e .address , key , vm .Memory [dataPtr :dataPtr + 32 ]))
139
+ e .Void (e .state .SetStorage (e .params . Callee , key , vm .Memory [dataPtr :dataPtr + 32 ]))
101
140
return 0
102
141
}
103
142
@@ -111,7 +150,7 @@ func (e *execContext) ResolveFunc(module, field string) exec.FunctionImport {
111
150
112
151
copy (key [:], vm .Memory [keyPtr :keyPtr + 32 ])
113
152
114
- val := e .Bytes (e .state .GetStorage (e .address , key ))
153
+ val := e .Bytes (e .state .GetStorage (e .params . Callee , key ))
115
154
copy (vm .Memory [dataPtr :], val )
116
155
117
156
return 0
@@ -138,6 +177,51 @@ func (e *execContext) ResolveFunc(module, field string) exec.FunctionImport {
138
177
panic (errors .Codes .ExecutionReverted )
139
178
}
140
179
180
+ case "getAddress" :
181
+ return func (vm * exec.VirtualMachine ) int64 {
182
+ addressPtr := int (uint32 (vm .GetCurrentFrame ().Locals [0 ]))
183
+
184
+ copy (vm .Memory [addressPtr :], e .params .Callee .Bytes ())
185
+
186
+ return 0
187
+ }
188
+
189
+ case "getCallValue" :
190
+ return func (vm * exec.VirtualMachine ) int64 {
191
+
192
+ valuePtr := int (uint32 (vm .GetCurrentFrame ().Locals [0 ]))
193
+
194
+ // ewasm value is little endian 128 bit value
195
+ bs := make ([]byte , 16 )
196
+ binary .LittleEndian .PutUint64 (bs , e .params .Value )
197
+
198
+ copy (vm .Memory [valuePtr :], bs )
199
+
200
+ return 0
201
+ }
202
+
203
+ case "getExternalBalance" :
204
+ return func (vm * exec.VirtualMachine ) int64 {
205
+ addressPtr := int (uint32 (vm .GetCurrentFrame ().Locals [0 ]))
206
+ balancePtr := int (uint32 (vm .GetCurrentFrame ().Locals [1 ]))
207
+
208
+ address := crypto.Address {}
209
+
210
+ copy (address [:], vm .Memory [addressPtr :addressPtr + crypto .AddressLength ])
211
+ acc , err := e .state .GetAccount (address )
212
+ if err != nil {
213
+ panic (errors .Codes .InvalidAddress )
214
+ }
215
+
216
+ // ewasm value is little endian 128 bit value
217
+ bs := make ([]byte , 16 )
218
+ binary .LittleEndian .PutUint64 (bs , acc .Balance )
219
+
220
+ copy (vm .Memory [balancePtr :], bs )
221
+
222
+ return 0
223
+ }
224
+
141
225
default :
142
226
panic (fmt .Sprintf ("unknown function %s" , field ))
143
227
}
0 commit comments