Solidity

需要幫助分解大契約

  • November 8, 2018

相關問題解決契約過大問題的最佳實踐?,我面臨著類似的問題(契約太大而無法部署,與區塊鏈的 gasLimit 相比),在我開始重構我的程式碼之前,我正在就可能的方法尋求建議。

這是我目前的設計:

contract A {
   // some state variables but not so many
   function A(some params) {
      // initialize the contract
   }
   function newT(some params) {
      // create a new T instance and store it in A's state variable
   } 
   // several other functions with business logic
}

contract T {
   // some state variables but not so many
   function T(A a, some params) {
      // test that it is only called by A, checking msg.sender
      // initialize the contract
   }
   function newU(some params) {
      // create a new U instance and store it in T's state variable
   } 
   // some business logic as functions
}

contract U {
   // some state variables but not so many
   function U(T t, some params) {
      // test that it is only called by T, checking msg.sender
      // initialize the contract
   }
   // some business logic as functions
}

創建 A 的第一個實例時,程式碼量很大。我是否正確理解 A 的程式碼將包括 A、T 和 U 的完整程式碼(因此它能夠創建 T 的新實例,分別為 U)?

如果是這樣,這是否意味著我沒有為乙太坊使用有效的工廠模式,因為工廠必須包含其實例化類的完整程式碼?

