55 "fmt"
66 "math/big"
77
8+ "github.com/hyperledger/burrow/execution/evm"
89 "github.com/hyperledger/burrow/execution/exec"
910
1011 bin "github.com/hyperledger/burrow/binary"
@@ -84,6 +85,12 @@ func (ctx *context) ResolveFunc(module, field string) lifeExec.FunctionImport {
8485
8586 switch field {
8687 case "call" :
88+ fallthrough
89+ case "callCode" :
90+ fallthrough
91+ case "callDelegate" :
92+ fallthrough
93+ case "callStatic" :
8794 return func (vm * lifeExec.VirtualMachine ) int64 {
8895 gasLimit := big .NewInt (vm .GetCurrentFrame ().Locals [0 ])
8996 addressPtr := uint32 (vm .GetCurrentFrame ().Locals [1 ])
@@ -97,10 +104,25 @@ func (ctx *context) ResolveFunc(module, field string) lifeExec.FunctionImport {
97104 // TODO: is this guaranteed to be okay? Should be avoid panic here if out of bounds?
98105 value := bin .BigIntFromLittleEndianBytes (vm .Memory [valuePtr : valuePtr + ValueByteSize ])
99106
107+ var callType exec.CallType
108+
109+ switch field {
110+ case "call" :
111+ callType = exec .CallTypeCall
112+ case "callCode" :
113+ callType = exec .CallTypeCode
114+ case "callStatic" :
115+ callType = exec .CallTypeStatic
116+ case "callDeletegate" :
117+ callType = exec .CallTypeDelegate
118+ default :
119+ panic ("should not happen" )
120+ }
121+
100122 var err error
101123 ctx .returnData , err = engine .CallFromSite (ctx .state , ctx .vm .externalDispatcher , ctx .params ,
102124 engine.CallParams {
103- CallType : exec . CallTypeCall ,
125+ CallType : callType ,
104126 Callee : target ,
105127 Input : vm .Memory [dataPtr : dataPtr + dataLen ],
106128 Value : * value ,
@@ -121,7 +143,6 @@ func (ctx *context) ResolveFunc(module, field string) lifeExec.FunctionImport {
121143 // Spec says return 1 for error, but not sure when to do that (as opposed to abort):
122144 // https://github.com/ewasm/design/blob/master/eth_interface.md#call
123145 panic (err )
124- return Error
125146 }
126147 return Success
127148 }
@@ -279,6 +300,111 @@ func (ctx *context) ResolveFunc(module, field string) lifeExec.FunctionImport {
279300 return Success
280301 }
281302
303+ case "getBlockTimestamp" :
304+ return func (vm * lifeExec.VirtualMachine ) int64 {
305+ return int64 (ctx .state .Blockchain .LastBlockTime ().Unix ())
306+ }
307+
308+ case "getBlockNumber" :
309+ return func (vm * lifeExec.VirtualMachine ) int64 {
310+ return int64 (ctx .state .Blockchain .LastBlockHeight ())
311+ }
312+
313+ case "getTxOrigin" :
314+ return func (vm * lifeExec.VirtualMachine ) int64 {
315+ addressPtr := int (uint32 (vm .GetCurrentFrame ().Locals [0 ]))
316+
317+ copy (vm .Memory [addressPtr :addressPtr + crypto .AddressLength ], ctx .params .Origin .Bytes ())
318+
319+ return Success
320+ }
321+
322+ case "getCaller" :
323+ return func (vm * lifeExec.VirtualMachine ) int64 {
324+ addressPtr := int (uint32 (vm .GetCurrentFrame ().Locals [0 ]))
325+
326+ copy (vm .Memory [addressPtr :addressPtr + crypto .AddressLength ], ctx .params .Caller .Bytes ())
327+
328+ return Success
329+ }
330+
331+ case "getBlockGasLimit" :
332+ return func (vm * lifeExec.VirtualMachine ) int64 {
333+ return ctx .params .Gas .Int64 ()
334+ }
335+
336+ case "getGasLeft" :
337+ return func (vm * lifeExec.VirtualMachine ) int64 {
338+ // do the same as EVM
339+ return ctx .params .Gas .Int64 ()
340+ }
341+
342+ case "getBlockCoinbase" :
343+ return func (vm * lifeExec.VirtualMachine ) int64 {
344+ // do the same as EVM
345+ addressPtr := int (uint32 (vm .GetCurrentFrame ().Locals [0 ]))
346+
347+ copy (vm .Memory [addressPtr :addressPtr + crypto .AddressLength ], crypto .ZeroAddress .Bytes ())
348+
349+ return Success
350+ }
351+
352+ case "getBlockHash" :
353+ return func (vm * lifeExec.VirtualMachine ) int64 {
354+ blockNumber := uint64 (vm .GetCurrentFrame ().Locals [0 ])
355+ hashPtr := int (vm .GetCurrentFrame ().Locals [1 ])
356+
357+ lastBlockHeight := ctx .state .Blockchain .LastBlockHeight ()
358+ if blockNumber >= lastBlockHeight {
359+ panic (fmt .Sprintf (" => attempted to get block hash of a non-existent block: %v" , blockNumber ))
360+ } else if lastBlockHeight - blockNumber > evm .MaximumAllowedBlockLookBack {
361+ panic (fmt .Sprintf (" => attempted to get block hash of a block %d outside of the allowed range " +
362+ "(must be within %d blocks)" , blockNumber , evm .MaximumAllowedBlockLookBack ))
363+ } else {
364+ hash , err := ctx .state .Blockchain .BlockHash (blockNumber )
365+ if err != nil {
366+ panic (fmt .Sprintf (" => blockhash failed: %v" , err ))
367+ }
368+
369+ copy (vm .Memory [hashPtr :hashPtr + len (hash )], hash )
370+ }
371+
372+ return Success
373+ }
374+
375+ case "log" :
376+ return func (vm * lifeExec.VirtualMachine ) int64 {
377+ dataPtr := int (uint32 (vm .GetCurrentFrame ().Locals [0 ]))
378+ dataLen := int (uint32 (vm .GetCurrentFrame ().Locals [1 ]))
379+
380+ data := vm .Memory [dataPtr : dataPtr + dataLen ]
381+
382+ topicCount := uint32 (vm .GetCurrentFrame ().Locals [2 ])
383+ topics := make ([]bin.Word256 , topicCount )
384+
385+ if topicCount > 4 {
386+ panic (fmt .Sprintf ("%d topics not permitted" , topicCount ))
387+ }
388+
389+ for i := uint32 (0 ); i < topicCount ; i ++ {
390+ topicPtr := int (uint32 (vm .GetCurrentFrame ().Locals [3 + i ]))
391+ topicData := vm .Memory [topicPtr : topicPtr + bin .Word256Bytes ]
392+ topics [i ] = bin .RightPadWord256 (topicData )
393+ }
394+
395+ err := ctx .state .EventSink .Log (& exec.LogEvent {
396+ Address : ctx .params .Callee ,
397+ Topics : topics ,
398+ Data : data ,
399+ })
400+
401+ if err != nil {
402+ panic (fmt .Sprintf (" => log failed: %v" , err ))
403+ }
404+
405+ return Success
406+ }
407+
282408 default :
283409 panic (fmt .Sprintf ("unknown function %s" , field ))
284410 }
0 commit comments