Skip to content

Commit 9931793

Browse files
committed
Merge branch 'master' of https://github.com/tinychain/tiny-wasm
2 parents 3a4de67 + 81fbdfa commit 9931793

13 files changed

+332
-83
lines changed

common.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package tiny_wasm
1+
package tinywasm
22

33
// Size (in bytes) of a u256
44
const u256Len = 32
@@ -9,5 +9,8 @@ const u128Len = 16
99
// Max recursion depth for contracts
1010
const maxCallDepth = 1024
1111

12+
// Max bytecode to permit for a contract
13+
const MaxCodeSize = 24576
14+
1215
// Address of the sentinel (metering) contract
13-
const sentinelContractAddress = "0x000000000000000000000000000000000000000a"
16+
const sentinelContractAddress = "0x000000000000000000000000000000000000000a"

context.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// You should have received a copy of the GNU Lesser General Public License
1515
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
1616

17-
package tiny_wasm
17+
package tinywasm
1818

1919
import (
2020
"github.com/tinychain/tinychain/common"

contract.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// You should have received a copy of the GNU Lesser General Public License
1515
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
1616

17-
package tiny_wasm
17+
package tinywasm
1818

1919
import (
2020
"github.com/tinychain/tinychain/common"

contracts.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// You should have received a copy of the GNU Lesser General Public License
1515
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
1616

17-
package tiny_wasm
17+
package tinywasm
1818

1919
import (
2020
"crypto/sha256"

eei_api.go

+171-26
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
package tiny_wasm
1+
package tinywasm
22

33
import (
44
"fmt"
55
"github.com/tinychain/tiny-wasm/wagon/exec"
66
"github.com/tinychain/tinychain/common"
7+
"github.com/tinychain/tinychain/core/types"
78
"math/big"
89
)
910

@@ -31,6 +32,7 @@ const (
3132
GasCostSSet = 20000
3233
GasCostSReset = 5000
3334
GasRefundSClear = 15000
35+
GasSstoreClear = 5000
3436
GasRefundSelfDestruct = 24000
3537
GasCostCreate = 32000
3638
GasCostCall = 700
@@ -41,6 +43,7 @@ const (
4143
GasCostLogTopic = 375
4244
GasCostCopy = 3
4345
GasCostBlockHash = 800
46+
GasCostCreateData = 200
4447

4548
GasCostExtcodeSize = 700
4649
GasCostExtcodeCopy = 700
@@ -60,14 +63,14 @@ func (*eeiApi) useGas(p *exec.Process, w *WasmIntptr, amount int64) {
6063

6164
func (*eeiApi) getAddress(p *exec.Process, w *WasmIntptr, resultOffset int32) {
6265
w.useGas(GasCostBase)
63-
p.WriteAt(w.contract.Address().Bytes(), int64(resultOffset))
66+
writeToMem(p, w.contract.Address().Bytes(), resultOffset)
6467
}
6568

6669
func (*eeiApi) getExternalBalance(p *exec.Process, w *WasmIntptr, addressOffset, resultOffset int32) {
6770
w.useGas(GasCostBalance)
6871
addr := loadFromMem(p, addressOffset, common.AddressLength)
6972
balance := w.evm.StateDB.GetBalance(common.BytesToAddress(addr))
70-
p.WriteAt(balance.Bytes(), int64(resultOffset))
73+
writeToMem(p, balance.Bytes(), resultOffset)
7174
}
7275

7376
// getBlockHash gets the hash of one of the 256 most recent completed blocks.
@@ -78,7 +81,7 @@ func (*eeiApi) getBlockHash(p *exec.Process, w *WasmIntptr, number int64, result
7881
return ErrEEICallFailure
7982
}
8083
hash := w.evm.Context.GetHash(uint64(number))
81-
p.WriteAt(hash.Bytes(), int64(resultOffset))
84+
writeToMem(p, hash.Bytes(), resultOffset)
8285
return EEICallSuccess
8386

8487
}
@@ -108,8 +111,8 @@ func (*eeiApi) call(p *exec.Process, w *WasmIntptr, gas int64, addressOffset, va
108111
}
109112

110113
func (*eeiApi) callDataCopy(p *exec.Process, w *WasmIntptr, resultOffset, dataOffset, length int32) {
111-
w.useGas(GasCostCopy * uint64(length))
112-
p.WriteAt(w.contract.Input[dataOffset:dataOffset+length], int64(resultOffset))
114+
w.useGas(GasCostVeryLow + GasCostCopy*uint64(length))
115+
writeToMem(p, w.contract.Input[dataOffset:dataOffset+length], resultOffset)
113116
}
114117

115118
func (*eeiApi) getCallDataSize(p *exec.Process, w *WasmIntptr) int32 {
@@ -159,81 +162,195 @@ func (*eeiApi) callStatic(p *exec.Process, w *WasmIntptr, gas int64, addressOffs
159162
}
160163

161164
func (*eeiApi) storageStore(p *exec.Process, w *WasmIntptr, pathOffset, valueOffset int32) {
165+
if w.IsReadOnly() {
166+
panic("Static mode violation in storageStore")
167+
}
168+
169+
key := common.BytesToHash(loadFromMem(p, pathOffset, u256Len))
170+
val := loadFromMem(p, pathOffset, u256Len)
171+
172+
oldVal := w.StateDB().GetState(w.contract.Address(), key)
173+
174+
// This checks for 3 scenario's and calculates gas accordingly:
175+
//
176+
// 1. From a zero-value address to a non-zero value (NEW VALUE)
177+
// 2. From a non-zero value address to a zero-value address (DELETE)
178+
// 3. From a non-zero to a non-zero (CHANGE)
179+
switch {
180+
case oldVal == nil && new(big.Int).SetBytes(val).Sign() != 0: // 0 => non 0
181+
w.useGas(GasCostSSet)
182+
case oldVal != nil && new(big.Int).SetBytes(val).Sign() == 0: // non 0 => 0
183+
w.useGas(GasSstoreClear)
184+
default: // non 0 => non 0 (or 0 => 0)
185+
w.useGas(GasCostSReset)
186+
}
162187

188+
w.StateDB().SetState(w.contract.Address(), key, val)
163189
}
164190

165191
func (*eeiApi) storageLoad(p *exec.Process, w *WasmIntptr, pathOffset, resultOffset int32) {
166-
192+
w.useGas(GasCostSLoad)
193+
key := common.BytesToHash(loadFromMem(p, pathOffset, u256Len))
194+
val := w.StateDB().GetState(w.contract.Address(), key)
195+
writeToMem(p, val, resultOffset)
167196
}
168197

169198
func (*eeiApi) getCaller(p *exec.Process, w *WasmIntptr, resultOffset int32) {
170-
199+
w.useGas(GasCostBase)
200+
addr := w.contract.CallerAddress
201+
writeToMem(p, addr.Bytes(), resultOffset)
171202
}
172203

173204
func (*eeiApi) getCallValue(p *exec.Process, w *WasmIntptr, resultOffset int32) {
174-
205+
w.useGas(GasCostBase)
206+
writeToMem(p, w.contract.Value().Bytes(), resultOffset)
175207
}
176208

177209
func (*eeiApi) codeCopy(p *exec.Process, w *WasmIntptr, resultOffset, codeOffset, length int32) {
178-
210+
w.useGas(GasCostVeryLow + GasCostCopy*uint64(length))
211+
writeToMem(p, w.contract.Code[codeOffset:codeOffset+length], resultOffset)
179212
}
180213

181214
func (*eeiApi) getCodeSize(p *exec.Process, w *WasmIntptr) int32 {
182-
215+
w.useGas(GasCostBase)
216+
return int32(len(w.contract.Code))
183217
}
184218

185219
func (*eeiApi) getBlockCoinbase(p *exec.Process, w *WasmIntptr, resultOffset int32) {
186-
220+
w.useGas(GasCostBase)
221+
writeToMem(p, w.evm.Coinbase().Bytes(), resultOffset)
187222
}
188223

189-
func (*eeiApi) create(p *exec.Process, w *WasmIntptr, valueOffset, dataOffset, length, resultOffset int32) {
224+
func (*eeiApi) create(p *exec.Process, w *WasmIntptr, valueOffset, dataOffset, length, resultOffset int32) int32 {
225+
w.useGas(GasCostCreate)
226+
227+
oldVM := w.vm
228+
oldContract := w.contract
229+
defer func() {
230+
w.vm = oldVM
231+
w.contract = oldContract
232+
}()
190233

234+
w.terminateType = TerminateInvalid
235+
236+
if int(valueOffset)+u128Len > len(w.vm.Memory()) {
237+
return ErrEEICallFailure
238+
}
239+
240+
if int(dataOffset+length) > len(w.vm.Memory()) {
241+
return ErrEEICallFailure
242+
}
243+
244+
code := loadFromMem(p, dataOffset, length)
245+
val := loadFromMem(p, valueOffset, u128Len)
246+
247+
w.terminateType = TerminateFinish
248+
249+
// EIP150 says that the calling contract should keep 1/64th of the
250+
// leftover gas.
251+
gas := w.contract.Gas - w.contract.Gas/64
252+
_, addr, leftGas, _ := w.evm.Create(w.contract, code, gas, new(big.Int).SetBytes(val))
253+
254+
switch w.terminateType {
255+
case TerminateFinish:
256+
oldContract.Gas += leftGas
257+
p.WriteAt(addr.Bytes(), int64(resultOffset))
258+
return EEICallSuccess
259+
case TerminateRevert:
260+
oldContract.Gas += gas
261+
return ErrEEICallRevert
262+
default:
263+
oldContract.Gas += leftGas
264+
return ErrEEICallFailure
265+
}
191266
}
192267

193268
func (*eeiApi) getBlockDifficulty(p *exec.Process, w *WasmIntptr, resultOffset int32) {
194269

195270
}
196271

197272
func (*eeiApi) externalCodeCopy(p *exec.Process, w *WasmIntptr, addressOffset, resultOffset, codeOffset, length int32) {
273+
addr := common.BytesToAddress(loadFromMem(p, addressOffset, common.AddressLength))
274+
code := w.StateDB().GetCode(addr)
198275

276+
w.useGas(GasCostVeryLow + GasCostCopy*uint64(len(code)))
277+
writeToMem(p, code[codeOffset:codeOffset+length], resultOffset)
199278
}
200279

201280
func (*eeiApi) getExternalCodeSize(p *exec.Process, w *WasmIntptr, addressOffset int32) int32 {
202-
281+
w.useGas(GasCostExtCode)
282+
addr := common.BytesToAddress(loadFromMem(p, addressOffset, common.AddressLength))
283+
return int32(w.StateDB().GetCodeSize(addr))
203284
}
204285

205286
func (*eeiApi) getGasLeft(p *exec.Process, w *WasmIntptr) int64 {
206-
287+
w.useGas(GasCostBase)
288+
return int64(w.contract.Gas)
207289
}
208290

209291
func (*eeiApi) getBlockGasLimit(p *exec.Process, w *WasmIntptr) int64 {
210-
292+
w.useGas(GasCostBase)
293+
return int64(w.evm.GasLimit)
211294
}
212295

213296
func (*eeiApi) getTxGasPrice(p *exec.Process, w *WasmIntptr, valueOffset int32) {
214-
297+
w.useGas(GasCostBase)
298+
writeToMem(p, w.evm.GasPrice.Bytes(), valueOffset)
215299
}
216300

217-
func (*eeiApi) log(p *exec.Process, w *WasmIntptr, dataOffset, length, numberOfTopics, topic1, topic2, topic3, topic4 int32) {
301+
func (*eeiApi) log(p *exec.Process, w *WasmIntptr, dataOffset, dataLength, numberOfTopics, topic1, topic2, topic3, topic4 int32) {
302+
w.useGas(GasCostLog + GasCostLogData*uint64(dataLength) + GasCostLogTopic*uint64(numberOfTopics))
218303

304+
if numberOfTopics > 4 || numberOfTopics < 0 {
305+
w.terminateType = TerminateInvalid
306+
p.Terminate()
307+
}
308+
309+
data := loadFromMem(p, dataOffset, dataLength)
310+
topics := make([]common.Hash, numberOfTopics)
311+
312+
switch numberOfTopics {
313+
case 4:
314+
topics[3] = common.BytesToHash(loadFromMem(p, topic4, u256Len))
315+
fallthrough
316+
case 3:
317+
topics[2] = common.BytesToHash(loadFromMem(p, topic3, u256Len))
318+
fallthrough
319+
case 2:
320+
topics[1] = common.BytesToHash(loadFromMem(p, topic2, u256Len))
321+
fallthrough
322+
case 1:
323+
topics[0] = common.BytesToHash(loadFromMem(p, topic1, u256Len))
324+
default:
325+
return
326+
}
327+
328+
w.StateDB().AddLog(&types.Log{
329+
Address: w.contract.Address(),
330+
Topics: topics,
331+
Data: data,
332+
BlockHeight: w.evm.BlockHeight.Uint64(),
333+
})
219334
}
220335

221336
func (*eeiApi) getBlockNumber(p *exec.Process, w *WasmIntptr) int64 {
222-
337+
w.useGas(GasCostBase)
338+
return w.evm.BlockHeight.Int64()
223339
}
224340

225341
func (*eeiApi) getTxOrigin(p *exec.Process, w *WasmIntptr, resultOffset int32) {
226-
342+
w.useGas(GasCostBase)
343+
writeToMem(p, w.evm.Origin.Bytes(), resultOffset)
227344
}
228345

229346
func (*eeiApi) finish(p *exec.Process, w *WasmIntptr, dataOffset, length int32) {
230-
w.returnData = loadFromMem(p, dataOffset, int(length))
347+
w.returnData = loadFromMem(p, dataOffset, length)
231348
w.terminateType = TerminateFinish
232349
p.Terminate()
233350
}
234351

235352
func (*eeiApi) revert(p *exec.Process, w *WasmIntptr, dataOffset, length int32) {
236-
w.returnData = loadFromMem(p, dataOffset, int(length))
353+
w.returnData = loadFromMem(p, dataOffset, length)
237354
w.terminateType = TerminateRevert
238355
p.Terminate()
239356
}
@@ -245,21 +362,48 @@ func (*eeiApi) getReturnDataSize(p *exec.Process, w *WasmIntptr) int32 {
245362

246363
func (*eeiApi) returnDataCopy(p *exec.Process, w *WasmIntptr, resultOffset, dataOffset, length int32) {
247364
w.useGas(GasCostCopy * uint64(length))
248-
p.WriteAt(loadFromMem(p, dataOffset, int(length)), int64(resultOffset))
365+
writeToMem(p, w.returnData[dataOffset:dataOffset+length], resultOffset)
249366
}
250367

251368
func (*eeiApi) selfDestruct(p *exec.Process, w *WasmIntptr, addressOffset int32) {
369+
addr := common.BytesToAddress(loadFromMem(p, addressOffset, common.AddressLength))
370+
balance := w.StateDB().GetBalance(w.contract.Address())
371+
372+
totalGas := GasCostSuicide
373+
// If the target address dose not exist, add the account creation cost
374+
if !w.StateDB().Exist(addr) {
375+
totalGas += GasCostCreateBySuicide
376+
}
377+
w.StateDB().AddBalance(addr, balance)
378+
w.useGas(uint64(totalGas))
379+
w.StateDB().Suicide(w.contract.Address())
252380

381+
w.terminateType = TerminateSuicide
382+
p.Terminate()
253383
}
254384

255385
func (*eeiApi) getBlockTimestamp(p *exec.Process, w *WasmIntptr) int64 {
386+
w.useGas(GasCostBase)
387+
return w.evm.Time.Int64()
388+
}
256389

390+
// swapEndian swap big endian to little endian or reverse.
391+
func swapEndian(src []byte) []byte {
392+
rect := make([]byte, len(src))
393+
for i, b := range src {
394+
rect[len(src)-i-1] = b
395+
}
396+
return rect
257397
}
258398

259-
func loadFromMem(p *exec.Process, offset int32, size int) []byte {
399+
func loadFromMem(p *exec.Process, offset int32, size int32) []byte {
260400
b := make([]byte, size)
261401
p.ReadAt(b, int64(offset))
262-
return b
402+
return swapEndian(b)
403+
}
404+
405+
func writeToMem(p *exec.Process, data []byte, offset int32) (int, error) {
406+
return p.WriteAt(swapEndian(data), int64(offset))
263407
}
264408

265409
func getCallParams(p *exec.Process, w *WasmIntptr, addressOffset, valueOffset, dataOffset, dataLength int32) (addr common.Address, value *big.Int, input []byte) {
@@ -277,11 +421,12 @@ func getCallParams(p *exec.Process, w *WasmIntptr, addressOffset, valueOffset, d
277421
}
278422

279423
// Get the input data from mem
280-
input = loadFromMem(p, dataOffset, int(dataLength))
424+
input = loadFromMem(p, dataOffset, dataLength)
281425

282426
return
283427
}
284428

429+
// call provides a common call function for `call`, `callCode` and `callDelegate` of EEI api.
285430
func call(w *WasmIntptr, toContract *Contract, input []byte, snapshot int) int32 {
286431
if w.evm.depth > maxCallDepth {
287432
// Clear all gas of contract

0 commit comments

Comments
 (0)