Vorkompilierte Contracts auf Moonbase Alpha

Nikki
Moonbeam-DE translations
5 min readJul 30, 2021

Einleitung

Eine weitere Funktion, die mit der Veröffentlichung von Moonbase Alpha v2 hinzugefügt wurde, ist das Enthalten einiger vorkompilierter Verträge, die nativ auf Ethereum verfügbar sind.

Derzeit sind fünf Vorkompilierungen enthalten, darunter: ecrecover, sha256, Reifemd-160, die Identitätsfunktion und die modulare Exponentiation.

In dieser Anleitung erklären wir, wie Sie diese Vorkompilierungen verwenden und/oder überprüfen.

Voraussetzungen Prüfen

Wir müssen Node.js (wir verwenden v15.x) und den npm-Paketmanager installieren. Sie können direkt von Node.js oder in Ihrem Terminal herunterladen:

Ubuntu

curl -sL https://deb.nodesource.com/setup_15.x | sudo -E bash -

sudo apt install -y nodejs

MacOS

# You can use homebrew (https://docs.brew.sh/Installation)

brew install node

# Or you can use nvm (https://github.com/nvm-sh/nvm)

nvm install node

Wir können überprüfen, ob alles richtig installiert ist, indem wir die Version für jedes Paket abfragen:

node -v

npm -v

Zum zeitpunkt des Schreibens dieser Anleitung, waren die verwendeten Versionen 15.2.1 bzw. 7.0.8. Wir müssen auch das Web3-Paket installieren, indem wir Folgendes ausführen:

npm install — save web3

Um die installierte Version von Web3 zu überprüfen, können Sie den Befehl ls verwenden:

npm ls web3

Zum Zeitpunkt der Erstellung dieser Anleitung war die verwendete Version 1.3.0. Wir werden auch Remix verwenden und es über MetaMask mit dem Moonbase Alpha TestNet verbinden.

Signaturen mit ECRECOVER verifizieren

Die Hauptfunktion dieser Vorkompilierung besteht darin, die Signatur einer Nachricht zu überprüfen. Im Allgemeinen geben Sie ecrecover die Signaturwerte der Transaktion und es gibt eine Adresse zurück. Die Signatur wird verifiziert, wenn die zurückgegebene Adresse mit der öffentlichen Adresse übereinstimmt, die die Transaktion gesendet wurde.

Lassen Sie uns zu einem kleinen Beispiel springen, um zu zeigen, wie Sie diese vorkompilierte Funktion nutzen können. Dazu müssen wir die Signaturwerte der Transaktion (v, r, s) abrufen. Daher signieren und rufen wir die signierte Nachricht mit diesen Werten ab:

const Web3 = require(‘web3’);

// Provider

