Com determinar l'adreça d'un contracte intel·ligent abans del desplegament: utilitzant CREATE2 per a un intercanvi criptogràfic

El tema de la cadena de blocs no deixa de ser una font no només de tota mena de bombo, sinó també d'idees molt valuoses des del punt de vista tecnològic. Per tant, no va passar per alt els residents de la ciutat assolellada. La gent està mirant de prop, estudiant i intentant transferir la seva experiència en seguretat de la informació tradicional als sistemes blockchain. Fins ara, és correcte: un dels desenvolupaments de Rostelecom-Solar pot comprovar la seguretat del programari basat en blockchain. I al llarg del camí, sorgeixen algunes reflexions sobre la resolució de problemes aplicats de la comunitat blockchain. Un d'aquests trucs de vida: com determinar l'adreça d'un contracte intel·ligent abans del desplegament mitjançant CREATE2, avui vull compartir amb vosaltres sota el tall.

Com determinar l'adreça d'un contracte intel·ligent abans del desplegament: utilitzant CREATE2 per a un intercanvi criptogràfic
El codi operatiu CREATE2 es va afegir al hard fork de Constantinoble el 28 de febrer d'aquest any. Tal com s'indica a l'EIP, aquest codi operatiu es va introduir principalment per als canals estatals. Tanmateix, l'hem utilitzat per resoldre un problema diferent.

Hi ha usuaris amb saldos a l'intercanvi. Hem de proporcionar a cada usuari una adreça d'Ethereum a la qual qualsevol pugui enviar fitxes, reomplint així el seu compte. Anomenem aquestes adreces "carteres". Quan arriben fitxes a les carteres, les hem d'enviar a una única cartera (hotwallet).

En els apartats següents, analitzo les opcions per resoldre aquest problema sense CREATE2 i us explico per què les vam abandonar. Si només esteu interessats en el resultat final, el podeu trobar a l'apartat "Solució final".

Adreces d'Ethereum

La solució més senzilla és generar noves adreces d'Ethereum per a nous usuaris. Aquestes adreces seran les carteres. Per transferir fitxes d'una cartera a una cartera ràpida, heu de signar la transacció trucant a la funció transferència () amb la clau privada de la cartera del backend.

Aquest enfocament té els següents avantatges:

  • és fàcil
  • el cost de transferir fitxes d'una cartera a una cartera calenta és igual al cost d'una trucada de funció transferència ()

Tanmateix, ens vam decidir en contra d'aquest enfocament perquè té un inconvenient important: heu d'emmagatzemar les claus privades en algun lloc. No només es poden perdre, sinó que també cal gestionar acuradament l'accés a aquestes claus. Si almenys un d'ells està compromès, les fitxes d'un usuari concret no arribaran a la cartera calenta.

Com determinar l'adreça d'un contracte intel·ligent abans del desplegament: utilitzant CREATE2 per a un intercanvi criptogràfic

Creeu un contracte intel·ligent independent per a cada usuari

La implementació d'un contracte intel·ligent independent per a cada usuari us permet evitar emmagatzemar claus privades per a carteres al servidor. L'intercanvi trucarà a aquest contracte intel·ligent per transferir els fitxes a l'hotwallet.

També vam abandonar aquesta solució, ja que a l'usuari no se li pot mostrar la seva adreça de cartera sense desplegar un contracte intel·ligent (això és realment possible, però d'una manera força complexa amb altres inconvenients que no parlarem aquí). A l'intercanvi, un usuari pot crear tants comptes com necessiti i cadascun necessita la seva pròpia cartera. Això vol dir que hem de gastar diners en desplegar un contracte sense ni tan sols estar segurs que l'usuari utilitzarà aquest compte.

Opcode CREATE2

Per solucionar el problema del mètode anterior, vam decidir utilitzar el codi operatiu CREATE2. CREATE2 us permet determinar prèviament l'adreça on es desplegarà el contracte intel·ligent. L'adreça es calcula amb la fórmula següent:

keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]


