MagicNumber
目标:使用10个操作码输出42
pragma solidity^0.4.24;
contract MagicNum{
address public solver;
constructor()public{}
function setSolver(address _solver)public{
solver=_solver;
}
/*
____________/\__/\\
__________/\___////////\_
________//\___///______//\_
______///\___________//
____//__/\______///
__/\\\\///___
_/////////////____//_
___________/\_____/\\\\_
___________///_____///////////////__
*/
}
在合约创建的时候,用户或合约将交易发送到以太坊网络,没有参数to,表示这是个合约创建而不是一个交易
EVM把solidity代码编译为字节码,字节码直接转换成opcodes运行
字节码包含两部分:initialization code和runtime code,一开始合约创建的时候EVM只执行initialization code,遇到第一个stop或者return的时候合约的构造函数就运行了,此时合约便有了地址
想要做这道题要构造这两段代码initialization code和runtime code,initialization code是由EVM创建并且存储需要用的runtime code的,所以首先来看runtime code,想要返回42,需要用return(p,s)但是在返回值前先要把值存储到内存中mstore(p,v)
首先,用mstore(p,v)把42存储到内存中,v是42的十六进制值0x2a,p是内存中的位置,push的字节码是0x60
0x602a;PUSH1 0x2a v
0x6080;PUSH1 0x80 p
0x52;MSTORE
复制
然后,用return(p,s)返回42,p是存储的位置,s是存储所占的大小不明白为啥是0x20
0x6020;PUSH1 0x20 s
0x6080;PUSH1 0x80 p
0xf3;RETURN
复制
所以整个runtime code是0x602a60805260206080f3
再来看initialization code,首先initialization code要把runtime code拷贝到内训,然后再返回给EVM
将代码从一个地方复制到一个地方的方法是codecopy(t,f,s)。t是目标位置,f是当前位置,s是代码大小(单位:字节),之前我们的代码大小为10字节
;copy bytecode to memory
0x600a;PUSH1 0x0a S(runtime code size)
0x60??;PUSH1 0x??F(current position of runtime opcodes)
0x6000;PUSH1 0x00 T(destination memory index 0)
0x39;CODECOPY
复制
然后,将内存中的runtime codes返回到EVM
;return code from memory to EVM
0x600a;PUSH1 0x0a S
0x6000;PUSH1 0x00 P
0xf3;RETURN
复制
initialization codes总共占了0x0c字节,这表示runtime codes从索引0x0c开始,所以??的地方是0x0c
所以,initialization codes最后的顺序是600a600c600039600a6000f3
两个拼起来,得到字节码是:
0x600a600c600039600a6000f3602a60805260206080f3
var bytecode="0x600a600c600039600a6000f3602a60805260206080f3";
web3.eth.sendTransaction({from:player,data:bytecode},function(err,res){console.log(res)});