burrow, EVM precompiled contracts

There are several precompiled functions in Burrow EVM:

  • sha256 @0x0000000000000000000000000000000000000002
  • ripemd160 @0x0000000000000000000000000000000000000003
  • identityFunc @0x0000000000000000000000000000000000000004
  • expModFunc @0x0000000000000000000000000000000000000005

Native Contract

  • Permission @0x0A758FEB535243577C1A79AE55BED8CA03E226EC

Permission can be accessed at 0x0A758FEB535243577C1A79AE55BED8CA03E226EC.

It has serveral functions:

  • addRole
  • removeRole
  • hasRole
  • setBase
  • unsetBase
  • hasBase
  • setGlobal

Native Contract Call:

// Dispatch is designed to be called from the EVM once a native contract
// has been selected.
func (c *Contract) Call(state engine.State, params engine.CallParams) (output []byte, err error) {
	if len(params.Input) < abi.FunctionIDSize {
		return nil, errors.Errorf(errors.Codes.NativeFunction,
			"Burrow Native dispatch requires a 4-byte function identifier but arguments are only %v bytes long",
			len(params.Input))
	}

	var id abi.FunctionID
	copy(id[:], params.Input)
	function, err := c.FunctionByID(id)
	if err != nil {
		return nil, err
	}

	params.Input = params.Input[abi.FunctionIDSize:]

	return function.Call(state, params)
}

Call stack:

github.com/hyperledger/burrow/execution/native.hasRole at permissions.go:229
runtime.call256 at asm_amd64.s:542
reflect.Value.call at value.go:460
reflect.Value.Call at value.go:321
github.com/hyperledger/burrow/execution/native.(*Function).execute at function.go:106
github.com/hyperledger/burrow/execution/native.(*Function).execute-fm at function.go:76
github.com/hyperledger/burrow/execution/native.Call at call.go:17
github.com/hyperledger/burrow/execution/native.(*Function).Call at function.go:73
github.com/hyperledger/burrow/execution/native.(*Contract).Call at contract.go:113
github.com/hyperledger/burrow/execution/evm.(*Contract).execute at contract.go:775
github.com/hyperledger/burrow/execution/evm.(*Contract).execute-fm at contract.go:36
github.com/hyperledger/burrow/execution/native.Call at call.go:17
github.com/hyperledger/burrow/execution/evm.(*Contract).Call at contract.go:32
github.com/hyperledger/burrow/execution/evm.(*EVM).Execute at evm.go:87
github.com/hyperledger/burrow/execution/contexts.(*CallContext).Deliver at call_context.go:222
github.com/hyperledger/burrow/execution/contexts.(*CallContext).Execute at call_context.go:49
github.com/hyperledger/burrow/execution.CallSim at simulated_call.go:42
github.com/hyperledger/burrow/rpc/rpctransact.(*transactServer).CallTxSim at transact_server.go:108
github.com/hyperledger/burrow/rpc/rpctransact._Transact_CallTxSim_Handler.func1 at rpctransact.pb.go:613
github.com/hyperledger/burrow/rpc.unaryInterceptor.func1 at grpc.go:104
github.com/hyperledger/burrow/rpc/rpctransact._Transact_CallTxSim_Handler at rpctransact.pb.go:615
google.golang.org/grpc.(*Server).processUnaryRPC at server.go:1024
google.golang.org/grpc.(*Server).handleStream at server.go:1313
google.golang.org/grpc.(*Server).serveStreams.func1.1 at server.go:722
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
google.golang.org/grpc.(*Server).serveStreams.func1 at server.go:720

Precompiled Native Functions

When executing the bytecode, EVM will try to dispatch the contact call for any opCode of Call/DelegateCall/STaticCall/CallCode, as below:

returnData, callErr = c.Dispatch(acc).Call(childState, calleeParams)

calleeParams are constructed from Stack, and acc is the address of the callee contract, which is for example, 0x0000000000000000000000000000000000000002, when it comes to precompiled sha256.