on:

  • direcció — l'adreça del contracte intel·ligent que anomenarà CREATE2
  • sal - valor aleatori
  • codi_inici — codi de bytes de contracte intel·ligent per al desplegament

Això garanteix que l'adreça que proporcionem a l'usuari conté realment el bytecode desitjat. A més, aquest contracte intel·ligent es pot implementar sempre que ho necessitem. Per exemple, quan un usuari decideix utilitzar la seva cartera per primera vegada.
Com determinar l'adreça d'un contracte intel·ligent abans del desplegament: utilitzant CREATE2 per a un intercanvi criptogràfic
A més, podeu calcular l'adreça del contracte intel·ligent cada vegada en lloc d'emmagatzemar-la perquè:

  • direcció en la fórmula és constant, ja que aquesta és l'adreça de la nostra fàbrica de carteres
  • sal — user_id hash
  • codi_inici és constant ja que fem servir la mateixa cartera

Més millores

La solució anterior encara té un inconvenient: cal pagar per desplegar el contracte intel·ligent. No obstant això, pots desfer-te'n. Per fer-ho podeu cridar la funció transferència ()i després autodestruir() al constructor de carteres. I després es retornarà el gas per desplegar el contracte intel·ligent.

Contràriament a la creença popular, podeu implementar un contracte intel·ligent a la mateixa adreça diverses vegades amb el codi operatiu CREATE2. Això es deu al fet que CREATE2 comprova que el noce de l'adreça de destinació sigui zero (se li assigna el valor "1" al començament del constructor). En aquest cas, la funció autodestruir() restableix les adreces nonce cada vegada. Per tant, si torneu a trucar a CREATE2 amb els mateixos arguments, passarà la comprovació de nonce.

Tingueu en compte que aquesta solució és similar a l'opció d'adreça d'Ethereum, però sense necessitat d'emmagatzemar claus privades. El cost de transferir diners d'una cartera a una cartera calenta és aproximadament igual al cost de trucar a una funció transferència (), ja que no paguem el desplegament de contracte intel·ligent.

Decisió final

Com determinar l'adreça d'un contracte intel·ligent abans del desplegament: utilitzant CREATE2 per a un intercanvi criptogràfic

Preparat originalment per:

  • funció d'aconseguir sal user_id
  • un contracte intel·ligent que cridarà al codi operatiu CREATE2 amb la sal adequada (és a dir, fàbrica de carteres)
  • codi de bytes de cartera corresponent al contracte amb el constructor següent:

constructor () {
    address hotWallet = 0x…;
    address token = 0x…;
    token.transfer (hotWallet, token.balanceOf (address (this)));
    selfdestruct (address (0));
}


Per a cada usuari nou mostrem la seva adreça de cartera per càlcul

keccak256 (0xff ++ address ++ salt ++ keccak256 (init_code)) [12:]


Quan un usuari transfereix fitxes a l'adreça de la cartera corresponent, el nostre backend veu un esdeveniment de transferència amb el paràmetre _a, igual a l'adreça de la cartera. En aquest punt, ja és possible augmentar el saldo de l'usuari a l'intercanvi abans de desplegar la cartera.

Quan una adreça de cartera acumula un nombre suficient de fitxes, podem transferir-les totes alhora a hotwallet. Per fer-ho, el backend crida a la funció de fàbrica de contracte intel·ligent, que realitza les accions següents:

function deployWallet (соль uint256) {
    bytes memory walletBytecode =…;
    // invoke CREATE2 with wallet bytecode and salt
}


Així, s'anomena el constructor de contracte intel·ligent de cartera, que transfereix tots els seus testimonis a l'adreça de hotwallet i després s'autodestrueix.

Es pot trobar el codi complet aquí. Tingueu en compte que aquest no és el nostre codi de producció, ja que vam decidir optimitzar el bytecode de la cartera i l'hem escrit en opcodes.

Autor Pavel Kondratenkov, especialista en Ethereum

Font: www.habr.com

Afegeix comentari