君士坦丁堡硬升级中引入了一个新操作码 CREATE2[1] ,它使用新的方式来计算常见的合约地址,让生成的合约地址更具有可控性,通过 CREATE2 可以延伸出很多新的玩法,这篇文章来探讨下,在广义状态通道中的妙用 在 CREATE2 以前,CREATE指令创建的合约地址是通通过交易发起者(sender)的地址以及交易序号(nonce)来计算确定的。 init_code)) CREATE创建的合约地址依赖于一个跟随交易者发起的交易数量不断的增长的nonce变量,这种方式很难确定一个未来要部署的合约地址(比如提前使用一个还未部署的合约地址),而使用 CREATE2 通过使用 CREATE2,可以在游戏合约不上链的情况下进行游戏,因为只要游戏的规则代码确定了,就可以确定游戏合约的地址,在链下就可以基于这个确定的合约地址进行签名玩游戏,甚至我们根本不需要部署游戏合约, References [1] 新操作码 CREATE2: https://learnblockchain.cn/docs/eips/eip-1014.html [2] 编写一个简单的支付通道: https
本文作者:gasshadow[1] 由于文章:实践 create2 进行合约无缝升级[2]过了编辑时间,不能继续编辑。单开一篇文章,把后半部分补全。 recover 流程和deploy差不多: 通过create2创建保险库合约(或者 call 调用保险库合约),如果保险库合约里有钱,就转到临时合约。 通过create2创建临时合约,并在临时合约里调用create创建最终合约 最终合约的初始化是将最终合约里的钱转给交易发起者(也就是调用 metapod 的交易者),并调用 selfdestruct 自毁 deploy create2 创建保险库合约,保险库合约将自己的钱转给临时合约 create2 创建临时合约,通过getInitializationCode获取最终合约的代码,使用create部署最终合约 使用create2创建临时合约,通过getInitializationCode获取最终合约的代码,使用create部署最终合约(并将自己的钱转给最终合约),自己调用selfdestruct销毁。
使用CREATE2当然比最初的CREATE更复杂。不再仅仅写new Token()就行了,而必须要编写汇编代码。 译者注:现在可以不用编写汇编, solidity 0.8 之后, 可以通过指定 slat 来使用 create2 ,例如:new Token{salt: bytes32}() 但是create2有一个重要的属性 由于网上相关的案例很少,我想写一篇简单的博客来解释一下: CREATE和CREATE2都是怎么工作的 怎样在智能合约中使用CREATE2 我怎样用它来完成一个Capture The Ether[2]挑战 解决方案 要用CREATE2找到包含badc0de的地址,我们需要: 要部署的合约的字节码 部署合约的地址 (用CREATE2的合约) salt — 我们将通过计算得出. 第二步: 用 CREATE2 的合约 现在我们可以定义一个简单的合约,给他一个 salt,并且用CREATE2来部署字节码: contract Deployer { bytes contractBytecode
CREATE2 是以太坊在2019年2月28号的君士坦丁堡(Constantinople)硬分叉[1]中引入 的一个新操作码。 下面我们分析一下在没有CREATE2操作码时,如何解决上述问题, 以及为什么这些方案不适用。如果你只对最终结果感兴趣,可以直接跳到最后一节:最终方案[3]。 改进:使用CREATE2 操作码预计算合约地址 为了解决上一节没有办法显示充值地址的问题,我们决定使用 CREATE2 操作码,它允许我们提前计算出要部署的合约地址,地址计算公式如下: keccak256 与常见错误认识相反,其实你可以使用CREATE2操作码在同一地址多次部署智能合约。这是因为CREATE2检查目标地址的 nonce 是否为零(它会在构造函数的开头将其设置为1)。 因此,如果再次使用相同的参数调用CREATE2创建合约,对nonce的检查是可以通过的。 这个解决方案类似于使用以太坊地址的方案,但是无需存储私钥。
root->right = create1(pre, y + 1, x2, x + 1, x4); return root; } 后序遍历+中序遍历 分析 代码实现 BitTree* create2 BitTree(root_val); int x = mp[root_val]; //中序遍历中的位置 int y = x1 + x - 1 - x3; //创建左子树 root->left = create2 (post, x1, y, x3, x - 1); //创建右子树 root->right = create2(post, y + 1, x2 - 1, x + 1, x4); return (post, x1, y, x3, x - 1); //创建右子树 root->right = create2(post, y + 1, x2 - 1, x + 1, x4); return } int size = in.size(); BitTree *T1 = create1(pre, 0, size - 1, 0, size - 1); BitTree *T2 = create2
CREATE2 创建交易对,就是创建一个新的合约,作为流动池来提供交易功能。 因为指定了salt,solidity会使用EVM的CREATE2指令来创建合约。使用CREATE2指令的好处是,只要合约的bytecode及salt不变,那么创建出来的地址也将不变。 关于使用salt创建合约的解释:Salted contract creations/create2 CREATE2指令的具体解释可以参考:EIP-1014。 使用CREATE2的好处是: 可以在链下计算出已经创建的交易池的地址 其他合约不必通过UniswapV3Factory中的接口来查询交易池的地址,可以节省gas 合约地址不会因为reorg而改变 这是因为CREATE2会将合约的initcode和salt一起用来计算创建出的合约地址。
本文作者:darren94me[1] 背景 在 Uniswap 源码看到工厂合约 UniswapV2Factory[2]中 createPair 方法,使用了 create2[3],预先知道配对合约地址 uint _salt) public payable{ address addr; /* how to call create create2 memory n size of code s salt */ assembly { addr := create2 ://learnblockchain.cn/people/4859 [2] UniswapV2Factory: https://learnblockchain.cn/article/3604 [3] create2
我启动了三个 demo 应用,分别是 create1,create2,create3.create1 中会提供一个 request 接口,在这里面调用 create2 的 create2 接口,create2 > { myServiceStub.create2(request).getMessage(); }); return message; }create2 :@Override public void create2(HelloRequest request, StreamObserver<HelloReply> responseObserver) { HelloReply reply = HelloReply.newBuilder() .setMessage("Create2 ==> " + request.getName( )) .build(); log.info("Create2: {}", reply.getMessage()); myMethod(request.getName
@Autowired private RabbitTemplate rabbitTemplate; // 下单的接口 @RequestMapping("/create2 ") public String create2(){ // 发送对象 OrderInfo orderInfo = new OrderInfo(); orderInfo); // 收到消息后的处理,代码省略 } } 运行程序 访问订单系统的接口,模拟下单请求: http://127.0.0.1:8080/order/create2 @Autowired private RabbitTemplate rabbitTemplate; // 下单的接口 @RequestMapping("/create2 ") public String create2(){ // 发送对象 OrderInfo orderInfo = new OrderInfo();
typedef struct node { datatype data; struct node*next; }linklist; void create1(linklist*&); void create2 linklist*); void solve(linklist*,linklist*,linklist*); int main() { linklist *a,*b,*c; create1(a); create2 linklist*)malloc(sizeof(linklist)); s->data=x; r->next=s; r=s; x++; } r->next=NULL; } void create2
CREATE2,修改EIP并在下次升级时启动CREATE2。 PeckShield研发副总吴家志对此表示:CREATE2的启用对于智能合约安全审计增加不少难度,除了源码与二进制的审计外,还必须考虑合约的部署方式。 例如CREATE2部署的一个合约CREATE了一个子合约,子合约再CREATE孙合约,由于自毁合约(SELFDESTRUCT)后流水号(Nonce)不会被保留,这些合约都有被篡改的风险。 站在安全从业人员的角度,CREATE2的启用还需要从长计议。 现在删除CREATE2的话,可能会再次延后君士坦丁堡升级,进而难度炸弹造成出块时间继续增大;如果不立即删除,在不久的将来也可能需要再次修改EIP并且升级。
TryAdd 的方法的性能会比使用 GetOrAdd 的性能高 这是我更改的方法,使用 GetOrAdd 可以做到只创建一个对象 public static ElementMetadata Create2 Method Mean Error StdDev Gen 0 Gen 1 Gen 2 Allocated Create 22.19 ns 0.154 ns 0.144 ns - - - - Create2 37.22 ns 0.337 ns 0.315 ns 0.0210 - - 88 B 为什么 Create2 方法会更慢,同时需要申请内存? } [BenchmarkCategory("ElementMetadataTests")] [Benchmark] public void Create2
function create1() { $class = get_class($this); return new $class(); } public function create2 ); } } class B extends A { } $b = new B(); var_dump(get_class($b->create1()), get_class($b->create2
创建右子树 root->right = create1(pre, y + 1, x2, x + 1, x4); return root; } //中序遍历和后续遍历构建二叉树 BitTree* create2 BitTree(root_val); int x = mp[root_val]; //中序遍历中的位置 int y = x1 + x - 1 - x3; //创建左子树 root->left = create2 (post, x1, y, x3, x - 1); //创建右子树 root->right = create2(post, y + 1, x2 - 1, x + 1, x4); return } int size = in.size(); BitTree *T1 = create1(pre, 0, size - 1, 0, size - 1); //BitTree *T2 = create2
自0.8.0版本开始,new关键字通过指定salt选项支持create2特性。 •createWithSalt函数:与create函数类似,但它使用create2特性创建新的Car合约实例。create2特性允许你使用一个salt值来影响新合约的地址。
我们可以通过使用 CREATE2 函数来实现这一点。 让我们创建一个工厂合约,它也有 SimpleWallet合约,它将使用 Solidity 文档中所说的 CREATE2 操作码:加“盐”的合约创建 / create2[23]。 deploy( uint _salt ) public payable returns (address) { // 不在使用 assembly的新语法调用 create2 等待交易,并前往Etherscan[25]确认它是否正确部署: 在交易细节部分(在 Etherscan 上)选择 Internal Txns标签: 在页面上,我们看到CREATE2 函数被我们的工厂合约调用 注意,由于 Etherscan 的 Goerli 网络似乎是运行在 OpenEthereum 节点上,CREATE2 在 Etherscan 界面中被渲染成 CREATE。
三个合约之间的关系如下图(引自崔棉大师教程视频中的图): 工厂合约 工厂合约最核心的函数就是 createPair() ,其实现代码如下: 里面创建合约采用了 create2,这是一个汇编 opcode 使用 create2 最大的好处其实在于:可以在部署智能合约前预先计算出合约的部署地址。 接着就用 assembly 关键字包起一段内嵌汇编代码,里面调用 create2 操作码来创建新合约。 除了 create2 创建新合约的这部分代码之外,其他的都很好理解,我就不展开说明了。 这是因为用 create2 创建合约的方式限制了构造函数不能有参数。 另外,配对合约中最核心的函数有三个:mint()、burn()、swap() 。
custom[0] = bytes1(rtType); custom = bytesCopy(bytesname, custom, 1); assembly { //create2 指令参数1为转账额,参数2为合约字节码长度,参数3为字节码,参数4为虚拟机类型+合约名 addr := create2(0, add(bytesCode,0x20), mload(
class OrderInfo { private String orderId; private String name; } 生产者: @RequestMapping("/create2 ") public String create2() { //省略相关操作 例如校验参数 相关数据库操作 //主要测试代码是否最后成功发送即可 OrderInfo
subscriber) { subscriber.onNext("create1"); //发射一个"create1"的String subscriber.onNext("create2 "); //发射一个"create2"的String subscriber.onCompleted();//发射完成,这种方法需要手动调用onCompleted,才会回调Observer