向 solidity 添加新的自定义操作码
Adding new custom opcode to solidity
我在向 solidity 添加新操作码时遇到问题。我正在使用 solc(在 C++ 上)和 geth(在 Go 上使用以太坊)。我想添加新的操作码,需要 address payable, uint256, uint256, bytes memory
和 returns bytes memory
。所以我对 return 值有疑问。
下面的一些代码,我会跳过一些文件,使问题更短。
- 太阳系
libsolidity/codegen/ExpressionCompiler.cpp
// ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::MyOpcode:
{
acceptAndConvert(*arguments[0], *function.parameterTypes()[0], true);
acceptAndConvert(*arguments[1], *function.parameterTypes()[1], true);
acceptAndConvert(*arguments[2], *function.parameterTypes()[2], true);
arguments[3]->accept(*this);
utils().fetchFreeMemoryPointer();
utils().packedEncode(
{arguments[3]->annotation().type},
{TypeProvider::array(DataLocation::Memory, true)}
);
utils().toSizeAfterFreeMemoryPointer();
m_context << Instruction::MYOPCODE;
}
libsolidity/analysis/GlobalContext.cpp
// inline vector<shared_ptr<MagicVariableDeclaration const>> constructMagicVariables()
magicVarDecl("myopcode", TypeProvider::function(strings{"address payable", "uint256", "uint256", "bytes memory"}, strings{"bytes memory"}, FunctionType::Kind::MyOpcode, false, StateMutability::Payable)),
- libevmasm/Instruction.cpp
// static std::map<Instruction, InstructionInfo> const c_instructionInfo =
{ Instruction::MYOPCODE, { "MYOPCODE", 0, 5, 1, true, Tier::Base } }
- Geth
- core/vm/jump_table.go
// func newFrontierInstructionSet() JumpTable {
CALLACTOR: {
execute: opMyOpCode,
dynamicGas: gasCallActor,
minStack: minStack(5, 1),
maxStack: maxStack(5, 1),
memorySize: memoryReturn,
writes: true,
returns: true,
},
- core/vm/instructions.go
func opMyOpcode(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
inoffset, insize := callContext.stack.pop(), callContext.stack.pop()
params := callContext.memory.GetPtr(int64(inoffset.Uint64()), int64(insize.Uint64()))
secondValue := callContext.stack.pop()
firstValue := callContext.stack.pop()
addr := callContext.stack.pop()
// ... Do smth with input ...
outoffset := inoffset.Uint64() + insize.Uint64()
callContext.memory.Set(outoffset, 1, []byte{0x2})
tmp := make([]byte, 1)
tmp[0] = 0x98
callContext.memory.Set(outoffset + 1, 1, tmp)
callContext.stack.push(uint256.NewInt().SetUint64(outoffset))
return tmp, nil
}
- 智能合约
pragma solidity >=0.6.0; // SPDX-License-Identifier: GPL-3
contract test {
event ReturnValue(address payable _from, bytes data);
function f() public returns(bytes memory){
address payable addr1 = payable(msg.sender);
bytes memory params = new bytes(2);
params[0] = 0x21;
params[1] = 0x22;
bytes memory result = myopcode(addr1, 0x11, 0x12, params);
emit ReturnValue(addr1, result);
return result;
}
}
当我 运行 该代码时,我得到 invalid jump destination
。那么,我需要做什么才能让我的代码正常工作?
我找到了一个解决方案,它看起来确实很愚蠢,但是这个案例已经由开发人员提供了。您只需要 utils().returnDataToArray()
.
我在向 solidity 添加新操作码时遇到问题。我正在使用 solc(在 C++ 上)和 geth(在 Go 上使用以太坊)。我想添加新的操作码,需要 address payable, uint256, uint256, bytes memory
和 returns bytes memory
。所以我对 return 值有疑问。
下面的一些代码,我会跳过一些文件,使问题更短。
- 太阳系
libsolidity/codegen/ExpressionCompiler.cpp
// ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::MyOpcode:
{
acceptAndConvert(*arguments[0], *function.parameterTypes()[0], true);
acceptAndConvert(*arguments[1], *function.parameterTypes()[1], true);
acceptAndConvert(*arguments[2], *function.parameterTypes()[2], true);
arguments[3]->accept(*this);
utils().fetchFreeMemoryPointer();
utils().packedEncode(
{arguments[3]->annotation().type},
{TypeProvider::array(DataLocation::Memory, true)}
);
utils().toSizeAfterFreeMemoryPointer();
m_context << Instruction::MYOPCODE;
}
libsolidity/analysis/GlobalContext.cpp
// inline vector<shared_ptr<MagicVariableDeclaration const>> constructMagicVariables()
magicVarDecl("myopcode", TypeProvider::function(strings{"address payable", "uint256", "uint256", "bytes memory"}, strings{"bytes memory"}, FunctionType::Kind::MyOpcode, false, StateMutability::Payable)),
- libevmasm/Instruction.cpp
// static std::map<Instruction, InstructionInfo> const c_instructionInfo =
{ Instruction::MYOPCODE, { "MYOPCODE", 0, 5, 1, true, Tier::Base } }
- Geth
- core/vm/jump_table.go
// func newFrontierInstructionSet() JumpTable {
CALLACTOR: {
execute: opMyOpCode,
dynamicGas: gasCallActor,
minStack: minStack(5, 1),
maxStack: maxStack(5, 1),
memorySize: memoryReturn,
writes: true,
returns: true,
},
- core/vm/instructions.go
func opMyOpcode(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
inoffset, insize := callContext.stack.pop(), callContext.stack.pop()
params := callContext.memory.GetPtr(int64(inoffset.Uint64()), int64(insize.Uint64()))
secondValue := callContext.stack.pop()
firstValue := callContext.stack.pop()
addr := callContext.stack.pop()
// ... Do smth with input ...
outoffset := inoffset.Uint64() + insize.Uint64()
callContext.memory.Set(outoffset, 1, []byte{0x2})
tmp := make([]byte, 1)
tmp[0] = 0x98
callContext.memory.Set(outoffset + 1, 1, tmp)
callContext.stack.push(uint256.NewInt().SetUint64(outoffset))
return tmp, nil
}
- 智能合约
pragma solidity >=0.6.0; // SPDX-License-Identifier: GPL-3
contract test {
event ReturnValue(address payable _from, bytes data);
function f() public returns(bytes memory){
address payable addr1 = payable(msg.sender);
bytes memory params = new bytes(2);
params[0] = 0x21;
params[1] = 0x22;
bytes memory result = myopcode(addr1, 0x11, 0x12, params);
emit ReturnValue(addr1, result);
return result;
}
}
当我 运行 该代码时,我得到 invalid jump destination
。那么,我需要做什么才能让我的代码正常工作?
我找到了一个解决方案,它看起来确实很愚蠢,但是这个案例已经由开发人员提供了。您只需要 utils().returnDataToArray()
.