Therefore, c.Dispatch(acc) will look the external dispatcher and locate the callable Function of sha256Func:

callable = {github.com/hyperledger/burrow/execution/engine.Callable | *github.com/hyperledger/burrow/execution/native.Function} 
	 Comment = {string} "Compute the sha256 hash of input"
	 PermFlag = {github.com/hyperledger/burrow/permission.PermFlag} None (0)
	 F = {interface {} | func(github.com/hyperledger/burrow/execution/native.Context) ([]uint8, error)} github.com/hyperledger/burrow/execution/native.sha256Func
	 contractName = {string} ""
	 name = {string} "sha256Func"
	 abi = {*github.com/hyperledger/burrow/execution/evm/abi.FunctionSpec} nil
	 address = {github.com/hyperledger/burrow/crypto.Address} len:20
	 externals = {github.com/hyperledger/burrow/execution/engine.Dispatcher | github.com/hyperledger/burrow/execution/engine.Dispatchers} len:1, cap:1
	 logger = {*github.com/hyperledger/burrow/logging.Logger} nil

See Dispatch() for more details:

func (vm *EVM) Dispatch(acc *acm.Account) engine.Callable {
	// Try external calls then fallback to EVM
	callable := vm.externals.Dispatch(acc)
	if callable != nil {
		return callable
	}
	// This supports empty code calls
	return vm.Contract(acc.EVMCode)
}

sha256 example

Solidity code:

  function testB() public {
    address nnn = 0x0000000000000000000000000000000000000002;  
    nnn.call("123");
	...
  }

call stack

github.com/hyperledger/burrow/execution/native.sha256Func at precompiles.go:63
runtime.call256 at asm_amd64.s:542
reflect.Value.call at value.go:460
reflect.Value.Call at value.go:321
github.com/hyperledger/burrow/execution/native.(*Function).execute at function.go:106
github.com/hyperledger/burrow/execution/native.(*Function).execute-fm at function.go:76
github.com/hyperledger/burrow/execution/native.Call at call.go:17
github.com/hyperledger/burrow/execution/native.(*Function).Call at function.go:73
github.com/hyperledger/burrow/execution/evm.(*Contract).execute at contract.go:775
github.com/hyperledger/burrow/execution/evm.(*Contract).execute-fm at contract.go:36
github.com/hyperledger/burrow/execution/native.Call at call.go:17
github.com/hyperledger/burrow/execution/evm.(*Contract).Call at contract.go:32
github.com/hyperledger/burrow/execution/evm.(*EVM).Execute at evm.go:87
github.com/hyperledger/burrow/execution/contexts.(*CallContext).Deliver at call_context.go:222
github.com/hyperledger/burrow/execution/contexts.(*CallContext).Execute at call_context.go:49
github.com/hyperledger/burrow/execution.(*executor).Execute at execution.go:257
github.com/hyperledger/burrow/consensus/abci.ExecuteTx at execute_tx.go:30
github.com/hyperledger/burrow/consensus/abci.(*App).DeliverTx at app.go:212
github.com/tendermint/tendermint/abci/client.(*localClient).DeliverTxAsync at local_client.go:88
github.com/tendermint/tendermint/proxy.(*appConnConsensus).DeliverTxAsync at app_conn.go:73
github.com/tendermint/tendermint/state.execBlockOnProxyApp at execution.go:293
github.com/tendermint/tendermint/state.(*BlockExecutor).ApplyBlock at execution.go:131
github.com/tendermint/tendermint/consensus.(*State).finalizeCommit at state.go:1431
github.com/tendermint/tendermint/consensus.(*State).tryFinalizeCommit at state.go:1350
github.com/tendermint/tendermint/consensus.(*State).enterCommit.func1 at state.go:1285
github.com/tendermint/tendermint/consensus.(*State).enterCommit at state.go:1322
github.com/tendermint/tendermint/consensus.(*State).addVote at state.go:1819
github.com/tendermint/tendermint/consensus.(*State).tryAddVote at state.go:1642
github.com/tendermint/tendermint/consensus.(*State).handleMsg at state.go:709
github.com/tendermint/tendermint/consensus.(*State).receiveRoutine at state.go:660
runtime.goexit at asm_amd64.s:1357
 - Async stack trace
