Wie kann ein Fabrikvertrag den Bytecode eines bestehenden Vertrags klonen?

Die Verwendung newzum Erstellen eines Vertrags bewirkt, dass der Fabrikvertrag kompiliert wird, wobei der Bytecode des Produktvertrags am Ende angehängt wird ...

contract Foo
{
    function Foo() {}
}

bytecode: 60606040525b600056

contract FooFactory
{
    function newFoo() returns (Foo) {
       return new Foo();
    }
}

bytecode: 6060604052346000575b6092806100166000396000f3606060405260e060020a60003504639a67a7068114601c575b6000565b346000576026604f565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b6000604051602080607283396040519101819003906000f0801560005790505b90566060604052346000575b5b5b60098060176000396000f360606040525b600056                                                                        
                                                                                                                                                                                                                                                                                                                                        ^ Foo bytecode starts here

Bei großen Werks-/Produktverträgen kann dies bei der Bereitstellung zu einem Problem mit der Blockgasgrenze werden.

Gibt es eine Möglichkeit für einen Fabrikvertrag, den Bytecode eines bestehenden Vertrags zu klonen?

Foo bereitstellen und dann EXTCODECOPY für seine Adresse verwenden? ethereum.stackexchange.com/questions/1906/…
Vielen Dank. Es sieht also möglich aus, ist aber nicht trivial. Eines Tages werde ich genug Zeit haben, um die EVM-Montage eingehend zu studieren ...

Antworten (2)

Martin Holst Swende hat hier eine Umsetzung eines Klonervertrages veröffentlicht! https://gist.github.com/holiman/069de8d056a531575d2b786df3345665

Auszug:

function clone(address a) returns(address){

    /*

    Assembly of the code that we want to use as init-code in the new contract, 
    along with stack values:
                    # bottom [ STACK ] top
     PUSH1 00       # [ 0 ]
     DUP1           # [ 0, 0 ]
     PUSH20         
     <address>      # [0,0, address] 
     DUP1       # [0,0, address ,address]
     EXTCODESIZE    # [0,0, address, size ]
     DUP1           # [0,0, address, size, size]
     SWAP4          # [ size, 0, address, size, 0]
     DUP1           # [ size, 0, address ,size, 0,0]
     SWAP2          # [ size, 0, address, 0, 0, size]
     SWAP3          # [ size, 0, size, 0, 0, address]
     EXTCODECOPY    # [ size, 0]
     RETURN 

    The code above weighs in at 33 bytes, which is _just_ above fitting into a uint. 
    So a modified version is used, where the initial PUSH1 00 is replaced by `PC`. 
    This is one byte smaller, and also a bit cheaper Wbase instead of Wverylow. It only costs 2 gas.

     PC             # [ 0 ]
     DUP1           # [ 0, 0 ]
     PUSH20         
     <address>      # [0,0, address] 
     DUP1       # [0,0, address ,address]
     EXTCODESIZE    # [0,0, address, size ]
     DUP1           # [0,0, address, size, size]
     SWAP4          # [ size, 0, address, size, 0]
     DUP1           # [ size, 0, address ,size, 0,0]
     SWAP2          # [ size, 0, address, 0, 0, size]
     SWAP3          # [ size, 0, size, 0, 0, address]
     EXTCODECOPY    # [ size, 0]
     RETURN 

    The opcodes are:
    58 80 73 <address> 80 3b 80 93 80 91 92 3c F3
    We get <address> in there by OR:ing the upshifted address into the 0-filled space. 
      5880730000000000000000000000000000000000000000803b80938091923cF3 
     +000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx000000000000000000
     -----------------------------------------------------------------
      588073xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx00000803b80938091923cF3

    This is simply stored at memory position 0, and create is invoked. 

    */
    address retval;
    assembly{
        mstore(0x0, or (0x5880730000000000000000000000000000000000000000803b80938091923cF3 ,mul(a,0x1000000000000000000)))
        retval := create(0,0, 32)
    }
    return retval;
}
Was wird im Konstruktor nicht ausgeführt, gibt es eine neue Möglichkeit, dies zu tun?

Dieser Code hat einen wichtigen Nachteil. Es führt den Quellvertragskonstruktor nicht aus, wenn die pragma solidity vorhanden ist ^0.4.25;

contract Factory {

function at(address _addr) private view returns (bytes memory o_code) {
    assembly {
        // retrieve the size of the code, this needs assembly
        let size := extcodesize(_addr)
        // allocate output byte array - this could also be done without assembly
        // by using o_code = new bytes(size)
        o_code := mload(0x40)
        // new "memory end" including padding
        mstore(0x40, add(o_code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
        // store length in memory
        mstore(o_code, size)
        // actually retrieve the code, this needs assembly
        extcodecopy(_addr, add(o_code, 0x20), 0, size)
    }
}

function create(address _addrOfCode) returns (address){
    address retval;
    assembly{
        mstore(0x0, or (0x5880730000000000000000000000000000000000000000803b80938091923cF3 ,mul(_addrOfCode,0x1000000000000000000)))
        retval := create(0,0, 32)
    }
    return retval;
}
}

contract Adder {
uint256 public param;

constructor(){
    param = 5;
}

function add(uint a, uint b) returns (uint){
    return a+b;
}
}

contract Tester {

Adder a;

function Tester(address factory,address adder){
    address cAdr = Factory(factory).create(adder);
    a = Adder(cAdr);
    if(address(a) == 0) throw;
}

function test(uint x, uint y) constant returns (uint){
    return a.add(x,y);
}
/* Reasonable expectation is 5, but it is 0 */
function getParam() constant returns (uint){
    return a.param();
}
}