I have a problem with adding new opcode to solidity. I'm using solc (on C++) and geth(ethereum on Go). I want to add new opcode, that takes address payable, uint256, uint256, bytes memory
and returns bytes memory
. So I have a problem with return value.
Some peaces of code below, I will skip some files, to make question shorter.
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)),
// static std::map<Instruction, InstructionInfo> const c_instructionInfo =
{ Instruction::MYOPCODE, { "MYOPCODE", 0, 5, 1, true, Tier::Base } }
// func newFrontierInstructionSet() JumpTable {
CALLACTOR: {
execute: opMyOpCode,
dynamicGas: gasCallActor,
minStack: minStack(5, 1),
maxStack: maxStack(5, 1),
memorySize: memoryReturn,
writes: true,
returns: true,
},
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;
}
}
When I run that code I get invalid jump destination
. So, what I need to do, to get my code work correctly?
I found a solution, it certainly looks stupid, but this case is already provided by the developers. All you need is utils().returnDataToArray()
.