github.com/tendermint/tendermint/consensus.(*State).OnStart at state.go:335

Call, DelegateCall, StaticCall, CallCode


		case CALL, CALLCODE, DELEGATECALL, STATICCALL: // 0xF1, 0xF2, 0xF4, 0xFA
			returnData = nil

			if maybe.PushError(ensurePermission(st.CallFrame, params.Callee, permission.Call)) {
				continue
			}
			// Pull arguments off stack:
			gasLimit := stack.Pop64()
			target := stack.PopAddress()
			value := params.Value
			// NOTE: for DELEGATECALL value is preserved from the original
			// caller, as such it is not stored on stack as an argument
			// for DELEGATECALL and should not be popped.  Instead previous
			// caller value is used.  for CALL and CALLCODE value is stored
			// on stack and needs to be overwritten from the given value.
			if op != DELEGATECALL && op != STATICCALL {
				value = stack.Pop64()
			}
			// inputs
			inOffset, inSize := stack.PopBigInt(), stack.PopBigInt()
			// outputs
			retOffset := stack.PopBigInt()
			retSize := stack.Pop64()
			c.debugf(" => %v\n", target)

			// Get the arguments from the memory
			// EVM contract
			maybe.PushError(useGasNegative(params.Gas, native.GasGetAccount))
			// since CALL is used also for sending funds,
			// acc may not exist yet. This is an errors.CodedError for
			// CALLCODE, but not for CALL, though I don't think
			// ethereum actually cares
			acc := getAccount(st.CallFrame, maybe, target)
			if acc == nil {
				if op != CALL {
					maybe.PushError(errors.Codes.UnknownAddress)
					continue
				}
				// We're sending funds to a new account so we must create it first
				if maybe.PushError(createAccount(st.CallFrame, params.Callee, target)) {
					continue
				}
				acc = mustGetAccount(st.CallFrame, maybe, target)
			}

			// Establish a stack frame and perform the call
			childCallFrame, err := st.CallFrame.NewFrame()
			if maybe.PushError(err) {
				continue
			}
			childState := engine.State{
				CallFrame:  childCallFrame,
				Blockchain: st.Blockchain,
				EventSink:  st.EventSink,
			}
			// Ensure that gasLimit is reasonable
			if *params.Gas < gasLimit {
				// EIP150 - the 63/64 rule - rather than errors.CodedError we pass this specified fraction of the total available gas
				gasLimit = *params.Gas - *params.Gas/64
			}
			// NOTE: we will return any used gas later.
			*params.Gas -= gasLimit

			// Setup callee params for call type

			calleeParams := engine.CallParams{
				Origin: params.Origin,
				Input:  memory.Read(inOffset, inSize),
				Value:  value,
				Gas:    &gasLimit,
			}

			// Set up the caller/callee context
			switch op {
			case CALL:
				// Calls contract at target from this contract normally
				// Value: transferred
				// Caller: this contract
				// Storage: target
				// Code: from target

				calleeParams.CallType = exec.CallTypeCall
				calleeParams.Caller = params.Callee
				calleeParams.Callee = target

			case STATICCALL:
				// Calls contract at target from this contract with no state mutation
				// Value: not transferred
				// Caller: this contract
				// Storage: target (read-only)
				// Code: from target

				calleeParams.CallType = exec.CallTypeStatic
				calleeParams.Caller = params.Callee
				calleeParams.Callee = target

				childState.CallFrame.ReadOnly()
				childState.EventSink = exec.NewLogFreeEventSink(childState.EventSink)

			case CALLCODE:
				// Calling this contract from itself as if it had the code at target
				// Value: transferred
				// Caller: this contract
				// Storage: this contract
				// Code: from target

				calleeParams.CallType = exec.CallTypeCode
				calleeParams.Caller = params.Callee
				calleeParams.Callee = params.Callee

			case DELEGATECALL:
				// Calling this contract from the original caller as if it had the code at target
				// Value: not transferred
				// Caller: original caller
				// Storage: this contract
				// Code: from target

				calleeParams.CallType = exec.CallTypeDelegate
				calleeParams.Caller = params.Caller
				calleeParams.Callee = params.Callee

			default:
				panic(fmt.Errorf("switch statement should be exhaustive so this should not have been reached"))
			}

			var callErr error
			returnData, callErr = c.Dispatch(acc).Call(childState, calleeParams)

			if callErr == nil {
				// Sync error is a hard stop
				maybe.PushError(childState.CallFrame.Sync())
			}

			// Push result
			if callErr != nil {
				c.debugf("error from nested sub-call (depth: %v): %s\n", st.CallFrame.CallStackDepth(), callErr.Error())
				// So we can return nested errors.CodedError if the top level return is an errors.CodedError
				stack.Push(Zero256)

				if errors.GetCode(callErr) == errors.Codes.ExecutionReverted {
					memory.Write(retOffset, RightPadBytes(returnData, int(retSize)))
				}
			} else {
				stack.Push(One256)

				// Should probably only be necessary when there is no return value and
				// returnData is empty, but since EVM expects retSize to be respected this will
				// defensively pad or truncate the portion of returnData to be returned.
				memory.Write(retOffset, RightPadBytes(returnData, int(retSize)))
			}

			// Handle remaining gas.
			*params.Gas += *calleeParams.Gas

			c.debugf("resume %s (%v)\n", params.Callee, params.Gas)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