const web3 = new Web3(‘https://rpc.testnet.moonbeam.network');

// Address and Private Key

const address = ‘0x6Be02d1d3665660d22FF9624b7BE0551ee1Ac91b’;

const pk1 = ‘99B3C12287537E38C90A9219D4CB074A89A16E9CDB20BF85728EBD97C343E342’;

const msg = web3.utils.sha3(‘supercalifragilisticexpialidocious’);

async function signMessage(pk) {

try {

// Sign and get Signed Message

const smsg = await web3.eth.accounts.sign(msg, pk);

console.log(smsg);

} catch (error) {

console.error(error);

}

}

signMessage(pk1);

Dieser Code gibt das folgende Objekt im Terminal zurück:

{

message: ‘0xc2ae6711c7a897c75140343cde1cbdba96ebbd756f5914fde5c12fadf002ec97’,

messageHash: ‘0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d50’,

v: ‘0x1b’,

r: ‘0x44287513919034a471a7dc2b2ed121f95984ae23b20f9637ba8dff471b6719ef’,

s: ‘0x7d7dc30309a3baffbfd9342b97d0e804092c0aeb5821319aa732bc09146eafb4’,

signature: ‘0x44287513919034a471a7dc2b2ed121f95984ae23b20f9637ba8dff471b6719ef7d7dc30309a3baffbfd9342b97d0e804092c0aeb5821319aa732bc09146eafb41b’

}

Mit den notwendigen Werten können wir zu Remix gehen, um den vorkompilierten Vertrag zu testen. Beachten Sie, dass dies auch mit der Web3 JS-Bibliothek überprüft werden kann, aber in unserem Fall gehen wir zu Remix, um sicherzustellen, dass der vorkompilierte Vertrag in der Blockchain verwendet wird. Der Solidity-Code, mit dem wir die Signatur überprüfen können, ist der folgende:

pragma solidity ^0.7.0;

contract ECRECOVER{

address addressTest = 0x12Cb274aAD8251C875c0bf6872b67d9983E53fDd;

bytes32 msgHash = 0xc51dac836bc7841a01c4b631fa620904fc8724d7f9f1d3c420f0e02adf229d50;

uint8 v = 0x1b;

bytes32 r = 0x44287513919034a471a7dc2b2ed121f95984ae23b20f9637ba8dff471b6719ef;

bytes32 s = 0x7d7dc30309a3baffbfd9342b97d0e804092c0aeb5821319aa732bc09146eafb4;

function verify() public view returns(bool) {

// Use ECRECOVER to verify address

return (ecrecover(msgHash, v, r, s) == (addressTest));

}

}

Mit dem Remix-Compiler und der Bereitstellung und mit MetaMask, der mit Moonbase Alpha verunden ist, können wir den Vertrag bereitstellen und die Methode verify() aufrufen, die true zurückgibt, wenn die von ecrecover zurückgegebene Adresse der Adresse entspricht, die zum Signieren der Nachricht verwendet wird (sie ist auf die privaten Schlüssel bezogen und muss im Vertrag manuell eingestellt werden).

Hashing mit SHA256

Diese Hashing-Funktion gibt den SHA256-Hash aus den angegebenen Daten zurück. Um diese Vorkompilierung zu testen, können Sie mit diesem Online-Tool den SHA256-Hash eines beliebigen Strings berechnen. In unserem Fall tun wir dies mit Hello World!. Wir können direkt zu Remix gehen und den folgenden Code bereitstellen, in dem der berechnete Hash für die expectedHash Variable festgelegt wird:

pragma solidity ^0.7.0;

contract Hash256{

bytes32 public expectedHash = 0x7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069;

function calculateHash() internal pure returns (bytes32) {

string memory word = ‘Hello World!’;

bytes32 hash = sha256(bytes (word));

return hash;

}

function checkHash() public view returns(bool) {

return (calculateHash() == expectedHash);

}

}

Sobald der Vertrag bereitgestellt wurde, können wir die Methode checkHash() aufrufen, die true zurückgibt, wenn der von calculateHash() zurückgegebene Hash dem bereitgestellten Hash entspricht.

Hashing mit RIPEMD-160

Diese Hashing-Funktion gibt einen RIPEMD-160-Hash aus den angegebenen Daten zurück. Um diese Vorkompilierung zu testen, können Sie mit diesem Online-Tool den RIPEMD-160-Hash eines beliebigen Strings berechnen. In unserem Fall werden wir dies mit Hello World! wiederholen. Wir werden den gleichen Code wie zuvor wiederverwenden, verwenden jedoch die Funktion ripemd160. Beachten Sie, dass es eine Variable vom Typ bytes20 zurückgibt:

pragma solidity ^0.7.0;

contract HashRipmd160{

bytes20 public expectedHash = hex’8476ee4631b9b30ac2754b0ee0c47e161d3f724c’;

function calculateHash() internal pure returns (bytes20) {

string memory word = ‘Hello World!’;

bytes20 hash = ripemd160(bytes (word));

return hash;

}

function checkHash() public view returns(bool) {

return (calculateHash() == expectedHash);

}

}

Wenn der Vertrag bereitgestellt ist, können wir die Methode checkHash() aufrufen, die true zurückgibt, wenn der von computeHash() zurückgegebene Hash dem bereitgestellten Hash entspricht.

Die Identitätsfunktion

Diese Funktion wird auch als Datenkopie bezeichnet und dient als kostengünstigere Möglichkeit, Daten in den Speicher zu kopieren. Der Solidity-Compiler unterstützt dies nicht, daher muss er mit Inline-Assembly aufgerufen werden. Der folgende Code (angepasst an Solidity) kann verwendet werden, um diesen vorkompilierten Vertrag aufzurufen. Wir können dieses Online-Tool verwenden, um Bytes aus einem beliebigen String zu erhalten, da dies die Eingabe der Methode callDataCopy() ist.

pragma solidity ^0.7.0;

contract Identity{

bytes public memoryStored;

function callDatacopy(bytes memory data) public returns (bytes memory) {

bytes memory result = new bytes(data.length);

assembly {

let len := mload(data)

if iszero(call(gas(), 0x04, 0, add(data, 0x20), len, add(result,0x20), len)) {

invalid()

}

}

memoryStored = result;

return result;

}

}

Wenn der Vertrag bereitgestellt ist, können wir die Methode callDataCopy() aufrufen und überprüfen, ob memoryStored mit den Bytes übereinstimmt, die Sie als Eingabe der Funktion übergeben.

Modulare Exponentiation

Diese fünfte Vorkompilierung berechnet den Rest, wenn eine ganze Zahl b (Basis) auf die e-te Potenz (der Exponent) erhöht und durch eine positive ganze Zahl m (den Modul) dividiert wird.

Der Solidity-Compiler unterstützt dies nicht, daher muss er mit Inline-Assembly aufgerufen werden. Der folgende Code wurde vereinfacht, um die Funktionalität dieser Vorkompilierung zu zeigen.

pragma solidity ^0.7.0;

contract ModularCheck {

uint public checkResult;

// Function to Verify ModExp Result

function verify( uint _base, uint _exp, uint _modulus) public {

checkResult = modExp(_base, _exp, _modulus);

}

function modExp(uint256 _b, uint256 _e, uint256 _m) public returns (uint256 result) {

assembly {

// Free memory pointer

let pointer := mload(0x40)

// Define length of base, exponent and modulus. 0x20 == 32 bytes

mstore(pointer, 0x20)

mstore(add(pointer, 0x20), 0x20)

mstore(add(pointer, 0x40), 0x20)

// Define variables base, exponent and modulus

mstore(add(pointer, 0x60), _b)

mstore(add(pointer, 0x80), _e)

mstore(add(pointer, 0xa0), _m)

// Store the result

let value := mload(0xc0)

// Call the precompiled contract 0x05 = bigModExp

if iszero(call(not(0), 0x05, 0, pointer, 0xc0, value, 0x20)) {

revert(0, 0)

}

result := mload(value)

}

}

}

Sie können dies in Remix versuchen. Verwenden Sie die Funktion verify() und übergeben Sie Basis, Exponent und Modul. Die Funktion speichert den Wert in der Variablen checkResult.

--

--