因此,當我們擁有嵌入真實業務邏輯的真實業務合約時,最好的工廠模式是什麼?(在這個階段我仍然處於概念驗證階段:-()

工廠用法的補充回答

對編譯後的程式碼大小進行了一些測試,我發現如果在合約上呼叫 new 運算符,編譯器只會包含創建的合約的程式碼。

如果我們考慮以下 3 個具有足夠內容的契約進行比較:

contract Child {
   uint i1;
   uint i2;
   uint i3;
   uint i4;
   uint i5;

   function f1() { i1=1;   }
   function f2() { i2=2;   }
   function f3() { i3=3;   }
   function f4() { i4=4;   }
   function f5() { i5=5;   }
}

contract MainFactory {
   Child ch;

   function MainFactory() {
       ch = new Child();
   }

   function test() {
       ch.f1();
       ch.f2();
       ch.f3();
       ch.f4();
       ch.f5();
   }
}

contract Main {
   Child ch;
   function Main(address child) {
       ch=(Child(child));
   }
   function test() {
       ch.f1();
       ch.f2();
       ch.f3();
       ch.f4();
       ch.f5();
   }
}

當用 solc 編譯時,我們有

  • Child的程式碼長度= 518
  • Main 的程式碼長度 = 1384
  • MainFactory 的程式碼長度 = 1970

在測試 Child 的程式碼是否包含在其他兩個合約的程式碼中時,我們有

  • 主要不包括子字節碼
  • MainFactory 確實在其末尾附加了 Child 字節碼。

結論:使用像 Rob 這樣的 MetaFactory 可以使主合約在子合約增長時不會增長,同時保持編譯能夠檢查類型、函式呼叫等,而無需實現抽象合約。

— 編輯以進一步展示 —

現在我更改 Child 合約,添加更多函式以使其字節碼增長:

contract Child {
   uint i1;
   uint i2;
   uint i3;
   uint i4;
   uint i5;

   function f1() { i1=1;   }
   function f2() { i2=2;   }
   function f3() { i3=3;   }
   function f4() { i4=4;   }
   function f5() { i5=5;   }

   function f1_() { i1=1;  }
   function f2_() { i2=2;  }
   function f3_() { i3=3;  }
   function f4_() { i4=4;  }
   function f5_() { i5=5;  }
}

現在編譯後我們有:

  • Child的程式碼長度= 942
  • Main 的程式碼長度 = 1384(無變化)
  • MainFactory 的程式碼長度 = 2394

另外,如果我在其他合約的字節碼中搜尋 Child 的字節碼

> DictContract["Child"].code
"0x6060604052341561000c57fe5b5b6101ba8061001c6000396000f300606060405236156100885763ffffffff60e060020a600035041663070d4270811461008a5780633c9d377d1461009c578063518efaf01461009c5780639942ec6f146100c0578063a7b4581d146100d2578063aaf05f3d1461008a578063af09d814146100c0578063c27fc30514610108578063c2ce99ea14610108578063c3f90202146100d2575bfe5b341561009257fe5b61009a61013e565b005b34156100a457fe5b61009a610146565b005b34156100a457fe5b61009a610146565b005b34156100c857fe5b61009a610156565b005b34156100da57fe5b61009a61015e565b005b341561009257fe5b61009a61013e565b005b34156100c857fe5b61009a610156565b005b341561011057fe5b61009a610176565b005b341561011057fe5b61009a610176565b005b34156100da57fe5b61009a61015e565b005b60036002555b565b60056004555b565b60056004555b565b60026001555b565b60046003555b565b60036002555b565b60026001555b565b60016000555b565b60016000555b565b60046003555b5600a165627a7a7230582072fe9922ad7ce90140824c40e32acecfdcd85c50682c9d410778319d9e10cb4e0029"
> DictContract["Main"].code
"0x6060604052341561000c57fe5b6040516020806102b383398101604052515b60008054600160a060020a031916600160a060020a0383161790555b505b6102688061004b6000396000f300606060405263ffffffff60e060020a600035041663f8a8fd6d8114610021575bfe5b341561002957fe5b610031610033565b005b60008054604080517fc27fc3050000000000000000000000000000000000000000000000000000000081529051600160a060020a039092169263c27fc3059260048084019382900301818387803b151561008957fe5b60325a03f1151561009657fe5b505060008054604080517f9942ec6f0000000000000000000000000000000000000000000000000000000081529051600160a060020a039092169350639942ec6f92600480830193919282900301818387803b15156100f157fe5b60325a03f115156100fe57fe5b505060008054604080517faaf05f3d0000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216935063aaf05f3d92600480830193919282900301818387803b151561015957fe5b60325a03f1151561016657fe5b505060008054604080517fc3f902020000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216935063c3f9020292600480830193919282900301818387803b15156101c157fe5b60325a03f115156101ce57fe5b505060008054604080517f3c9d377d0000000000000000000000000000000000000000000000000000000081529051600160a060020a039092169350633c9d377d92600480830193919282900301818387803b151561022957fe5b60325a03f1151561023657fe5b5050505b5600a165627a7a72305820f58668157b5128d3af3ed23b8e804e37b8940af2111d63810108e3100c6afef60029"
> DictContract["MainFactory"].code
"0x6060604052341561000c57fe5b5b61001561004f565b60405190819003906000f080151561002957fe5b60008054600160a060020a031916600160a060020a03929092169190911790555b61005f565b6040516101d6806102d683390190565b6102688061006e6000396000f300606060405263ffffffff60e060020a600035041663f8a8fd6d8114610021575bfe5b341561002957fe5b610031610033565b005b60008054604080517fc27fc3050000000000000000000000000000000000000000000000000000000081529051600160a060020a039092169263c27fc3059260048084019382900301818387803b151561008957fe5b60325a03f1151561009657fe5b505060008054604080517f9942ec6f0000000000000000000000000000000000000000000000000000000081529051600160a060020a039092169350639942ec6f92600480830193919282900301818387803b15156100f157fe5b60325a03f115156100fe57fe5b505060008054604080517faaf05f3d0000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216935063aaf05f3d92600480830193919282900301818387803b151561015957fe5b60325a03f1151561016657fe5b505060008054604080517fc3f902020000000000000000000000000000000000000000000000000000000081529051600160a060020a03909216935063c3f9020292600480830193919282900301818387803b15156101c157fe5b60325a03f115156101ce57fe5b505060008054604080517f3c9d377d0000000000000000000000000000000000000000000000000000000081529051600160a060020a039092169350633c9d377d92600480830193919282900301818387803b151561022957fe5b60325a03f1151561023657fe5b5050505b5600a165627a7a72305820908047bc9b21dceed16a5af60990e083fa13908ecf84b3f9f3cf73cb0adc7cf000296060604052341561000c57fe5b5b6101ba8061001c6000396000f300606060405236156100885763ffffffff60e060020a600035041663070d4270811461008a5780633c9d377d1461009c578063518efaf01461009c5780639942ec6f146100c0578063a7b4581d146100d2578063aaf05f3d1461008a578063af09d814146100c0578063c27fc30514610108578063c2ce99ea14610108578063c3f90202146100d2575bfe5b341561009257fe5b61009a61013e565b005b34156100a457fe5b61009a610146565b005b34156100a457fe5b61009a610146565b005b34156100c857fe5b61009a610156565b005b34156100da57fe5b61009a61015e565b005b341561009257fe5b61009a61013e565b005b34156100c857fe5b61009a610156565b005b341561011057fe5b61009a610176565b005b341561011057fe5b61009a610176565b005b34156100da57fe5b61009a61015e565b005b60036002555b565b60056004555b565b60056004555b565b60026001555b565b60046003555b565b60036002555b565b60026001555b565b60016000555b565b60016000555b565b60046003555b5600a165627a7a7230582072fe9922ad7ce90140824c40e32acecfdcd85c50682c9d410778319d9e10cb4e0029"


> DictContract["MainFactory"].code.indexOf(DictContract["Child"].code.replace("0x",""))
1454   <-- Found
> DictContract["Main"].code.indexOf(DictContract["Child"].code.replace("0x",""))
-1     <-- Not found

你是對的。工廠包含他們部署的合約的字節碼。這並不意味著您沒有正確使用工廠,但這確實意味著您需要打破 A(又名 MegaFactory)中字節碼的積累。

圖書館可能是合適的,但您也可以在不消耗 gas 預算的情況下建立一個 MegaFactory 工廠。只是結構略有不同。

與其讓 A 成為擁有所有合約的所有字節碼的大型工廠,不如為每個物種擁有一個小工廠。所以,FactoryT 和 FactoryU。這些工廠只會比他們部署的字節碼略大。

你仍然可以擁有一個能完成這一切的 MegaFactory。它將使用介面契約來提供足夠的資訊來理解它與之交談的實際工廠的 ABI。像這樣的東西:

contract FactoryTInterface {
 function newT() returns(address newTContract);
}

contract MegaFactory is FactoryTInterface {

 address factoryTaddress;

 function MegaFactory(address factoryT) {
     factoryTaddress = factoryT;
 }

 function newT() returns(address newContract) {
   FactoryTInterface factory = FactoryTInterface(factoryTaddress);
   return factory.newT();
 }
}

contract FactoryT {

 function newT() returns(address newT) {
   T t = new T();
   return t;
 }
}

contract T {
 // do something :-)
}

MegaFactory 沒有吸收 T 的所有字節碼,因為它不關心實際部署一個字節碼。它從介面合約中獲取它需要的所有資訊;足以向真正的工廠發送請求。

希望能幫助到你。

引用自:https://ethereum.stackexchange.com/questions/12698