1444. Elephpotamus Time limit: 0.5 second Memory limit: 64 MB Harry Potter is taking an examination in Care for Magical Creatures. His task is to feed a dwarf elephpotamus. Harry remembers that elephpotamuses are very straightforward and imperturbable. In fact, they are so straightforward that always move along a straight line and they are so imperturbable that only move when attracted by something really tasty. In addition, if an elephpotamus stumbles into a chain of its own footprints, it falls into a stupor and refuses to go anywhere. According to Hagrid, elephpotamuses usually get back home moving along their footprints. This is why they never cross them, otherwise they may get lost. When an elephpotamus sees its footprints, it tries to remember in detail all its movements since leaving home (this is also the reason why they move along straight lines only, this way it is easier to memorize). Basing on this information, the animal calculates in which direction its burrow is situated, then turns and goes straight to it. It takes some (rather large) time for an elephpotamus to perform these calculations. And what some ignoramuses recognize as a stupor is in fact a demonstration of outstanding calculating abilities of this wonderful, though a bit slow-witted creature. Elephpotamuses' favorite dainty is elephant pumpkins, and some of such pumpkins grow on the lawn where Harry is to take his exam. At the start of the exam, Hagrid will drag the elephpotamus to one of the pumpkins. Having fed the animal with a pumpkin, Harry can direct it to any of the remaining pumpkins. In order to pass the exam, Harry must lead the elephpotamus so that it eats as many pumpkins as possible before it comes across its footprints. Input The first input line contains the number of pumpkins on the lawn N (3 ≤ N ≤ 30000). The pumpkins are numbered from 1 to N, the number one being assigned to the pumpkin to which the animal is brought at the start of the trial. In the next N lines, the coordinates of the pumpkins are given in the order corresponding to their numbers. All the coordinates are integers in the range from −1000 to 1000. It is guaranteed that there are no two pumpkins at the same location and there is no straight line passing through all the pumpkins. Output In the first line write the maximal number K of pumpkins that can be fed to the elephpotamus. In the next K lines, output the order in which the animal will eat them, giving one number in a line. The first number in this sequence must always be 1.写一段Java完成此目的
最新发布
06-03

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值