Hoang  Ha

Hoang Ha

1657683000

Kiểm Tra đơn Vị Và Triển Khai Hợp Đồng Thông Minh Với Forge

Vào tháng 12 năm 2021, công ty đầu tư tiền điện tử lớn nhất thế giới, CTO Georgios của Paradigm Lab đã phát hành một blog về việc phát hành một khuôn khổ mới để phát triển hợp đồng thông minh (dựa trên evm), được gọi là Foundry.

Nó đã đưa cộng đồng tiền điện tử như vũ bão và sớm trở thành tiêu chuẩn công nghiệp để phát triển và thử nghiệm các hợp đồng thông minh, nhờ vào hiệu quả của nó so với các khuôn khổ khác.

Để hiểu được tầm quan trọng của Foundry, trước tiên chúng ta cần xem xét các vấn đề mà nó cố gắng giải quyết.

Vấn đề chính nằm ở các framework như Hardhat và Truffle là chúng yêu cầu các nhà phát triển phải biết một ngôn ngữ kịch bản như JavaScript / TypeScript để làm việc với framework.

Vì những ngôn ngữ kịch bản đó nặng về phát triển web, nhà phát triển solidity không cần biết những ngôn ngữ như vậy để phát triển hợp đồng thông minh vì nó được coi là hướng đến phụ trợ nhiều hơn.

Một vấn đề khác là bản thân hardhat được triển khai bằng TypeScript, vì vậy nó chậm hơn Foundry vì sau này được triển khai bằng Rust.

(Lưu ý: Nếu bạn quan tâm đến việc kiểm tra điểm chuẩn, vui lòng xem mô phỏng này )

Biểu đồ so sánh thời gian biên dịch giữa Forge và Hardhat

Foundry có rất nhiều tính năng thú vị ngoài điều này như:

  • Dấu vết ngăn xếp cuộc gọi
  • Trình gỡ lỗi tương tác
  • Inbuilt-fuzzing
  • Tập lệnh Solidity

Bây giờ, tôi hy vọng bạn có cái nhìn tổng quan về Foundry và sự cần thiết của việc thử nghiệm các hợp đồng thông minh bằng Solidity. Foundry xuất xưởng với hai công cụ CLI tuyệt vời:

 

  • Forge: Được sử dụng để thử nghiệm và triển khai các hợp đồng thông minh
  • Truyền: Được sử dụng để tương tác với các hợp đồng thông minh đã triển khai

Bắt đầu nào.

Cài đặt xưởng đúc

Cài đặt Foundry rất đơn giản và dễ hiểu.

Mở thiết bị đầu cuối của bạn và chạy:

curl -L https://foundry.paradigm.xyz | bash && foundryup

Sau khi Foundry được cài đặt, bạn có thể bắt đầu sử dụng Forge and Cast ngay lập tức.

Đối với một số hệ điều hành, bạn có thể muốn cài đặt gỉ trước khi cài đặt Foundry.

Thiết lập dự án Foundry

Bạn có thể thiết lập ngay một dự án Foundry ngay lập tức bằng cách chạy

rèn init <PROJECT_NAME>

Để làm cho cuộc sống của bạn dễ dàng hơn, tôi đã tạo một kho lưu trữ mẫu để bạn có thể bắt đầu dễ dàng hơn. Nó chứa các thư viện, tập lệnh và thiết lập thư mục cần thiết. Vì vậy, tất cả những gì bạn cần làm là chỉ cần chạy lệnh sau trong thiết bị đầu cuối của bạn:

Lệnh trên tạo một thư mục mới được gọi foundry-faucetvà khởi tạo một dự án Foundry mới bằng cách sử dụng mẫu của tôi. Đây sẽ là cấu trúc thư mục. Các thư mục và tệp quan trọng mà chúng tôi muốn tập trung vào là:

Cấu trúc thư mục

  • lib: Cái này chứa tất cả các thư viện / phụ thuộc mà chúng ta sẽ sử dụng. Ví dụ: nếu chúng ta muốn sử dụng Solmate, nó sẽ nằm dưới dạng một mô-đun con git bên trong thư mục này
  • script: Thư mục này có tất cả các script, như triển khai và xác minh hợp đồng
  • src: Thư mục này có tất cả các hợp đồng và các bài kiểm tra được liên kết với các hợp đồng
  • Foundry.toml: Tệp này chứa các tùy chọn cấu hình cho dự án Foundry hiện tại

Chúng ta cũng nên cập nhật và cài đặt các thư viện được sử dụng; để chạy các lệnh sau:

git submodule update --init --recursive
forge install

Tạo hợp đồng vòi đơn giản

Bây giờ, chúng tôi sẽ triển khai hợp đồng vòi cho mã thông báo ERC20 của chúng tôi, có thể nhỏ giọt mã thông báo khi được yêu cầu. Chúng tôi cũng có thể hạn chế số lượng mã thông báo cho mỗi yêu cầu bằng cách đặt một mã limitsẽ được 100mặc định trong hợp đồng của chúng tôi.

Mở src/Faucet.soltệp và thêm mã sau:

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.13;

import {Ownable} from "openzeppelin-contracts/access/Ownable.sol";
import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";

contract Faucet is Ownable {
   /// Address of the token that this faucet drips
   IERC20 public token;

   /// For rate limiting
   mapping(address => uint256) public nextRequestAt;
   /// Max token limit per request
   uint256 public limit = 100;

   /// @param _token The address of the faucet's token
   constructor(IERC20 _token) {
       token = _token;
   }

   /// Used to send the tokens
   /// @param _recipient The address of the tokens recipient
   /// @param _amount The amount of tokens required from the faucet
   function drip(address _recipient, uint256 _amount) external {
       require(_recipient != address(0), "INVALID_RECIPIENT");

       require(_amount <= limit, "EXCEEDS_LIMIT");

       require(nextRequestAt[_recipient] <= block.timestamp, "TRY_LATER");
       nextRequestAt[_recipient] = block.timestamp + (5 minutes);

       token.transfer(_recipient, _amount);
   }

   /// Used to set the max limit per request
   /// @dev This method is restricted and should be called only by the owner
   /// @param _limit The new limit for the tokens per request
   function setLimit(uint256 _limit) external onlyOwner {
       limit = _limit;
   }
}

Hợp đồng vòi của chúng tôi đã được thêm vào. Bây giờ chúng ta có thể tiếp tục và biên dịch các hợp đồng bằng cách chạy:

forge build

Nếu mọi thứ suôn sẻ, bạn sẽ thấy một kết quả tương tự:

[⠒] Compiling...
[⠒] Compiling 14 files with 0.8.13
Compiler run successful

Ngọt! Chúng tôi đã thiết lập thành công dự án Foundry của mình và biên soạn hợp đồng của chúng tôi mà không có bất kỳ sai sót nào! Công việc tốt, anon🎉

Bây giờ, chúng tôi có thể tiếp tục và bắt đầu thử nghiệm hợp đồng Vòi của mình.

Kiểm tra đơn vị bằng Forge

Như bạn đã biết, không giống như Hardhat, Forge giúp chúng ta viết các bài kiểm tra đơn vị bằng Solidity.

Nếu bạn mở src/test/Faucet.t.soltệp, bạn sẽ thấy một số nhập utils và hợp đồng BaseSetup.

Hợp đồng thiết lập cơ sở

Nó có một số thiết lập ban đầu khởi tạo một số biến mà chúng tôi có thể sử dụng trong các thử nghiệm của mình. Ngoài ra, setUp()chức năng này tương tự như beforeEachtrong hardhat và nó chạy trước mọi bài kiểm tra.

Hàm setUp()tạo hai địa chỉ và gắn nhãn cho chúng AliceBob. Sẽ rất hữu ích khi bạn cố gắng gỡ lỗi thông qua dấu vết cuộc gọi vì nhãn xuất hiện trong dấu vết cùng với địa chỉ.

(Lưu ý: vm.label được gọi là mã cheatcode và nó dành riêng cho Forge; Nó giúp chúng tôi thực hiện một số hoạt động đặc biệt bằng cách tương tác với máy ảo trong bản thử nghiệm. Chúng ta sẽ thấy nhiều mã cheatcode hơn trong quá trình của bài viết. Đối với danh sách đầy đủ các cheatcodes, bạn có thể tham khảo liên kết này )

Thay thế Faucet.t.solmã bằng mã sau để bắt đầu với các bài kiểm tra đơn vị;

// SPDX-License-Identifier: MIT
pragma solidity >=0.8;

import {console} from "forge-std/console.sol";
import {stdStorage, StdStorage, Test} from "forge-std/Test.sol";
import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";

import {Utils} from "./utils/Utils.sol";
import {Faucet} from "../Faucet.sol";
import {MockERC20} from "../MockERC20.sol";

contract BaseSetup is Test {
   Utils internal utils;
   Faucet internal faucet;
   MockERC20 internal token;

   address payable[] internal users;
   address internal owner;
   address internal dev;
   uint256 internal faucetBal = 1000;

   function setUp() public virtual {
       utils = new Utils();
       users = utils.createUsers(2);
       owner = users[0];
       vm.label(owner, "Owner");
       dev = users[1];
       vm.label(dev, "Developer");

       token = new MockERC20();
       faucet = new Faucet(IERC20(token));
       token.mint(address(faucet), faucetBal);
   }
}

Bạn có thể thấy rằng bây giờ chúng tôi đã tạo các biến trạng thái mới như faucet, tokenvà chúng tôi cũng đã đổi tên alicebobthành ownerdevđể dễ hiểu. Trong ngữ cảnh này, devlà ai đó yêu cầu mã thông báo từ vòi trong khi người đó ownerlà chủ sở hữu của chính vòi đó.

Trong ba dòng cuối cùng của setUp()phương pháp, chúng tôi triển khai mã thông báo giả cho vòi, chuyển địa chỉ của nó vào phương thức khởi tạo của new Faucet()(triển khai vòi), sau đó gọi và đúc một số mã thông báo cho hợp đồng vòi đã triển khai.

Bây giờ, chúng tôi sẽ kế thừa BaseSetuphợp đồng viết các bài kiểm tra đơn vị cho hợp đồng Vòi của chúng tôi.

Bên dưới BaseSetuphợp đồng, hãy thêm mã sau:

contract FaucetTest is BaseSetup {
   uint256 amountToDrip = 1;

   function setUp() public override {
       super.setUp();
   }

Như đã đề cập trước đó, setUp()phương thức chạy trước tất cả các testcase và ở đây chúng ta đang gọi setUp()phương thức của hợp đồng cơ sở là BaseSetuphợp đồng thông qua super.setUp().

Được rồi, bây giờ chúng ta hãy bắt đầu thêm các bài kiểm tra đơn vị cho hợp đồng của mình. Ngay bên dưới setUp()phương thức của hợp đồng FaucetTest, hãy thêm đoạn mã sau:

   function test_drip_transferToDev() public {
       console.log(
           "Should transfer tokens to recipient when `drip()` is called"
       );
       uint256 _inititalDevBal = token.balanceOf(dev);

       /// Make sure that initial dev balance is Zero
       assertEq(_inititalDevBal, 0);

       /// Request some tokens to the dev wallet from the wallet
       faucet.drip(dev, amountToDrip);

       uint256 _devBalAfterDrip = token.balanceOf(dev);

      /// The difference should be equal to the amount requested from the faucet
       assertEq(_devBalAfterDrip - _inititalDevBal, amountToDrip);
   }

Đoạn mã trên giúp chúng tôi kiểm tra drip()phương pháp. Quy trình làm việc rất đơn giản.

  1. Đầu tiên, lưu trữ số dư ban đầu của nhà phát triển trong một biến (_inititalDevBal)
  2. Hãy chắc chắn rằng nó là 0, vì chúng tôi không đúc bất kỳ mã thông báo nào cho nhà phát triển. Đây là những gì dòng assertEq(_inititalDevBal, 0);làm
  3. Sau đó, gọi drip()phương thức từ phiên faucetbản hợp đồng
  4. Lấy số dư devsau khi drip()được gọi là
  5. Chênh lệch giữa số dư của devtài khoản trước và sau drip()phải bằng amountToDrip, được lưu trữ dưới dạng biến trạng thái trong hợp đồng FaucetTest

Bây giờ, chúng ta hãy lưu tệp và chạy thử nghiệm :.forge test

Bạn sẽ thấy đầu ra trong thiết bị đầu cuối của mình tương tự như sau:

Biên dịch kết quả kiểm tra trong thiết bị đầu cuối

Mát mẻ! Hãy thêm một số thử nghiệm nữa.

Kiểm tra ở trên xác minh rằng drip()phương pháp chuyển các mã thông báo đến dev. Vì vậy, chúng tôi cũng nên kiểm tra xem chuyển khoản có hợp lệ không, có nghĩa là số dư mã thông báo của vòi sẽ bị giảm.

Thêm thử nghiệm sau đây bên dưới - test_drip_transferToDev()phương pháp.

 function test_drip_reduceFaucetBalance() public {
       console.log("The faucet balance should be reduced");
       faucet.drip(dev, amountToDrip);
       assertEq(token.balanceOf(address(faucet)), faucetBal - amountToDrip);
   }

Điều này đảm bảo rằng các mã thông báo mà nhà phát triển nhận được thực sự được gửi từ vòi - nếu vậy, số dư của vòi sẽ được giảm bớt.

Chúng tôi có thể đảm bảo bằng cách chạy lại bộ thử nghiệm:forge test

Nếu mọi thứ diễn ra tốt đẹp, thì đầu ra của bạn sẽ tương tự như sau:

Biên dịch kết quả kiểm tra trong thiết bị đầu cuối

Ngọt! Nếu bạn nhận thấy, chúng tôi có console.logcác câu lệnh trong các trường hợp thử nghiệm của mình, nhưng chúng không hiển thị trong bảng điều khiển. Lý do là Forge không hiển thị nhật ký theo mặc định. Để hiển thị các bản ghi, chúng ta cần chạy lệnh với verbosity 2: forge test -vvsẽ hiển thị các bản ghi.

Biên dịch kết quả kiểm tra trong thiết bị đầu cuối

Ngoài ra, nếu có bất kỳ sự kiện nào được tạo ra bởi hợp đồng của bạn, bạn có thể xem chúng trong các bài kiểm tra với độ dài ba (-vvv). Bạn có thể nhận được dấu vết cuộc gọi chi tiết cho các bài kiểm tra của mình cao đến mức độ chi tiết năm, giúp gỡ lỗi tốt hơn.

Được rồi, chúng ta hãy tiếp tục thêm các bài kiểm tra khác. Bây giờ chúng tôi sẽ kiểm tra cơ chế giới hạn tỷ giá của chúng tôi. Phải có khoảng thời gian ít nhất là năm phút trước khi gọi drip()với cùng một địa chỉ người nhận.

   function test_drip_revertIfThrottled() public {
       console.log("Should revert if tried to throttle");
       faucet.drip(dev, amountToDrip);

       vm.expectRevert(abi.encodePacked("TRY_LATER"));
       faucet.drip(dev, amountToDrip);
   }

vm.expectRevert(bytes32)là một mã gian lận khác để kiểm tra xem cuộc gọi tiếp theo có hoàn nguyên với thông báo lỗi đã cho hay không. Trong trường hợp này, thông báo lỗi là TRY_LATER. Nó chấp nhận thông báo lỗi dưới dạng byte không phải là chuỗi, do đó chúng tôi đang sử dụng abi.encodePacked.

Nếu bạn còn nhớ, tôi đã đề cập rằng Forge xuất xưởng với một bộ phận làm mờ. Thử một lần đi.

Chúng tôi kết hợp các bài kiểm tra test_drip_transferToDevtest_drip_reduceFaucetBalancethay vì chuyển các đầu vào theo cách thủ công, chúng tôi sẽ cho phép bộ mờ nhập các giá trị để chúng tôi có thể đảm bảo rằng hợp đồng của chúng tôi xử lý các đầu vào khác nhau.

   function test_drip_withFuzzing(address _recipient, uint256 _amount) public {
       console.log("Should handle fuzzing");
       /// inform the constraints to the fuzzer, so that the tests don't revert on bad inputs.
       vm.assume(_amount <= 100);
       vm.assume(_recipient != address(0));
       uint256 _inititalBal = token.balanceOf(_recipient);
       faucet.drip(_recipient, _amount);
       uint256 _balAfterDrip = token.balanceOf(_recipient);
       assertEq(_balAfterDrip - _inititalBal, _amount);
       assertEq(token.balanceOf(address(faucet)), faucetBal - _amount);
   }

Fuzzing là thử nghiệm dựa trên tài sản. Forge sẽ áp dụng fuzzing cho bất kỳ bài kiểm tra nào có ít nhất một tham số.

Khi bạn thực thi bộ thử nghiệm, bạn có thể tìm thấy dòng sau trong đầu ra:

[PASS] test_drip_withFuzzing (địa chỉ, uint256) (chạy: 256)

Từ kết quả đầu ra ở trên, chúng ta có thể suy ra rằng Forge fuzzer được gọi là phương thức test_drip_withFuzzing () 256lần với các đầu vào ngẫu nhiên. Tuy nhiên, chúng ta có thể ghi đè số này bằng cách sử dụng FOUNDRY_FUZZ_RUNSbiến môi trường.

Bây giờ, hãy để chúng tôi thêm một vài thử nghiệm khác cho phương pháp chỉ dành cho chủ sở hữusetLimit()

function test_setLimit() public {
       console.log("Should set the limit when called by the owner");
       faucet.setLimit(1000);

       /// the limit should be updated assertEq(faucet.limit(), 1000); } function test_setLimit_revertIfNotOwner() public {console.log("Should revert if not called by Owner"); /// Sets the msg.sender as dev for the next tx vm.prank(dev); vm.expectRevert(abi.encodePacked("Ownable: caller is not the owner")); faucet.setLimit(1000); }

Trong test_setLimit_revertIfNotOwner()phương thức này, một mã cheatcode mới vm.prank(address)được sử dụng. Nó chơi khăm vm bằng cách ghi đè msg.sender bằng địa chỉ đã cho; trong trường hợp của chúng tôi là dev. Vì vậy, setLimit()nên hoàn nguyên với caller is not the ownerthông báo vì hợp đồng Vòi của chúng tôi kế thừa Ownablehợp đồng.

Được rồi, hãy để chúng tôi đảm bảo rằng không có thử nghiệm nào bị lỗi bằng cách chạy forge testlại.

Đầu ra thiết bị đầu cuối thử nghiệm giả mạo

Bây giờ đã đến lúc triển khai.

Hợp đồng triển khai tới Kovan testnet

Tạo một tệp mới từ .env.exampletệp và đặt tên là .env. Vui lòng điền INFURA_API_KEY của bạn và PRIVATE_KEY (với quỹ Kovan testnet).

Khi tất cả các trường đã được điền, bạn đã sẵn sàng triển khai cho Kovan. Trước khi triển khai vòi, chúng tôi cần triển khai mã thông báo ERC20 của mình.

Bạn có thể tìm thấy các tập lệnh triển khai bên trong thư mục scriptsvà triển khai mã thông báo MockERC20 cho Kovan testnet bằng cách thực thi ./scripts/deploy_token_kovan.shtập lệnh bash.

Đầu ra sẽ giống như sau:

Deployer: (YOUR_DEPLOYMENT_ADDRESS)

Deployed to: 0x1a70d8a2a02c9cf0faa5551304ba770b5496ed80

Transaction hash: 0xa3780d2e3e1d1f9346035144f3c2d62f31918b613a370f416a4fb1a6c2eadc77

Để đảm bảo rằng giao dịch đã thực sự được thực hiện, bạn có thể tìm kiếm băm giao dịch trong https://kovan.etherscan.io

Sao chép Deployed to:địa chỉ, vì đó là địa chỉ của mã thông báo MockERC20 mà chúng tôi nên sử dụng để triển khai hợp đồng Vòi của mình. Để triển khai vòi, bạn có thể thực thi ./scripts/deploy_faucet_kovan.shtập lệnh.

Nó sẽ nhắc bạn nhập địa chỉ mã thông báo; sau đó nhập địa chỉ mã thông báo MockERC20 đã sao chép đã được triển khai trước đó.

Đầu ra sẽ trông giống như sau:

Nhập địa chỉ hợp đồng mã thông báo và biên dịch

Woohoo  Chúng tôi đã biên dịch, thử nghiệm và triển khai thành công hợp đồng của chúng tôi với mạng thử nghiệm Kovan bằng cách sử dụng Forge

Chúng tôi vẫn cần xác minh hợp đồng trên Etherscan và cũng đúc một số mã thông báo MockERC20 vào Vòi (bạn có thể sử dụng đúc cho việc này!) Để nó hoạt động như dự định. Tôi sẽ để lại điều này cho các bạn như một bài tập để các bạn tự thử nhé!

Như mọi khi, bạn có thể tìm thấy kho lưu trữ GitHub cho bài viết này tại đây .

Sự kết luận

Trong bài viết này, chúng tôi chỉ đề cập đến một vài phần của Forge. Foundry là một khuôn khổ rất mạnh mẽ cho các hợp đồng thông minh và nó cũng đang phát triển nhanh chóng.

Có nhiều tính năng thú vị hơn như bảo hiểm mã, xác minh hợp đồng, ảnh chụp nhanh khí, theo dõi cuộc gọi và gỡ lỗi tương tác. Hãy thoải mái chơi với repo bằng cách thử nghiệm nhiều tính năng hơn. Chúc bạn viết mã vui vẻ

Nguồn: https://blog.logrocket.com/unit-testing-smart-contracts-forge/

 #testing  #forge  #etherum  #foundry 

What is GEEK

Buddha Community

Kiểm Tra đơn Vị Và Triển Khai Hợp Đồng Thông Minh Với Forge
Hoang  Ha

Hoang Ha

1657683000

Kiểm Tra đơn Vị Và Triển Khai Hợp Đồng Thông Minh Với Forge

Vào tháng 12 năm 2021, công ty đầu tư tiền điện tử lớn nhất thế giới, CTO Georgios của Paradigm Lab đã phát hành một blog về việc phát hành một khuôn khổ mới để phát triển hợp đồng thông minh (dựa trên evm), được gọi là Foundry.

Nó đã đưa cộng đồng tiền điện tử như vũ bão và sớm trở thành tiêu chuẩn công nghiệp để phát triển và thử nghiệm các hợp đồng thông minh, nhờ vào hiệu quả của nó so với các khuôn khổ khác.

Để hiểu được tầm quan trọng của Foundry, trước tiên chúng ta cần xem xét các vấn đề mà nó cố gắng giải quyết.

Vấn đề chính nằm ở các framework như Hardhat và Truffle là chúng yêu cầu các nhà phát triển phải biết một ngôn ngữ kịch bản như JavaScript / TypeScript để làm việc với framework.

Vì những ngôn ngữ kịch bản đó nặng về phát triển web, nhà phát triển solidity không cần biết những ngôn ngữ như vậy để phát triển hợp đồng thông minh vì nó được coi là hướng đến phụ trợ nhiều hơn.

Một vấn đề khác là bản thân hardhat được triển khai bằng TypeScript, vì vậy nó chậm hơn Foundry vì sau này được triển khai bằng Rust.

(Lưu ý: Nếu bạn quan tâm đến việc kiểm tra điểm chuẩn, vui lòng xem mô phỏng này )

Biểu đồ so sánh thời gian biên dịch giữa Forge và Hardhat

Foundry có rất nhiều tính năng thú vị ngoài điều này như:

  • Dấu vết ngăn xếp cuộc gọi
  • Trình gỡ lỗi tương tác
  • Inbuilt-fuzzing
  • Tập lệnh Solidity

Bây giờ, tôi hy vọng bạn có cái nhìn tổng quan về Foundry và sự cần thiết của việc thử nghiệm các hợp đồng thông minh bằng Solidity. Foundry xuất xưởng với hai công cụ CLI tuyệt vời:

 

  • Forge: Được sử dụng để thử nghiệm và triển khai các hợp đồng thông minh
  • Truyền: Được sử dụng để tương tác với các hợp đồng thông minh đã triển khai

Bắt đầu nào.

Cài đặt xưởng đúc

Cài đặt Foundry rất đơn giản và dễ hiểu.

Mở thiết bị đầu cuối của bạn và chạy:

curl -L https://foundry.paradigm.xyz | bash && foundryup

Sau khi Foundry được cài đặt, bạn có thể bắt đầu sử dụng Forge and Cast ngay lập tức.

Đối với một số hệ điều hành, bạn có thể muốn cài đặt gỉ trước khi cài đặt Foundry.

Thiết lập dự án Foundry

Bạn có thể thiết lập ngay một dự án Foundry ngay lập tức bằng cách chạy

rèn init <PROJECT_NAME>

Để làm cho cuộc sống của bạn dễ dàng hơn, tôi đã tạo một kho lưu trữ mẫu để bạn có thể bắt đầu dễ dàng hơn. Nó chứa các thư viện, tập lệnh và thiết lập thư mục cần thiết. Vì vậy, tất cả những gì bạn cần làm là chỉ cần chạy lệnh sau trong thiết bị đầu cuối của bạn:

Lệnh trên tạo một thư mục mới được gọi foundry-faucetvà khởi tạo một dự án Foundry mới bằng cách sử dụng mẫu của tôi. Đây sẽ là cấu trúc thư mục. Các thư mục và tệp quan trọng mà chúng tôi muốn tập trung vào là:

Cấu trúc thư mục

  • lib: Cái này chứa tất cả các thư viện / phụ thuộc mà chúng ta sẽ sử dụng. Ví dụ: nếu chúng ta muốn sử dụng Solmate, nó sẽ nằm dưới dạng một mô-đun con git bên trong thư mục này
  • script: Thư mục này có tất cả các script, như triển khai và xác minh hợp đồng
  • src: Thư mục này có tất cả các hợp đồng và các bài kiểm tra được liên kết với các hợp đồng
  • Foundry.toml: Tệp này chứa các tùy chọn cấu hình cho dự án Foundry hiện tại

Chúng ta cũng nên cập nhật và cài đặt các thư viện được sử dụng; để chạy các lệnh sau:

git submodule update --init --recursive
forge install

Tạo hợp đồng vòi đơn giản

Bây giờ, chúng tôi sẽ triển khai hợp đồng vòi cho mã thông báo ERC20 của chúng tôi, có thể nhỏ giọt mã thông báo khi được yêu cầu. Chúng tôi cũng có thể hạn chế số lượng mã thông báo cho mỗi yêu cầu bằng cách đặt một mã limitsẽ được 100mặc định trong hợp đồng của chúng tôi.

Mở src/Faucet.soltệp và thêm mã sau:

// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.13;

import {Ownable} from "openzeppelin-contracts/access/Ownable.sol";
import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";

contract Faucet is Ownable {
   /// Address of the token that this faucet drips
   IERC20 public token;

   /// For rate limiting
   mapping(address => uint256) public nextRequestAt;
   /// Max token limit per request
   uint256 public limit = 100;

   /// @param _token The address of the faucet's token
   constructor(IERC20 _token) {
       token = _token;
   }

   /// Used to send the tokens
   /// @param _recipient The address of the tokens recipient
   /// @param _amount The amount of tokens required from the faucet
   function drip(address _recipient, uint256 _amount) external {
       require(_recipient != address(0), "INVALID_RECIPIENT");

       require(_amount <= limit, "EXCEEDS_LIMIT");

       require(nextRequestAt[_recipient] <= block.timestamp, "TRY_LATER");
       nextRequestAt[_recipient] = block.timestamp + (5 minutes);

       token.transfer(_recipient, _amount);
   }

   /// Used to set the max limit per request
   /// @dev This method is restricted and should be called only by the owner
   /// @param _limit The new limit for the tokens per request
   function setLimit(uint256 _limit) external onlyOwner {
       limit = _limit;
   }
}

Hợp đồng vòi của chúng tôi đã được thêm vào. Bây giờ chúng ta có thể tiếp tục và biên dịch các hợp đồng bằng cách chạy:

forge build

Nếu mọi thứ suôn sẻ, bạn sẽ thấy một kết quả tương tự:

[⠒] Compiling...
[⠒] Compiling 14 files with 0.8.13
Compiler run successful

Ngọt! Chúng tôi đã thiết lập thành công dự án Foundry của mình và biên soạn hợp đồng của chúng tôi mà không có bất kỳ sai sót nào! Công việc tốt, anon🎉

Bây giờ, chúng tôi có thể tiếp tục và bắt đầu thử nghiệm hợp đồng Vòi của mình.

Kiểm tra đơn vị bằng Forge

Như bạn đã biết, không giống như Hardhat, Forge giúp chúng ta viết các bài kiểm tra đơn vị bằng Solidity.

Nếu bạn mở src/test/Faucet.t.soltệp, bạn sẽ thấy một số nhập utils và hợp đồng BaseSetup.

Hợp đồng thiết lập cơ sở

Nó có một số thiết lập ban đầu khởi tạo một số biến mà chúng tôi có thể sử dụng trong các thử nghiệm của mình. Ngoài ra, setUp()chức năng này tương tự như beforeEachtrong hardhat và nó chạy trước mọi bài kiểm tra.

Hàm setUp()tạo hai địa chỉ và gắn nhãn cho chúng AliceBob. Sẽ rất hữu ích khi bạn cố gắng gỡ lỗi thông qua dấu vết cuộc gọi vì nhãn xuất hiện trong dấu vết cùng với địa chỉ.

(Lưu ý: vm.label được gọi là mã cheatcode và nó dành riêng cho Forge; Nó giúp chúng tôi thực hiện một số hoạt động đặc biệt bằng cách tương tác với máy ảo trong bản thử nghiệm. Chúng ta sẽ thấy nhiều mã cheatcode hơn trong quá trình của bài viết. Đối với danh sách đầy đủ các cheatcodes, bạn có thể tham khảo liên kết này )

Thay thế Faucet.t.solmã bằng mã sau để bắt đầu với các bài kiểm tra đơn vị;

// SPDX-License-Identifier: MIT
pragma solidity >=0.8;

import {console} from "forge-std/console.sol";
import {stdStorage, StdStorage, Test} from "forge-std/Test.sol";
import {IERC20} from "openzeppelin-contracts/token/ERC20/IERC20.sol";

import {Utils} from "./utils/Utils.sol";
import {Faucet} from "../Faucet.sol";
import {MockERC20} from "../MockERC20.sol";

contract BaseSetup is Test {
   Utils internal utils;
   Faucet internal faucet;
   MockERC20 internal token;

   address payable[] internal users;
   address internal owner;
   address internal dev;
   uint256 internal faucetBal = 1000;

   function setUp() public virtual {
       utils = new Utils();
       users = utils.createUsers(2);
       owner = users[0];
       vm.label(owner, "Owner");
       dev = users[1];
       vm.label(dev, "Developer");

       token = new MockERC20();
       faucet = new Faucet(IERC20(token));
       token.mint(address(faucet), faucetBal);
   }
}

Bạn có thể thấy rằng bây giờ chúng tôi đã tạo các biến trạng thái mới như faucet, tokenvà chúng tôi cũng đã đổi tên alicebobthành ownerdevđể dễ hiểu. Trong ngữ cảnh này, devlà ai đó yêu cầu mã thông báo từ vòi trong khi người đó ownerlà chủ sở hữu của chính vòi đó.

Trong ba dòng cuối cùng của setUp()phương pháp, chúng tôi triển khai mã thông báo giả cho vòi, chuyển địa chỉ của nó vào phương thức khởi tạo của new Faucet()(triển khai vòi), sau đó gọi và đúc một số mã thông báo cho hợp đồng vòi đã triển khai.

Bây giờ, chúng tôi sẽ kế thừa BaseSetuphợp đồng viết các bài kiểm tra đơn vị cho hợp đồng Vòi của chúng tôi.

Bên dưới BaseSetuphợp đồng, hãy thêm mã sau:

contract FaucetTest is BaseSetup {
   uint256 amountToDrip = 1;

   function setUp() public override {
       super.setUp();
   }

Như đã đề cập trước đó, setUp()phương thức chạy trước tất cả các testcase và ở đây chúng ta đang gọi setUp()phương thức của hợp đồng cơ sở là BaseSetuphợp đồng thông qua super.setUp().

Được rồi, bây giờ chúng ta hãy bắt đầu thêm các bài kiểm tra đơn vị cho hợp đồng của mình. Ngay bên dưới setUp()phương thức của hợp đồng FaucetTest, hãy thêm đoạn mã sau:

   function test_drip_transferToDev() public {
       console.log(
           "Should transfer tokens to recipient when `drip()` is called"
       );
       uint256 _inititalDevBal = token.balanceOf(dev);

       /// Make sure that initial dev balance is Zero
       assertEq(_inititalDevBal, 0);

       /// Request some tokens to the dev wallet from the wallet
       faucet.drip(dev, amountToDrip);

       uint256 _devBalAfterDrip = token.balanceOf(dev);

      /// The difference should be equal to the amount requested from the faucet
       assertEq(_devBalAfterDrip - _inititalDevBal, amountToDrip);
   }

Đoạn mã trên giúp chúng tôi kiểm tra drip()phương pháp. Quy trình làm việc rất đơn giản.

  1. Đầu tiên, lưu trữ số dư ban đầu của nhà phát triển trong một biến (_inititalDevBal)
  2. Hãy chắc chắn rằng nó là 0, vì chúng tôi không đúc bất kỳ mã thông báo nào cho nhà phát triển. Đây là những gì dòng assertEq(_inititalDevBal, 0);làm
  3. Sau đó, gọi drip()phương thức từ phiên faucetbản hợp đồng
  4. Lấy số dư devsau khi drip()được gọi là
  5. Chênh lệch giữa số dư của devtài khoản trước và sau drip()phải bằng amountToDrip, được lưu trữ dưới dạng biến trạng thái trong hợp đồng FaucetTest

Bây giờ, chúng ta hãy lưu tệp và chạy thử nghiệm :.forge test

Bạn sẽ thấy đầu ra trong thiết bị đầu cuối của mình tương tự như sau:

Biên dịch kết quả kiểm tra trong thiết bị đầu cuối

Mát mẻ! Hãy thêm một số thử nghiệm nữa.

Kiểm tra ở trên xác minh rằng drip()phương pháp chuyển các mã thông báo đến dev. Vì vậy, chúng tôi cũng nên kiểm tra xem chuyển khoản có hợp lệ không, có nghĩa là số dư mã thông báo của vòi sẽ bị giảm.

Thêm thử nghiệm sau đây bên dưới - test_drip_transferToDev()phương pháp.

 function test_drip_reduceFaucetBalance() public {
       console.log("The faucet balance should be reduced");
       faucet.drip(dev, amountToDrip);
       assertEq(token.balanceOf(address(faucet)), faucetBal - amountToDrip);
   }

Điều này đảm bảo rằng các mã thông báo mà nhà phát triển nhận được thực sự được gửi từ vòi - nếu vậy, số dư của vòi sẽ được giảm bớt.

Chúng tôi có thể đảm bảo bằng cách chạy lại bộ thử nghiệm:forge test

Nếu mọi thứ diễn ra tốt đẹp, thì đầu ra của bạn sẽ tương tự như sau:

Biên dịch kết quả kiểm tra trong thiết bị đầu cuối

Ngọt! Nếu bạn nhận thấy, chúng tôi có console.logcác câu lệnh trong các trường hợp thử nghiệm của mình, nhưng chúng không hiển thị trong bảng điều khiển. Lý do là Forge không hiển thị nhật ký theo mặc định. Để hiển thị các bản ghi, chúng ta cần chạy lệnh với verbosity 2: forge test -vvsẽ hiển thị các bản ghi.

Biên dịch kết quả kiểm tra trong thiết bị đầu cuối

Ngoài ra, nếu có bất kỳ sự kiện nào được tạo ra bởi hợp đồng của bạn, bạn có thể xem chúng trong các bài kiểm tra với độ dài ba (-vvv). Bạn có thể nhận được dấu vết cuộc gọi chi tiết cho các bài kiểm tra của mình cao đến mức độ chi tiết năm, giúp gỡ lỗi tốt hơn.

Được rồi, chúng ta hãy tiếp tục thêm các bài kiểm tra khác. Bây giờ chúng tôi sẽ kiểm tra cơ chế giới hạn tỷ giá của chúng tôi. Phải có khoảng thời gian ít nhất là năm phút trước khi gọi drip()với cùng một địa chỉ người nhận.

   function test_drip_revertIfThrottled() public {
       console.log("Should revert if tried to throttle");
       faucet.drip(dev, amountToDrip);

       vm.expectRevert(abi.encodePacked("TRY_LATER"));
       faucet.drip(dev, amountToDrip);
   }

vm.expectRevert(bytes32)là một mã gian lận khác để kiểm tra xem cuộc gọi tiếp theo có hoàn nguyên với thông báo lỗi đã cho hay không. Trong trường hợp này, thông báo lỗi là TRY_LATER. Nó chấp nhận thông báo lỗi dưới dạng byte không phải là chuỗi, do đó chúng tôi đang sử dụng abi.encodePacked.

Nếu bạn còn nhớ, tôi đã đề cập rằng Forge xuất xưởng với một bộ phận làm mờ. Thử một lần đi.

Chúng tôi kết hợp các bài kiểm tra test_drip_transferToDevtest_drip_reduceFaucetBalancethay vì chuyển các đầu vào theo cách thủ công, chúng tôi sẽ cho phép bộ mờ nhập các giá trị để chúng tôi có thể đảm bảo rằng hợp đồng của chúng tôi xử lý các đầu vào khác nhau.

   function test_drip_withFuzzing(address _recipient, uint256 _amount) public {
       console.log("Should handle fuzzing");
       /// inform the constraints to the fuzzer, so that the tests don't revert on bad inputs.
       vm.assume(_amount <= 100);
       vm.assume(_recipient != address(0));
       uint256 _inititalBal = token.balanceOf(_recipient);
       faucet.drip(_recipient, _amount);
       uint256 _balAfterDrip = token.balanceOf(_recipient);
       assertEq(_balAfterDrip - _inititalBal, _amount);
       assertEq(token.balanceOf(address(faucet)), faucetBal - _amount);
   }

Fuzzing là thử nghiệm dựa trên tài sản. Forge sẽ áp dụng fuzzing cho bất kỳ bài kiểm tra nào có ít nhất một tham số.

Khi bạn thực thi bộ thử nghiệm, bạn có thể tìm thấy dòng sau trong đầu ra:

[PASS] test_drip_withFuzzing (địa chỉ, uint256) (chạy: 256)

Từ kết quả đầu ra ở trên, chúng ta có thể suy ra rằng Forge fuzzer được gọi là phương thức test_drip_withFuzzing () 256lần với các đầu vào ngẫu nhiên. Tuy nhiên, chúng ta có thể ghi đè số này bằng cách sử dụng FOUNDRY_FUZZ_RUNSbiến môi trường.

Bây giờ, hãy để chúng tôi thêm một vài thử nghiệm khác cho phương pháp chỉ dành cho chủ sở hữusetLimit()

function test_setLimit() public {
       console.log("Should set the limit when called by the owner");
       faucet.setLimit(1000);

       /// the limit should be updated assertEq(faucet.limit(), 1000); } function test_setLimit_revertIfNotOwner() public {console.log("Should revert if not called by Owner"); /// Sets the msg.sender as dev for the next tx vm.prank(dev); vm.expectRevert(abi.encodePacked("Ownable: caller is not the owner")); faucet.setLimit(1000); }

Trong test_setLimit_revertIfNotOwner()phương thức này, một mã cheatcode mới vm.prank(address)được sử dụng. Nó chơi khăm vm bằng cách ghi đè msg.sender bằng địa chỉ đã cho; trong trường hợp của chúng tôi là dev. Vì vậy, setLimit()nên hoàn nguyên với caller is not the ownerthông báo vì hợp đồng Vòi của chúng tôi kế thừa Ownablehợp đồng.

Được rồi, hãy để chúng tôi đảm bảo rằng không có thử nghiệm nào bị lỗi bằng cách chạy forge testlại.

Đầu ra thiết bị đầu cuối thử nghiệm giả mạo

Bây giờ đã đến lúc triển khai.

Hợp đồng triển khai tới Kovan testnet

Tạo một tệp mới từ .env.exampletệp và đặt tên là .env. Vui lòng điền INFURA_API_KEY của bạn và PRIVATE_KEY (với quỹ Kovan testnet).

Khi tất cả các trường đã được điền, bạn đã sẵn sàng triển khai cho Kovan. Trước khi triển khai vòi, chúng tôi cần triển khai mã thông báo ERC20 của mình.

Bạn có thể tìm thấy các tập lệnh triển khai bên trong thư mục scriptsvà triển khai mã thông báo MockERC20 cho Kovan testnet bằng cách thực thi ./scripts/deploy_token_kovan.shtập lệnh bash.

Đầu ra sẽ giống như sau:

Deployer: (YOUR_DEPLOYMENT_ADDRESS)

Deployed to: 0x1a70d8a2a02c9cf0faa5551304ba770b5496ed80

Transaction hash: 0xa3780d2e3e1d1f9346035144f3c2d62f31918b613a370f416a4fb1a6c2eadc77

Để đảm bảo rằng giao dịch đã thực sự được thực hiện, bạn có thể tìm kiếm băm giao dịch trong https://kovan.etherscan.io

Sao chép Deployed to:địa chỉ, vì đó là địa chỉ của mã thông báo MockERC20 mà chúng tôi nên sử dụng để triển khai hợp đồng Vòi của mình. Để triển khai vòi, bạn có thể thực thi ./scripts/deploy_faucet_kovan.shtập lệnh.

Nó sẽ nhắc bạn nhập địa chỉ mã thông báo; sau đó nhập địa chỉ mã thông báo MockERC20 đã sao chép đã được triển khai trước đó.

Đầu ra sẽ trông giống như sau:

Nhập địa chỉ hợp đồng mã thông báo và biên dịch

Woohoo  Chúng tôi đã biên dịch, thử nghiệm và triển khai thành công hợp đồng của chúng tôi với mạng thử nghiệm Kovan bằng cách sử dụng Forge

Chúng tôi vẫn cần xác minh hợp đồng trên Etherscan và cũng đúc một số mã thông báo MockERC20 vào Vòi (bạn có thể sử dụng đúc cho việc này!) Để nó hoạt động như dự định. Tôi sẽ để lại điều này cho các bạn như một bài tập để các bạn tự thử nhé!

Như mọi khi, bạn có thể tìm thấy kho lưu trữ GitHub cho bài viết này tại đây .

Sự kết luận

Trong bài viết này, chúng tôi chỉ đề cập đến một vài phần của Forge. Foundry là một khuôn khổ rất mạnh mẽ cho các hợp đồng thông minh và nó cũng đang phát triển nhanh chóng.

Có nhiều tính năng thú vị hơn như bảo hiểm mã, xác minh hợp đồng, ảnh chụp nhanh khí, theo dõi cuộc gọi và gỡ lỗi tương tác. Hãy thoải mái chơi với repo bằng cách thử nghiệm nhiều tính năng hơn. Chúc bạn viết mã vui vẻ

Nguồn: https://blog.logrocket.com/unit-testing-smart-contracts-forge/

 #testing  #forge  #etherum  #foundry 

Hoang  Ha

Hoang Ha

1660636803

Phát Triển Và Triển Khai Hợp Đồng Thông Minh Tezos

Tezos là một trong những blockchain hợp đồng thông minh lâu đời nhất, với Ethereum là blockchain đầu tiên.

Trong khi Ethereum là một lựa chọn phổ biến trong số các nhà phát triển để phát triển và triển khai các hợp đồng thông minh, các ứng dụng của nó không có khả năng mở rộng cao do phí cao và giao dịch chậm. Ngược lại, các ứng dụng Tezos rất hiệu quả và không tốn kém để thiết lập.

Trong hướng dẫn này, bạn sẽ học cách phát triển và triển khai các hợp đồng thông minh trong Tezos với SmartPy CLI. 

Bạn có thể lấy mã cuối cùng của dự án trong repo GitHub này .

Điều kiện tiên quyết

Để theo dõi bài viết này, bạn cần phải làm quen với chuỗi khối Tezos. Kiến thức của bạn không cần phải chuyên sâu.

Kiến thức về chuỗi khối Ethereum không bắt buộc, nhưng nó giúp ích rất nhiều.

Tezos là gì?

Tezos là một mạng lưới blockchain và một nền tảng hợp đồng thông minh được xây dựng để thích ứng thông qua mô hình quản trị và khả năng tự nâng cấp của nó.

Mặc dù Tezos và Ethereum là các blockchain tương tự hỗ trợ các hợp đồng thông minh và phát triển DApp, nhưng chúng khác nhau theo một số cách. Bảng Tezos so với Ethereum dưới đây cho thấy một số điểm khác biệt giữa hai mạng.

Tezos và Ethereum: Biểu đồ so sánh

TezosEthereum
Các nhà phát triển đưa ra đề xuất nâng cấp giao thức blockchain trên mạngCác nhà phát triển sử dụng một hardfork để nâng cấp giao thức blockchain
Các bên liên quan kiểm soát các nâng cấp đối với giao thức blockchain bằng cách bỏ phiếu chấp nhận hoặc từ chối đề xuấtNhững người tạo ra mạng lưới blockchain quản lý các nâng cấp đối với giao thức blockchain
Sử dụng xác minh chính thức để thực hiện các hợp đồng thông minhSử dụng EVM để lưu trữ và thực thi các hợp đồng thông minh trên mạng
Người tham gia (nút) có tùy chọn cung cấp tài nguyên máy tính hoặc ủy quyền mã thông báo của họ để tham gia xác thực giao dịchTất cả những người tham gia (các nút) phải cung cấp tài nguyên máy tính và đặt tiền của họ để tham gia xác thực giao dịch
Phí gas thấp nên rất dễ mở rộngPhí xăng thực sự cao, khiến nó không thể tính được

SmartPy là gì?

SmartPy là một công cụ cho phép bạn xây dựng các hợp đồng thông minh một cách dễ dàng trên chuỗi khối Tezos.

Bạn viết hợp đồng trong SmartPy bằng Python. Nếu bạn đã quen thuộc với Python, bạn không cần phải học một ngôn ngữ lập trình hợp đồng thông minh mới .

SmartPy có hai biến thể khác sử dụng các cú pháp khác: SmartTS, sử dụng TypeScript và SmartML, sử dụng OCaml.

SmartPy biên dịch các tập lệnh Python cho Michelson. Michelson là một ngôn ngữ lập trình cấp thấp cho các hợp đồng thông minh trong Tezos. SmartTS và SmartML cũng có thể được biên dịch bằng công cụ SmartPy.

Hợp đồng thông minh là gì?

Hợp đồng thông minh là các chương trình mà bạn có thể xây dựng, triển khai và thực thi trên mạng blockchain. Bạn không cần phải sở hữu một nút trên mạng trước khi triển khai hợp đồng thông minh của mình.

Với hợp đồng thông minh, bạn có thể xây dựng các ứng dụng có thể truy cập được trên tất cả các thiết bị mà không cần sở hữu hoặc duy trì máy chủ. Các ứng dụng hoàn toàn phi tập trung này yêu cầu ít hoặc không cần bảo trì.

Hợp đồng thông minh sử dụng toàn bộ tiềm năng của blockchain, cho phép bạn thực thi các chương trình trên chuỗi cũng như tương tác với chính chuỗi. Bạn có thể giữ hoặc chuyển các mã thông báo và truy cập chức năng chuyên biệt trên blockchain bằng một hợp đồng thông minh.

Bắt đầu với SmartPy CLI

Để cài đặt SmartPy CLI, hãy chạy lệnh dưới đây:

$ bash <(curl -s https://smartpy.io/cli/install.sh)

Lệnh này tạo một smartpy-clithư homemục với cấu trúc cây này:

smartpy-cli
├── browser.py
├── node_modules/
├── originator.js
├── package.json
├── package-lock.json
├── __pycache__/
├── smart.css
├── smart.js
├── smartpyc.js
├── smartpyc.py
├── smartpyio.py
├── smartpy.py
├── SmartPy.sh
├── smarttop/
├── smart-ts-cli.js
├── templates/
├── theme.js
└── typography.css

Để xác nhận cài đặt, hãy chạy như sau:

$ ~/smartpy-cli/SmartPy.sh --version

Là một bước bổ sung để có SmartPy.shthể truy cập dễ dàng, hãy tạo bí danh bằng cách sao chép thông tin bên dưới vào .bashrctệp của bạn hoặc tệp hồ sơ liên quan:

$ alias smartpy="$HOME/smartpy-cli/SmartPy.sh"

Bây giờ bạn có thể sử dụng:

$ smartpy --version

Thay vì:

$ ~/smartpy-cli/SmartPy.sh --version

Đang cài đặttezos-client

Hướng dẫn này sử dụng tezos-clientđể tương tác với hợp đồng thông minh đã triển khai. Để cài đặt tezos-client,, hãy chạy một trong các lệnh bên dưới, tùy thuộc vào việc bạn đang sử dụng hệ điều hành Mac hay Linux:

# Mac
$ brew tap serokell/tezos-packaging-stable https://github.com/serokell/tezos-packaging-stable.git
$ brew install tezos-client

# Linux
$ wget https://github.com/serokell/tezos-packaging/releases/latest/download/tezos-client
$ chmod +x tezos-client
$ mkdir -p $HOME/.local/bin
$ mv tezos-client $HOME/.local/bin
$ echo 'export PATH="$HOME/.local/bin:$PATH"' >> $HOME/.bashrc
$ source $HOME/.bashrc

Lưu ý rằng nếu bạn đang sử dụng Windows, bạn cần cài đặt một bản phân phối Linux với wsl và chạy cài đặt Linux.

Sau khi cài đặt tezos-client, bạn cần thiết lập nó. Bắt đầu bằng cách chạy lệnh dưới đây:

$ tezos-client --endpoint https://jakartanet.ecadinfra.com config update

Hướng dẫn này sử dụng Jarkatanet testnet để triển khai và tương tác với một hợp đồng thông minh. Lệnh trên kết nối tezos-clientvới mạng kiểm thử Jakartanet thông qua nút https://jakartanet.ecadinfra.comtrên mạng.

Trước khi thực hiện bất kỳ thao tác nào với tezos-client, bạn cần kết nối tài khoản. Tezos cung cấp tài khoản Vòi cho phép bạn tương tác với mạng miễn phí.

Bạn cần truy cập trang web Jakartanet Faucet và tải xuống tệp Faucet. Sau khi làm điều đó, hãy mở thư mục tải xuống trong thiết bị đầu cuối của bạn và chạy lệnh này:

$ tezos-client activate account faucet with ./jakartanet.json

Lệnh kích hoạt tài khoản Vòi trong của bạn tezos-clientvà đặt cho nó một bí danh faucet. Để kiểm tra số dư cho tài khoản này, hãy mở jakartanet.jsontệp, sao chép giá trị của pkh, sau đó chạy lệnh sau:

$ tezos-client get balance for <address>

Thay thế <address>bằng pkhgiá trị mà bạn đã sao chép.

Lưu ý rằng tài khoản Tezos Faucet được cung cấp công khai cho tất cả mọi người và có số lượng thẻ Tez giới hạn, vì vậy bạn phải điều chỉnh việc sử dụng của mình.

Phát triển hợp đồng thông minh Tezos với SmartPy

Để bắt đầu tạo hợp đồng thông minh mẫu của chúng tôi, hãy tạo một store_text.pytệp mới và sao chép thông tin bên dưới vào đó:

import smartpy as sp

class StoreText(sp.Contract):
    def __init__(self, value):
        self.init(text = value)

    @sp.entry_point
    def replace(self, params):
        self.data.text = params.text

    @sp.entry_point    # Note: the spaces before "@"
    def append(self, params):
        self.data.text += params.text

Đây là cách thức hoạt động của hợp đồng trên, từng phần:

Đầu tiên, chúng tôi đã nhập smartpythư viện:

import smartpy as sp

Sau đó, chúng tôi đã xác định một lớp mở rộng sp.Contract:

class StoreText(sp.Contract):

Cuối cùng, chúng tôi đã xác định một số mục trong hợp đồng thông minh; đầu tiên, một phương thức khởi tạo để khởi tạo text:

    def __init__(self, value):    # Note: the spaces before "def"
        self.init(text = value)

Thứ hai, một điểm vào để thay thế giá trị của text:

    @sp.entry_point    # Note: the spaces before "@"
    def replace(self, params):
        self.data.text = params.text

Thứ ba, một điểm nhập để nối một chuỗi vào text:

    @sp.entry_point    # Note: the spaces before "@"
    def append(self, params):
        self.data.text += params.text

Tiếp theo, chúng ta hãy xem cách kiểm tra hợp đồng thông minh.

Thử nghiệm hợp đồng thông minh Tezos

Không thể thay đổi hoặc xóa các hợp đồng thông minh được triển khai cho Tezos. Đây có thể là một vấn đề vì có thể có sai sót trong hợp đồng và sai sót có thể dẫn đến sai lầm tốn kém và mất tiền.

SmartPy cung cấp cho bạn khả năng dễ dàng kiểm tra hợp đồng của mình trước khi triển khai. Việc kiểm tra hợp đồng không yêu cầu bất kỳ mã thông báo hoặc tài khoản ví nào để chạy. Tất cả những gì bạn cần làm là mở store_text.pytệp và sao chép bên dưới tệp:

@sp.add_test(name = "StoreText")
def test():
  scenario = sp.test_scenario()
  contract = StoreText("Hello")
  scenario += contract

  scenario.verify(contract.data.text == "Hello")

  contract.replace(text = "Hi")
  contract.append(text = ", there!")
  scenario.verify(contract.data.text == "Hi, there!")

Đây là cách đoạn mã hoạt động. Đầu tiên, chúng tôi đã đăng ký một testhàm dưới dạng tập lệnh thử nghiệm:

@sp.add_test(name = "StoreText")

Sau đó, chúng tôi xác định testhàm:

def test():

Trong những dòng còn lại, chúng tôi đã tạo một kịch bản thử nghiệm:

  scenario = sp.test_scenario()

Khởi tạo hợp đồng với "Hello":

  contract = StoreText("Hello")

Đã thêm phiên bản hợp đồng vào kịch bản:

  scenario += contract

Đã xác minh rằng textgiá trị của hợp đồng là "Hello":

  scenario.verify(contract.data.text == "Hello")

Được gọi là điểm replaceappendđiểm vào:

  contract.replace(text = "Hi")
  contract.append(text = ", there!")

Và cuối cùng, đã xác minh rằng textgiá trị của hợp đồng bây giờ là "Hi, there":

  scenario.verify(contract.data.text == "Hi, there!")

Sau khi thêm thử nghiệm, hãy lưu tệp và chạy lệnh này:

$ ~/smartpy-cli/SmartPy.sh test store_text.py ./test-output

Nếu kiểm tra thành công, trình biên dịch sẽ không đưa ra thông báo lỗi.

Biên soạn hợp đồng thông minh cho Michelson

Trước khi triển khai hợp đồng thông minh của mình, bạn cần phải biên dịch nó sang Michelson. Như đã đề cập trước đó, Michelson là một ngôn ngữ lập trình cấp thấp được sử dụng cho các hợp đồng thông minh trên chuỗi khối Tezos.

Để biên dịch store_text.py, hãy chạy như sau:

$ ~/smartpy-cli/SmartPy.sh compile message.py ./output

Nếu nó được biên dịch thành công, bạn sẽ thấy một outputthư mục giống như bên dưới:

output/
├── scenario.json
├── script_init.py
├── script_pure.py
└── storeMessage/
    ├── log.txt
    ├── step_000_cont_0_contract.json
    ├── step_000_cont_0_contract.py
    ├── step_000_cont_0_contract.tz
    ├── step_000_cont_0_sizes.csv
    ├── step_000_cont_0_storage.json
    ├── step_000_cont_0_storage.py
    ├── step_000_cont_0_storage.tz
    └── step_000_cont_0_types.py

Thư outputmục chứa tất cả các tệp cần thiết để triển khai hợp đồng thông minh.

Triển khai hợp đồng thông minh Tezos

Để triển khai store_text.py, hãy mở output/storeMessagethư mục trong terminal và chạy lệnh bên dưới:

$ ~/smartpy-cli/SmartPy.sh originate-contract --code step_000_cont_0_contract.json --storage step_000_cont_0_storage.json --rpc https://jakartanet.ecadinfra.com

[INFO] - Using RPC https://jakartanet.ecadinfra.com/...
[INFO] - Contract KT1………………CAjjW originated!!!

Đây là cách hoạt động của lệnh:

  • originate-contractyêu tezos-clientcầu triển khai (“khởi tạo”) một hợp đồng
  • --code step_000_cont_0_contract.jsontrỏ đến tệp hợp đồng đã biên dịch
  • --storage step_000_cont_0_storage.jsontrỏ đến tệp lưu trữ đã biên dịch
  • --rpc https://jakartanet.ecadinfra.comtrỏ đến một nút RPC trên mạng mà bạn đang triển khai

Hợp đồng thông minh của Tezos thường liên quan đến hai thành phần: bộ nhớ và hợp đồng. Bộ nhớ lưu trữ dữ liệu mà hợp đồng lưu trữ và hợp đồng giữ logic của hợp đồng thông minh.

Lưu ý rằng bạn có thể triển khai hợp đồng với bất kỳ tập hợp hợp đồng hoặc bộ lưu trữ nào. Chúng chỉ phải là cùng một phần mở rộng tệp khi bạn đang sử dụng lệnh.

Theo mặc định, nếu bạn đang triển khai trên testnet, trình biên dịch sẽ sử dụng tài khoản Vòi. Nếu bạn đang triển khai mạng chính hoặc bạn muốn sử dụng tài khoản ví của mình, hãy thêm --private-keycờ theo sau là khóa cá nhân của tài khoản.

Tương tác với hợp đồng thông minh đã triển khai

Trước khi tương tác với hợp đồng thông minh đã triển khai, bạn cần biết hợp đồng hiện tại trông như thế nào. Để làm điều đó, hãy mở SmartPy Explorer trong trình duyệt của bạn và làm theo các bước sau:

  1. Điều hướng đến “Nút thay thế”
  2. Dán địa chỉ của hợp đồng vào đầu vào "Hợp đồng"
  3. Trong “Khám phá trên một nút cụ thể”, hãy chuyển từ mainnetsangjakartanet
  4. Dán URL RPC https://jakartanet.ecadinfra.comvào hộp văn bản
  5. Nhấp vào “Khám phá trên một nút cụ thể”

Khi dữ liệu hợp đồng đã xuất hiện, bộ lưu trữ văn bản sẽ hiển thị là "Xin chào!"

Bây giờ bạn đã biết nội dung của hợp đồng, bạn có thể thay đổi nó thành "Xin chào!" bằng cách gọi replaceentrypoint với lệnh này:

$ tezos-client transfer 0 from faucet to <contract-address> --entrypoint replace --arg '"Hi, There!"'

Nếu lệnh thành công, khi bạn làm mới trình khám phá, bộ nhớ bây giờ sẽ hiển thị “Xin chào!”

Lưu ý rằng bạn phải thay thế <contract-address>bằng địa chỉ của hợp đồng đã triển khai trước khi chạy lệnh.

Sự kết luận

Bài viết này đề cập đến quá trình xây dựng hợp đồng thông minh trên Tezos với SmartPy. Xây dựng các hợp đồng thông minh cho phép bạn tận dụng toàn bộ lợi thế của mạng blockchain để xây dựng các ứng dụng và tổ chức phi tập trung.

Tôi hy vọng bài viết này đã giúp bạn hiểu quy trình xây dựng hợp đồng thông minh trên Tezos. Nếu bạn muốn đọc thêm về hợp đồng thông minh, hãy xem bài viết này về những sai lầm trong hợp đồng thông minh cần tránh.

Cảm ơn vì đã đọc! Và có một ngày tốt đẹp. Phát triển và triển khai hợp đồng thông minh Tezos

Nguồn: https://blog.logrocket.com/developing-deploy-tezos-smart-contracts/

#tezos  #smartpy 

Hong  Nhung

Hong Nhung

1641270900

Phát triển và triển khai các Hợp đồng Thông minh cho Terra Blockchain

Phát triển hợp đồng thông minh Terra

Tìm hiểu cách có thể phát triển các hợp đồng thông minh và triển khai chúng vào mạng blockchain Terra để tạo các ứng dụng phi tập trung.

Việc xây dựng các hợp đồng thông minh của riêng bạn đã có từ khi ra đời Web 3, cho phép mọi người xây dựng các chương trình để triển khai vào một chuỗi khối.

Các blockchain triển khai hợp đồng thông minh bao gồm từ Ethereum đến Bitcoin và hơn thế nữa. Hơn nữa, các hợp đồng thông minh làm việc cùng nhau để tạo nên các ứng dụng phi tập trung, có thể được phát triển trên các khuôn khổ như Truffle, Hardhat và Embark.

Trong bài viết này, chúng ta sẽ xem xét cách chúng ta có thể phát triển các hợp đồng thông minh và triển khai chúng vào mạng blockchain Terra, tương tự như Ethereum.

Tổng quan cơ bản về Terra

Một số điều cần lưu ý về Terra trước khi đọc tiếp:

  • Các hợp đồng thông minh được triển khai cho blockchain Terra được viết bằng Rust
  • mạng thử nghiệm cục bộ của chúng tôi là LocalTerra
  • Terra.jsTerra SDK là hai thư viện có sẵn được sử dụng để tương tác với blockchain Terra
  • Terra được tạo bởi Terraform Labs

Ngoài ra, hãy lưu ý rằng sự đồng thuận của Terra là thuật toán bằng chứng cổ phần sử dụng Tendermint BFT. Điều này cho phép chủ sở hữu đặt cọc làm tài sản thế chấp để xác thực các giao dịch. Phần thưởng được trao sau đó tương ứng với số lượng mã thông báo được đặt cọc.

Cũng cần biết rằng LUNA là tiền điện tử của Terra và được sử dụng để cung cấp năng lượng cho chuỗi khối bằng chứng cổ phần. Chuỗi khối này mang lại sự ổn định về giá bằng cách mở rộng theo thuật toán và giảm nguồn cung.

Để hiểu thêm, tôi khuyên bạn nên đọc tài liệu tại đây . Trọng tâm chính của chúng tôi cho bài viết này là cách chúng tôi có thể triển khai hợp đồng thông minh của mình cho giao thức blockchain này.

Và cuối cùng, blockchain Terra tự hào có một cơ chế đồng thuận mạnh mẽ và mạnh mẽ giúp hoàn thành các lô giao dịch trong vài giây - nhanh hơn so với Bitcoin và Ethereum .

Yêu cầu và kiến ​​thức cơ bản về phát triển

Hãy để chúng tôi xem xét các yêu cầu cần thiết để xây dựng và triển khai hợp đồng thông minh bằng giao thức Terra:

  • Kiến thức ngôn ngữ lập trình rỉ sét
  • Làm quen với hệ sinh thái Terra
  • Docker được cài đặt trên máy tính của bạn
  • Lõi trái đất
  • LocalTerra

Tuy nhiên, đừng lo lắng về những yêu cầu trên nếu bạn chưa có, chúng tôi sẽ bao quát hết. Tuy nhiên, một yêu cầu cuối cùng cần thiết theo nhóm Terra là có mong muốn phá vỡ / xáo trộn tài chính truyền thống.

Thiết lập môi trường

Có một số thứ chúng ta cần cài đặt trước khi bắt đầu. Việc cài đặt này sẽ giúp chúng tôi kết nối với mạng thử nghiệm cục bộ của Terra khi viết hợp đồng và cung cấp phiên bản mới nhất của terrad. terradhoạt động với lõi Terra .

Bạn cũng sẽ cần cài đặt Rust nếu chưa có.

Để bắt đầu, hãy cài đặt Terra Core, yêu cầu chúng tôi cài đặt Go trước. Để thực hiện việc này, hãy tải xuống Go bằng liên kết này và xác minh:

➜  ~ go version
go version go1.17 darwin/amd64

Chuyển sang phiên bản v1.17 +, bắt buộc phải sử dụng Terra Core.

Cài đặt Terra Core

Cài đặt Terra Core bằng cách sao chép kho lưu trữ từ GitHub. Sau đó, hãy kiểm tra chi nhánh chính có bản phát hành mới nhất:

$ git clone https://github.com/terra-money/core terra-core
$ cd terra-core
$ git checkout main

Tiếp theo, cài đặt Terra Core để lấy terrad, nó sẽ đóng vai trò là tệp thực thi để tương tác với nút Terra:

$ make install

Sau đó, xác minh rằng bạn đã cài đặt thành công:

$ terrad version --long

Đầu ra của bạn sẽ trông giống như sau:

name: terra
server_name: terrad
version: 0.5.12-1-gd411ae7
commit: d411ae7a276e7eaada72973a640dcab69825163f
build_tags: netgo,ledger
go: go version go1.17 darwin/amd64

Cài đặt LocalTerra

LocalTerra sẽ là mạng thử nghiệm của chúng tôi để kiểm tra các hợp đồng thông minh của chúng tôi trong khi phát triển. Mạng thử nghiệm cục bộ của chúng tôi bao gồm tích hợp WebAssembly . Để tạo LocalTerra, bạn cần phải có Docker vàdocker-compose  thiết lập vì LocalTerra được chứa:

$ git clone --depth 1 https://www.github.com/terra-money/LocalTerra
$ cd LocalTerra

Với Docker chạy trong nền, hãy chạy lệnh sau:

$ docker-compose up

Bạn sẽ nhận được phản hồi bên dưới, đó là các bản ghi:

 11:25PM INF Timed out dur=4955.7669 height=5 module=consensus round=0 step=1
terrad_1         | 11:25PM INF received proposal module=consensus proposal={"Type":32,"block_id":{"hash":"54D9C757E9AA84E0F5AAA736E6EED3D83F364A3A62FDC625970539CA81DFA86E","parts":{"hash":"2517579A126AC2BF6EB9EB6274FAE6748D14115C91FC59FE3A2AF5F061A12740","total":1}},"height":5,"pol_round":-1,"round":0,"signature":"AMxXngubsUHyterTZuZsiLgY0olPDpdpgjMIRZ9L59UR9+JngC93xO63yTxwE0kQLp2HdZ99G8M4ATchS7d1CA==","timestamp":"2021-12-16T23:25:00.8000592Z"}
terrad_1         | 11:25PM INF received complete proposal block hash=54D9C757E9AA84E0F5AAA736E6EED3D83F364A3A62FDC625970539CA81DFA86E height=5 module=consensus
terrad_1         | 11:25PM INF finalizing commit of block hash=54D9C757E9AA84E0F5AAA736E6EED3D83F364A3A62FDC625970539CA81DFA86E height=5 module=consensus num_txs=0 root=84C2F2EF6B7FC8B3ACED8B2B0D2921D649F13CE54C5AB5B032DE988D1392E0FD
terrad_1         | 11:25PM INF minted coins from module account amount=226569846uluna from=mint module=x/bank
terrad_1         | 11:25PM INF executed block height=5 module=state num_invalid_txs=0 num_valid_txs=0
terrad_1         | 11:25PM INF commit synced commit=436F6D6D697449447B5B32382031303020373220323137203234312038352031363320313520313530203137382031353820323235203133312032343620313538203235322031333420313238203134392031383220323033203131372039382031333420312035382032333720323120333620313534203136203134335D3A357D
terrad_1         | 11:25PM INF committed state app_hash=1C6448D9F155A30F96B29EE183F69EFC868095B6CB756286013AED15249A108F height=5 module=state num_txs=0
terrad_1         | 11:25PM INF indexed block height=5 module=txindex
terrad_1         | 11:25PM INF Ensure peers module=pex numDialing=0 numInPeers=0 numOutPeers=0 numToDial=10
terrad_1         | 11:25PM INF No addresses to dial. Falling back to seeds module=pex
terrad_1         | 11:25PM INF Timed out dur=4975.4085 height=6 module=consensus round=0 step=1
terrad_1         | 11:25PM INF received proposal module=consensus proposal={"Type":32,"block_id":{"hash":"5FE8526C43C0B32BEF011299D67FDA44DBD625E0B69836D175C25C1F914DD06E","parts":{"hash":"BE583EC25B30F52E652FA28DEAB869D98602B3FB82CD0D9C80ADF96A210CC8D4","total":1}},"height":6,"pol_round":-1,"round":0,"signature":"Bx3WaDl3hhR9IkDjXRa+dXkSIK0Tezl07gZhDm4RXyJyHq0oriAkQD23Q9+ly1+cFhGIdKF3hyvH3GcjCNLvAQ==","timestamp":"2021-12-16T23:25:05.823444Z"}

Bây giờ, chúng tôi đã kết nối với mạng LocalTerra. Sau đây là số cổng để kết nối:

Cài đặt Rust

Rust là thứ Terra đã chọn để sử dụng và viết các hợp đồng thông minh vì Rust có thể biên dịch thành WebAssembly và công cụ WebAssembly đã hoàn thiện và được xây dựng cho Terra.

Để cài đặt Rust trên MacOS hoặc bất kỳ hệ điều hành giống Linux nào, hãy chạy lệnh sau:

$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

Nếu bạn đang sử dụng Windows, hãy sử dụng liên kết này .

Sau khi cài đặt thành công, chúng ta phải thêm wasm32-unknown-unknownđích để biên dịch:

$ rustup target add wasm32-unknown-unknown

Cuối cùng, hãy cài đặt cargo-generateđể tạo mẫu hợp đồng thông minh CosmWasm và cargo-run-scriptđể tối ưu hóa các hợp đồng thông minh của chúng tôi:

$ cargo install cargo-generate --features vendored-openssl
$ cargo install cargo-run-script

Cuối cùng thì chúng ta cũng đã hoàn thành việc cài đặt🙂!

Viết và khám phá hợp đồng thông minh trong Terra

Với mạng LocalTerra của chúng tôi đang chạy và đang chờ chúng tôi, chúng tôi đã sẵn sàng để viết một hợp đồng thông minh nhỏ, triển khai chúng và chúng tôi đã hoàn tất trong ngày!

Kể từ khi chúng tôi cài đặt cargo-generate, chúng tôi có thể nhanh chóng tạo ra một dự án đang hoạt động. Điều này sẽ giúp chúng tôi với cấu trúc thư mục để viết các hợp đồng của chúng tôi. Để thực hiện việc này, hãy sử dụng lệnh sau:

$ cargo generate --git https://github.com/CosmWasm/cw-template.git --name PROJECT_NAME

Đối với PROJECT_NAME, bạn nên đặt tên cho dự án của bạn. Dưới đây là những gì bạn sẽ nhận được sau khi chạy lệnh trước:

Vectormikes-MacBook-Pro:Projects macbookpro$ cargo generate --git https://github.com/CosmWasm/cw-template.git --name terra-demo
   Generating template ...
[ 1/34]   Done: .cargo/config
[ 2/34]   Done: .cargo
[ 3/34]   Skipped: .circleci/config.yml
[ 4/34]   Done: .circleci
[ 1/34]   Done: .cargo/config
[ 2/34]   Done: .cargo
[ 3/34]   Skipped: .circleci/config.yml
[ 4/34]   Done: .circleci
[ 5/34]   Done: .editorconfig
[ 6/34]   Done: .github/workflows/Basic.yml
[ 7/34]   Done: .github/workflows
[ 8/34]   Done: .github
[ 9/34]   Done: .gitignore
[10/34]   Done: .gitpod.Dockerfile
[11/34]   Done: .gitpod.yml
[ 1/34]   Done: .cargo/config
[ 2/34]   Done: .cargo
[ 3/34]   Skipped: .circleci/config.yml
[ 4/34]   Done: .circleci
[ 5/34]   Done: .editorconfig
[ 6/34]   Done: .github/workflows/Basic.yml
[ 7/34]   Done: .github/workflows
[ 8/34]   Done: .github
[ 9/34]   Done: .gitignore
[10/34]   Done: .gitpod.Dockerfile
[11/34]   Done: .gitpod.yml
[12/34]   Done: Cargo.lock
[13/34]   Done: Cargo.toml
[14/34]   Done: Developing.md
[15/34]   Done: Importing.md
[16/34]   Done: LICENSE
[17/34]   Done: NOTICE
[18/34]   Done: Publishing.md
[19/34]   Done: README.md
[20/34]   Done: examples/schema.rs
[21/34]   Done: examples
[22/34]   Done: rustfmt.toml
[23/34]   Done: schema/count_response.json
[24/34]   Done: schema/execute_msg.json
[25/34]   Done: schema/instantiate_msg.json
[26/34]   Done: schema/query_msg.json
[27/34]   Done: schema/state.json
[28/34]   Done: schema
[29/34]   Done: src/contract.rs
[30/34]   Done: src/error.rs
[31/34]   Done: src/lib.rs
[32/34]   Done: src/msg.rs
[33/34]   Done: src/state.rs
[34/34]   Done: src
   Moving generated files into: `/Users/macbookpro/Desktop/Projects/terra-demo`...
   Done! New project created /Users/macbookpro/Desktop/Projects/terra-demo

Nhìn vào src/msg.rstệp, chúng ta có thể thấy ba loại thông điệp mà chúng ta có thể gửi tới hợp đồng thông minh của mình. Đầu tiên, điều này bao gồm InstantiateMsg, thiết lập trạng thái trong hợp đồng thông minh, nghĩa là trạng thái ban đầu phải được cấp cho hợp đồng thông minh khi nó được tạo ra.

Thứ hai, ExecuteMsglà một thông báo thực hiện một hành động đối với sự thay đổi trạng thái, chẳng hạn như đăng một thông báo lên blockchain. Và cuối cùng, QueryMsgđúng như âm thanh của nó: nó hoạt động như một truy vấn đối với chuỗi, lấy dữ liệu từ nó.

Hãy xem cách sử dụng chúng được sử dụng trong mã:

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct InstantiateMsg {
    pub count: i32,
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum ExecuteMsg {
    Increment {},
    Reset { count: i32 },
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
#[serde(rename_all = "snake_case")]
pub enum QueryMsg {
    // GetCount returns the current count as a json-encoded number
    GetCount {},
}
// We define a custom struct for each query response
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct CountResponse {
    pub count: i32,
}

Trước khi chúng tôi chuyển sang hợp đồng, hãy xem chúng tôi có giao diện nào trong tệp của chúng tôi Statetrong src/state.rstệp:

use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use cosmwasm_std::Addr;
use cw_storage_plus::Item;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct State {
    pub count: i32,
    pub owner: Addr,
}
pub const STATE: Item<State> = Item::new("state");

Cấu trúc của chúng tôi State,, phải chứa một countcủa i32ownercủa Addr. Theo Terra, trạng thái của chúng ta tồn tại lâu dài vì LevelDB đang hoạt động của Terra , là nơi lưu trữ giá trị-khóa .

Với ý nghĩ đó, hợp đồng của chúng tôi nằm trong src/contract.rshồ sơ:

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn instantiate(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: InstantiateMsg,
) -> Result<Response, ContractError> {
    let state = State {
        count: msg.count,
        owner: info.sender.clone(),
    };
    set_contract_version(deps.storage, CONTRACT_NAME, CONTRACT_VERSION)?;
    STATE.save(deps.storage, &state)?;
    Ok(Response::new()
        .add_attribute("method", "instantiate")
        .add_attribute("owner", info.sender)
        .add_attribute("count", msg.count.to_string()))
}

Các instantiatephương pháp dự đoán bốn đối số, deps, _ env, info, và msg, với giao diện hỗ trợ của họ. Sau đó, chúng tôi mong đợi một kết quả sẽ là mong đợi của chúng tôi Responsehoặc ContractError.

Ở đây, chúng tôi đã xác định của chúng tôi ContractErrortrong src/error.rstệp:

use cosmwasm_std::StdError;
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ContractError {
    #[error("{0}")]
    Std(#[from] StdError),
    #[error("Unauthorized")]
    Unauthorized {},
    // Add any other custom errors you like here.
    // Look at https://docs.rs/thiserror/1.0.21/thiserror/ for details.
}

Một số giao diện khác Responsecũng được nhập từ cosmwasm_std:

#[cfg(not(feature = "library"))]
use cosmwasm_std::entry_point;
use cosmwasm_std::{to_binary, Binary, Deps, DepsMut, Env, MessageInfo, Response, StdResult};
use cw2::set_contract_version;

Tiếp theo, đối với các phương thức, chúng tôi cũng có executequerytrong hợp đồng của chúng tôi:

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn execute(
    deps: DepsMut,
    _env: Env,
    info: MessageInfo,
    msg: ExecuteMsg,
) -> Result<Response, ContractError> {
    match msg {
        ExecuteMsg::Increment {} => try_increment(deps),
        ExecuteMsg::Reset { count } => try_reset(deps, info, count),
    }
}

pub fn try_increment(deps: DepsMut) -> Result<Response, ContractError> {
    STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
        state.count += 1;
        Ok(state)
    })?;
    Ok(Response::new().add_attribute("method", "try_increment"))
}
pub fn try_reset(deps: DepsMut, info: MessageInfo, count: i32) -> Result<Response, ContractError> {
    STATE.update(deps.storage, |mut state| -> Result<_, ContractError> {
        if info.sender != state.owner {
            return Err(ContractError::Unauthorized {});
        }
        state.count = count;
        Ok(state)
    })?;
    Ok(Response::new().add_attribute("method", "reset"))
}

Ở đây, try_incrementcái tăng trạng thái đếm lên 1try_resetđặt lại trạng thái đếm là các hàm được sử dụng trong executehàm.

Cuối cùng, querysố đếm, lấy trạng thái hoặc thông tin từ bộ nhớ cho chúng tôi, có thể được thực hiện bên dưới:

#[cfg_attr(not(feature = "library"), entry_point)]
pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> StdResult<Binary> {
    match msg {
        QueryMsg::GetCount {} => to_binary(&query_count(deps)?),
    }
}
fn query_count(deps: Deps) -> StdResult<CountResponse> {
    let state = STATE.load(deps.storage)?;
    Ok(CountResponse { count: state.count })
}

Tải hợp đồng thông minh lên LocalTerra

Bây giờ chúng tôi có thể xây dựng hợp đồng thông minh của mình để kiểm tra lỗi trong quá trình biên dịch để chúng tôi có thể sửa chữa nó. Để làm điều đó, chúng tôi chạy như sau:

$ cargo wasm

Và cũng giống như chúng tôi đã cài đặt cargo-run-scriptđể giúp tối ưu hóa các bản dựng của mình, bây giờ chúng tôi phải sử dụng nó:

$ cargo run-script optimize

Trong thư mục dự án, chúng tôi sẽ thấy mã trong artifacts/terra_demo.wasmđó, chúng tôi sẽ tải lên LocalTerra trong thời gian ngắn. Bây giờ chúng ta có thể tạo tên testnet cục bộ và biệt danh nút:

$ terrad init --chain-id=<testnet_name> <node_moniker>

Sau đó, điều này sẽ nhắc bạn nhập ghi nhớ của mình:

 $ terrad keys add <account_name>

Theo Terra, tài khoản có ghi nhớ dưới đây là trình xác thực duy nhất trên mạng:

satisfy adjust timber high purchase tuition stool faith fine install that you unaware feed domain license impose boss human eager hat rent enjoy dawn

Tiếp theo, chúng tôi có thể tải mã lên mạng Terra:

terrad tx wasm store artifacts/terra_demo.wasm --from demo --chain-id=localterra --gas=auto --fees=100000uluna --broadcast-mode=block

Thao tác này sẽ yêu cầu quyền mà bạn phải nhập “yes” để cho phép nó đẩy lên LocalTerra. Nếu thành công, hợp đồng của bạn hiện được phát tới mạng LocalTerra.

Sự kết luận

Chúng tôi chỉ mới bắt đầu sơ lược bề mặt của các hợp đồng thông minh trong Terra và điều này sẽ chỉ cung cấp một cái nhìn tổng quan về cách xây dựng một dApp trên giao thức Terra.

Việc xây dựng dựa trên giao thức này rất được khuyến khích vì cơ sở người dùng đang phát triển tích cực của nó và các stablecoin Terra, bao gồm LUNA, đang được thêm vào các giải pháp thanh toán, đây là một tin tốt.

Nó cũng có sự đồng thuận nhanh chóng và hiệu quả với hiệu quả cao hơn trong các bản phát hành trong tương lai.

Nguồn: https://blog.logrocket.com

#blockchain

CODE VN

CODE VN

1643415780

Cách triển khai Oracle với Hợp đồng thông minh Ethereum

Tạo Oracle của riêng bạn với hợp đồng thông minh Ethereum

Tìm hiểu cách xây dựng Oracle, giúp kết nối các chuỗi khối với các hệ thống bên ngoài và cho phép truy cập vào dữ liệu từ các hệ thống ngoài chuỗi.

Trong bài viết này, chúng ta sẽ xem xét việc phát triển Oracle với hợp đồng thông minh Ethereum. Dưới đây là tổng quan ngắn gọn về các công nghệ mà chúng tôi sẽ làm việc cùng với các liên kết để tìm hiểu thêm.

Trước khi tìm hiểu quá sâu, chúng ta hãy trả lời một số câu hỏi cơ bản về các công nghệ mà chúng ta sẽ xem xét.

Blockchain là gì?

Blockchain có thể được mô tả như một cơ sở hạ tầng máy tính được thiết kế để tạo điều kiện cho sự hợp tác đáng tin cậy cao. Đó là một cơ sở dữ liệu công cộng được cập nhật và chia sẻ trên nhiều máy tính trong mạng. Sự hợp tác đáng tin cậy này cung cấp cho những người tham gia niềm tin vững chắc vào độ tin cậy của sự hợp tác.

Ethereum là gì?

Vitaly Buterin, người sáng lập Ethereum, nhận ra rằng mạng blockchain phổ biến nhất, Bitcoin, có những hạn chế do tập lệnh dựa trên ngăn xếp, thiếu chức năng và khả năng phát triển ứng dụng thấp ngoài việc chuyển quyền sở hữu tiền điện tử.

Điểm khác biệt giữa Ethereum với Bitcoin là nó sở hữu một ngôn ngữ lập trình có sẵn, hoàn chỉnh Turing, thiết lập một hợp đồng thông minh và cung cấp một nền tảng ứng dụng phi tập trung cho phép bất kỳ ai cũng có thể xác định, tạo và giao dịch tiền điện tử và tài sản tiền điện tử.

Hợp đồng thông minh là gì?

Hợp đồng thông minh là một cách để thiết lập niềm tin trong một quy trình hợp tác trên blockchain. Điều này thay thế sự tin cậy dựa trên thương hiệu bằng sự tin cậy dựa trên mật mã bằng cách chuyển các cơ chế thực thi và lưu ký của hợp đồng sang logic phần mềm, được chạy trên một mạng phi tập trung. Với hợp đồng thông minh, các nhà phát triển có thể xây dựng và triển khai các ứng dụng hướng đến người dùng (trò chơi, chợ, v.v.) và chúng thường được gọi là ứng dụng phi tập trung (DApps) .

Oracles là gì?

Oracles được sinh ra với mong muốn mở rộng các loại hình cộng tác có thể có trên các blockchain. Chúng kết nối các chuỗi khối với các hệ thống bên ngoài và cho phép truy cập vào dữ liệu từ các hệ thống ngoài chuỗi, hoạt động như một nguồn chân lý cho chuỗi khối. Do đó, họ cung cấp các blockchain với các cổng an toàn cho các hệ thống ngoài chuỗi, cho phép các ứng dụng hợp đồng thông minh xác minh các sự kiện bên ngoài và kích hoạt các hành động trên các dịch vụ bên ngoài.

Do đó, Oracles đóng vai trò là cầu nối giữa hai môi trường: on-chain đề cập đến mạng blockchain và off-chain đề cập đến các hệ thống bên ngoài.

Có nhiều loại Oracles khác nhau liên quan đến một số kết hợp của tìm nạp, xác thực và cung cấp dữ liệu:

  1. Phép màu đầu vào: Những dữ liệu này tìm nạp dữ liệu từ các nguồn ngoài chuỗi và phân phối nó đến mạng blockchain để sử dụng hợp đồng thông minh
  2. Oracles đầu ra: Kích hoạt hợp đồng thông minh để kích hoạt các hành động trên các hệ thống ngoài chuỗi
  3. Cross-Chain Oracles: Cho phép khả năng tương tác giữa các blockchains, cho phép đọc và ghi thông tin giữa các blockchains khác nhau
  4. Phép toán được kích hoạt bằng máy tính: Những điều này đang trở nên phổ biến vì chúng cung cấp một giải pháp tính toán rất hữu ích, an toàn, ngoài chuỗi, để thực hiện các phép tính trên một tập hợp các đầu vào; nó là một giải pháp thay thế cho chi phí tính toán tương đối đắt trên mạng Ethereum

Đang cài đặt

Có nhiều nhóm blockchain đang tích cực làm việc trên các giải pháp Oracle khả thi:

Chainlink được coi là tiền thân, vì vậy chúng ta sẽ khám phá nó trong bài viết này. Chainlink cung cấp khả năng kết nối hợp đồng thông minh của chúng tôi với hầu hết các API, bao gồm từ các API ngoài chuỗi.

Chainlink cũng vận hành Thị trường Chainlink , là danh sách được xác thực của các nhà khai thác nút tận dụng mạng Chainlink để làm cho dữ liệu của họ có thể truy cập trực tiếp trên chuỗi thông qua các nút Chainlink của riêng họ.

Quá trình phát triển của chúng tôi sẽ được thực hiện với Remix , một IDE web để tạo, chạy và gỡ lỗi các hợp đồng thông minh trong trình duyệt. Với Remix, chúng tôi không cần máy phát triển, vì mọi thứ đã được đưa vào giao diện web.

Metamask cho phép bất kỳ ai tương tác với các blockchain tương thích với Ethereum, cho phép tạo địa chỉ. Nó cũng tích hợp dễ dàng với Remix.

Tổng quan dự án

Trong bài viết này, chúng ta sẽ khám phá quy trình truy xuất giá hiện tại của Bitcoin từ một hệ thống ngoài chuỗi, sử dụng máy khách Chainlink, để tạo hợp đồng Thông minh Oracle. Chúng tôi cũng sẽ truy xuất giá Ethereum mới nhất bằng cách sử dụng nguồn dữ liệu trên chuỗi đã được xác thực từ Chainlink.

Để khám phá hai phương pháp truy xuất dữ liệu khác nhau này trong các hợp đồng thông minh của chúng tôi, chúng tôi sẽ tạo hai hợp đồng thông minh riêng biệt và triển khai chúng vào blockchain.

  1. Hợp đồng thông minh đầu tiên của chúng tôi sẽ tận dụng ChainlinkClient, mà chúng tôi có thể kết nối với bất kỳ URL nào để truy xuất dữ liệu và cho phép tạo các phép toán trên chuỗi
  2. Hợp đồng thông minh thứ hai của chúng tôi sử dụng Nguồn cấp dữ liệu Chainlink, cung cấp danh sách các nhà cung cấp dữ liệu độc lập đáng tin cậy để sử dụng trong mạng oracle phi tập trung

Thiết lập ví MetaMask của chúng tôi

Để bắt đầu quá trình phát triển của chúng tôi, thiết lập ví MetaMask là chìa khóa. Cài đặt tiện ích mở rộng MetaMask . Sau khi cài đặt thành công, hãy mở danh sách tiện ích mở rộng trình duyệt của bạn và nhấp vào biểu tượng MetaMask.
Biểu tượng tiện ích mở rộng trình duyệt MetaMask

Làm theo hướng dẫn trong MetaMask để tạo ví mới. Đảm bảo lưu trữ an toàn cụm từ ghi nhớ 12 từ của bạn ở một vị trí an toàn mà chỉ bạn mới có thể truy cập.

Đặt MetaMask để sử dụng mạng thử nghiệm Kovan .
Chọn mạng kiểm tra Kovan trong menu thả xuống

Bước tiếp theo là cấp vốn cho ví MetaMask. Kovan Testnet cung cấp Kovan Ether (KEth), không có giá trị thị trường và cho phép chúng tôi truy cập vào Kovan testnet.

Chainlink cung cấp Vòi để lấy LINK tiền điện tử của Chainlink cho mục đích thử nghiệm. Chúng tôi sẽ sử dụng LINK này để đảm bảo thực hiện thành công hợp đồng thông minh của mình, vì nó phụ thuộc vào mạng Chainlink.

Làm theo các bước được ghi lại trong gif dưới đây để gửi 0,1 ETH thử nghiệm và 10 LINK thử nghiệm đến ví MetaMask của bạn trên Kovan testnet.
Làm theo các bước để tự gửi ETH thử nghiệm và kiểm tra LINK

Tạo RequestPriceOracle của chúng tôi

Chainlink cho phép các hợp đồng thông minh truy cập vào bất kỳ nguồn dữ liệu bên ngoài nào. Dựa vào thư viện hợp đồng Chainlink cho phép chúng tôi truy cập vào một bộ công cụ cho phép tạo các hợp đồng thông minh có thể sử dụng dữ liệu và phục vụ như Oracles.

Trong Remix, hãy tạo một tệp mới có tên RequestPrice.sol, tệp này sẽ chứa mã hợp đồng thông minh của chúng tôi.

Chu trình dữ liệu yêu cầu và nhận của Chainlink cho phép sử dụng phản hồi API, mà hợp đồng của chúng tôi cần kế thừa từ đó ChainlinkClient.

Để tạo một yêu cầu API trong hợp đồng thông minh của chúng tôi, chúng tôi dựa vào cấu trúc Chainlink.Request. Yêu cầu phải bao gồm Oracle, ID công việc, phí và chữ ký hàm gọi lại.

Từ oracle khóa đề cập đến nút liên kết chuỗi cụ thể mà hợp đồng thực hiện lệnh gọi API từ đó jobId đề cập đến một công việc cụ thể để nút đó chạy. RequestPriceđủ linh hoạt để gọi bất kỳ URL công khai nào.

Chọn một nút Oracle là quan trọng. Hợp đồng thông minh của chúng tôi cần thực hiện một yêu cầu HTTP GET, do đó lựa chọn phù hợp của nút sẽ là nút hỗ trợ GETbộ điều hợp HTTP. Bạn có thể xem danh sách các nút Oracle khác nhau có sẵn trên trang Chainlink.

Trong RequestPrice.soltệp của chúng tôi, hợp đồng thông minh của chúng tôi được xác định và chúng tôi đã đặt nguồn dữ liệu của mình thành API CryptoCompare công khai . Chức năng requestPriceDatađược xác định trong hợp đồng của chúng tôi cho phép truy xuất giá hiện tại của BTC bằng USD.

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

import "@chainlink/contracts/src/v0.8/ChainlinkClient.sol";

contract RequestPrice is ChainlinkClient {
    using Chainlink for Chainlink.Request;

    uint256 public price;

    address private oracle;
    bytes32 private jobId;
    uint256 private fee;

    constructor() {
        setPublicChainlinkToken();
        oracle = 0xc57B33452b4F7BB189bB5AfaE9cc4aBa1f7a4FD8;
        jobId = "d5270d1c311941d0b08bead21fea7747";
        fee = 0.1 * 10 ** 18; 
    }

    /**
     * Create a Chainlink request to retrieve API response, find the target
     * data.
     */
    function requestPriceData() public returns (bytes32 requestId)
    {
        Chainlink.Request memory request = buildChainlinkRequest(jobId, address(this), this.fulfill.selector);


        // Set the URL to perform the GET request on
        request.add("get", "https://min-api.cryptocompare.com/data/generateAvg?fsym=BTC&tsym=USD&e=Kraken");

        // Specify the path for retrieving the data
        request.add("path", "RAW.PRICE");
        // Sends the request
        return sendChainlinkRequestTo(oracle, request, fee);
    }

      /**
     * Callback Function
     */
    function fulfill(bytes32 _requestId, uint256 _price) public recordChainlinkFulfillment(_requestId)
    {
        price = _price;
    }
}

Loại phản hồi được chỉ định trong RequestPricehợp đồng là một số nguyên không dấu ( uint256), nhưng nhiều kiểu dữ liệu có thể được chỉ định, chẳng hạn như:

  • bytes32: Giá trị chuỗi và byte
  • bool: Giá trị đúng hoặc sai
  • int256: Số nguyên có dấu
  • uint256: Số nguyên không dấu

Biên soạn hợp đồng thông minh

Trong Remix IDE, nhấp vào Trình biên dịch Solidity để xem cài đặt trình biên dịch.
Xem cài đặt trình biên dịch

Chúng tôi sẽ sử dụng cài đặt trình biên dịch mặc định, nhưng hãy đảm bảo rằng phiên bản Solidity của bạn giống với những gì được sử dụng trong trình biên dịch. Nhấp vào Biên dịch RequestPrice.sol để biên dịch hợp đồng thông minh mà chúng tôi vừa tạo.
Nhấp vào nút Biên dịch requestPrice.sol

Sau khi biên dịch hợp đồng, hãy điều hướng đến tab Triển khai và Chạy . Chọn môi trường Injected Web3 trong menu thả xuống để triển khai hợp đồng vào chuỗi khối.
Chọn môi trường Injected Web3 để triển khai hợp đồng thông minh của chúng tôi vào chuỗi khối

Trước khi triển khai, hãy xem kỹ tên Hợp đồng vì các hợp đồng khác có tên tương tự có thể có sẵn.

Kiểm tra tên hợp đồng để tìm các bản sao trước khi triển khai

Đây là một tên hợp đồng có thể thông qua, vì vậy chúng tôi sẵn sàng

Nhấp vào nút Triển khai . MetaMask sẽ mở và nhắc bạn thanh toán để triển khai hợp đồng.

Quay lại ví MetaMask của chúng tôi và xác nhận rằng nó được đặt thành mạng Kovan trước khi chấp nhận giao dịch.
Xác nhận rằng bạn vẫn kết nối với Kovan testnet trước khi chấp nhận giao dịch

Sau khi giao dịch hoàn tất, hợp đồng của bạn sẽ xuất hiện trong danh sách Hợp đồng đã triển khai trong Remix. Nhấp vào menu thả xuống Hợp đồng để xem các biến và chức năng của nó.
Xem các biến và chức năng của hợp đồng triển khai

Chạy các chức năng trong RequestPricehợp đồng thông minh

Để chạy các chức năng trong hợp đồng của chúng tôi, chúng tôi cần cấp vốn cho hợp đồng. Chúng tôi sẽ tài trợ cho hợp đồng Solidity của mình bằng mã thông báo gốc của mạng Chainlink, LINK, mà chúng tôi có được bằng cách sử dụng Vòi của họ.

Trong phần Hợp đồng đã triển khai , sử dụng nút Sao chép gần tiêu đề hợp đồng để sao chép địa chỉ hợp đồng. Sau đó, hãy làm theo các bước sau:

  1. Mở MetaMask
  2. Chọn testnet Kovan
  3. Nhấp vào nút Gửi trong MetaMask để bắt đầu giao dịch
  4. Dán địa chỉ hợp đồng đã sao chép
  5. Từ menu tài sản, chọn LIÊN KẾT hoặc ETH để gửi đến hợp đồng. Chainlink cung cấp hướng dẫn kèm theo hướng dẫn nhận testnet LINKChọn đơn vị tiền tệ bạn muốn gửi vào hợp đồng
  6. Nhấp vào Tiếp theo để xem lại giao dịch
  7. Nếu hài lòng, hãy nhấp vào Xác nhận

Quay lại IDE Remix của chúng tôi, trong tab Triển khai và Chạy giao dịch , điều hướng đến phần Triển khai hợp đồng và nhấp vào nút requestPriceData .
Nhấp vào nút requestPriceData trong phần Triển khai hợp đồng

Bạn sẽ nhận được lời nhắc từ MetaMask yêu cầu xác nhận giao dịch. Nhấp vào nút Xác nhận .
Xác nhận giao dịch trong MetaMask

Cuối cùng, nhấp vào nút biến giá để xem giá hiện tại của Bitcoin tính theo USD.
Nhấp vào nút biến giá

Nếu bạn đã làm được điều này, bạn đã tạo và triển khai thành công Hợp đồng thông minh Oracle trên chuỗi khối Ethereum.

Sử dụng Nguồn cấp dữ liệu Chainlink để truy xuất dữ liệu

Trong lần triển khai tiếp theo của hợp đồng thông minh, chúng ta sẽ xem xét triển khai chuyên sâu hơn một chút bằng cách sử dụng Nguồn cấp dữ liệu Chainlink .

Trước đó, tôi đã đề cập rằng có các phương pháp khác nhau để truy xuất dữ liệu trong các hợp đồng thông minh của chúng tôi với Chainlink bên cạnh việc thông qua các yêu cầu HTTP. Một khía cạnh chính cần xem xét khi xây dựng hợp đồng thông minh là chất lượng của nguồn dữ liệu cung cấp dữ liệu vào Oracle của chúng tôi.

Để trợ giúp việc này, Chainlink sắp xếp một danh sách các nguồn cấp dữ liệu phi tập trung để cung cấp các nguồn dữ liệu an toàn để cung cấp năng lượng cho các ứng dụng phi tập trung của chúng tôi. Tất cả những gì chúng ta cần làm là kéo dữ liệu vào hợp đồng thông minh của mình từ một hợp đồng thông minh trên chuỗi khác.

Bạn có thể truy cập nguồn cấp dữ liệu Ethereum do Chainlink quản lý trên trang web Chainlink.

Hãy kiểm tra nó ra. Tạo một tệp khác trong Remix được gọi là EthPrice.sol.

// SPDX-License-Identifier: GPL-3.0

pragma solidity >=0.7.0 <0.9.0;

import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";

contract EthPrice {

     AggregatorV3Interface internal ethFeed;

     // Precomputing hash of strings
       bytes32 ethHash = keccak256(abi.encodePacked("ETH"));

    /**
     * Network: Kovan
        0x9326BFA02ADD2366b30bacB125260Af641031331
     * Address: 0x169e633a2d1e6c10dd91238ba11c4a708dfef37c
     */
    constructor() {
        ethFeed = AggregatorV3Interface(0x9326BFA02ADD2366b30bacB125260Af641031331);
    }

    /**
     * Returns the latest price
     */
    function getEthPrice() public view returns (int) {
        (
            uint80 roundID,
            int price,
            uint startedAt,
            uint timeStamp,
            uint80 answeredInRound
        ) = ethFeed.latestRoundData();
        return price;
    }

}

Triển khai hợp đồng từ tab Triển khai trong Remix và chạy chức năng.
Triển khai hợp đồng bằng cách sử dụng Nguồn cấp dữ liệu

Sự kết luận

Hướng dẫn này khá thú vị, vì chúng tôi đã thấy cách chúng tôi có thể mở rộng khả năng của blockchain và hợp đồng thông minh vào các ứng dụng trong thế giới thực bằng cách cung cấp dữ liệu chính xác cho các ứng dụng phi tập trung của chúng tôi.

Tạo ra các Oracles an toàn và đáng tin cậy là một khía cạnh quan trọng của cuộc cách mạng blockchain, vì nó cho phép chuyển các hệ thống thế giới ngoài chuỗi sang các hệ thống trên chuỗi. Trong lần triển khai hợp đồng thông minh thứ hai, chúng tôi đã xem xét cách Chainlink giúp đảm bảo độ tin cậy của dữ liệu được sử dụng trong DApps bằng cách cung cấp danh sách các nhà cung cấp dữ liệu nguồn đơn và nhà cung cấp dữ liệu phi tập trung đã được hiệu đính.

Nguồn bài viết gốc tại https://blog.logrocket.com

Duong Tran

Duong Tran

1658887312

Xây dựng, Triển khai và Kiểm tra Microservices với .NET, C# và Docker

Tìm hiểu khái niệm về Kiến trúc Microservices. Tìm hiểu cách xây dựng, triển khai và kiểm tra Kiến trúc Microservices trong .NET và C # bằng cách sử dụng vùng chứa Docker.

Microservices

Thuật ngữ microservices mô tả một phong cách phát triển phần mềm đã phát triển từ các xu hướng hiện đại để thiết lập các phương pháp thực hành nhằm tăng tốc độ và hiệu quả của việc phát triển và quản lý các giải pháp phần mềm trên quy mô lớn. Microservices thiên về việc áp dụng một số nguyên tắc và mô hình kiến ​​trúc nhất định làm kiến ​​trúc. Mỗi microservice sống độc lập, nhưng mặt khác, tất cả cũng dựa vào nhau. Tất cả các microservices trong một dự án đều được triển khai trong quá trình sản xuất theo tốc độ riêng của chúng, tại chỗ trên đám mây, độc lập, sống song song với nhau.

Trong bài viết này, chúng ta sẽ tìm hiểu khái niệm về Microservices, kiến ​​trúc của chúng và cách tạo microservices trong .NET và C #. Bạn cũng sẽ tìm hiểu các bước để xây dựng, triển khai và kiểm tra các microservices trong .NET bằng cách sử dụng bộ chứa docker.

Kiến trúc Microservices

Hình ảnh sau đây từ Microsoft Docs cho thấy kiểu kiến ​​trúc microservices.

 

Có nhiều thành phần khác nhau trong kiến ​​trúc microservices ngoài bản thân microservices.

Quản lý . Duy trì các nút cho dịch vụ.

Nhà cung cấp danh tính . Quản lý thông tin nhận dạng và cung cấp dịch vụ xác thực trong mạng phân tán.

Khám phá dịch vụ . Theo dõi các dịch vụ và địa chỉ dịch vụ và điểm cuối.

Cổng API . Đóng vai trò là điểm vào của khách hàng. Một đầu mối liên hệ từ khách hàng sẽ trả lại phản hồi từ các dịch vụ nhỏ cơ bản và đôi khi là phản hồi tổng hợp từ nhiều dịch vụ vi mô cơ bản.

CDN . Mạng phân phối nội dung để cung cấp tài nguyên tĩnh cho các trang và nội dung web trong mạng phân tán

Nội dung tĩnh Các tài nguyên tĩnh như các trang và nội dung web

Các dịch vụ vi mô được triển khai độc lập với cơ sở dữ liệu của riêng chúng cho mỗi dịch vụ, do đó các dịch vụ vi mô cơ bản trông như thể hiện trong hình sau.

 

Kiến trúc nguyên khối so với Microservices

Các ứng dụng nguyên khối không chỉ là một gói hoàn chỉnh có tất cả các thành phần và dịch vụ cần thiết liên quan được gói gọn trong một gói.

Sau đây là biểu diễn sơ đồ của kiến ​​trúc nguyên khối được đóng gói hoàn toàn hoặc dựa trên dịch vụ.

 

Microservice là một cách tiếp cận để tạo ra các dịch vụ nhỏ, mỗi dịch vụ chạy trong không gian riêng của chúng và có thể giao tiếp qua tin nhắn. Đây là các dịch vụ độc lập gọi trực tiếp cơ sở dữ liệu của riêng chúng.

Sau đây là biểu diễn sơ đồ của kiến ​​trúc microservices.

 

Trong kiến ​​trúc nguyên khối, cơ sở dữ liệu vẫn giữ nguyên cho tất cả các chức năng ngay cả khi tuân theo cách tiếp cận của kiến ​​trúc hướng dịch vụ, trong khi trong microservices, mỗi dịch vụ sẽ có cơ sở dữ liệu riêng.

Docker Containers và cài đặt Docker

Các vùng chứa như Dockers và những vùng khác chia nhỏ tài nguyên của hệ điều hành, chẳng hạn như ngăn xếp mạng, không gian tên quy trình, phân cấp hệ thống tệp và ngăn xếp lưu trữ. Dockers giống như ảo hóa hệ điều hành hơn. Tìm hiểu thêm về dockers tại đây . Mở URL này và nhấp vào Tải xuống từ trung tâm Docker. Sau khi tải xuống, hãy đăng nhập vào Docker và làm theo hướng dẫn để cài đặt Docker cho Windows.

Microservice sử dụng ASP.NET Core

Phần này sẽ trình bày cách tạo một dịch vụ sản phẩm nhỏ bằng cách sử dụng ASP.NET Core từng bước với sự trợ giúp của hình ảnh. Dịch vụ sẽ được xây dựng bằng ASP.NET Core 2.1 và Visual Studio 2017. Asp.NET Core được tích hợp với VS 2017. Dịch vụ này sẽ có DBcontext và cơ sở dữ liệu riêng với kho lưu trữ riêng biệt để dịch vụ có thể được triển khai độc lập.

 

Tạo giải pháp ứng dụng cốt lõi ASP.NET

  1. Mở Visual Studio và thêm một dự án mới.

  2. Chọn ứng dụng là ASP.NET Core Web Application và đặt cho nó một cái tên có ý nghĩa.

  3. Tiếp theo, chọn API làm loại dự án và đảm bảo rằng tùy chọn “Bật hỗ trợ Docker” được chọn với loại hệ điều hành là Linux.

  4. Giải pháp sẽ như hình dưới đây.

Thêm mô hình

  1. Thêm một thư mục mới có tên "Model" vào dự án.

  2. Trong thư mục Mô hình, thêm một lớp có tên Sản phẩm.

  3. Thêm một số thuộc tính như Id, Tên, Mô tả, Giá vào loại sản phẩm. Sản phẩm cũng phải thuộc loại nào đó và đối với điều đó, mô hình danh mục được xác định và thuộc tính CategoryId được thêm vào mô hình sản phẩm.

  4. Tương tự, thêm mô hình Danh mục.

Bật EF Core

Mặc dù dự án .NET Core API có hỗ trợ sẵn cho EF Core và tất cả các phần phụ thuộc liên quan được tải xuống tại thời điểm tạo và biên dịch dự án có thể được tìm thấy trong phần SDK trong dự án như được hiển thị bên dưới.

 

Microsoft.EntityFrameworkCore.SqlServer (2.1.1) phải là gói bên trong SDK đã tải xuống. Nếu nó không có mặt, nó có thể được thêm vào dự án một cách rõ ràng thông qua Nuget Packages.

Thêm EF Core DbContext

Một bối cảnh cơ sở dữ liệu là cần thiết để các mô hình có thể tương tác với cơ sở dữ liệu.

  1. Thêm một thư mục mới có tên DBContexts vào dự án.

  2. Thêm một lớp mới có tên ProductContext bao gồm các thuộc tính DbSet cho Sản phẩm và Danh mục. OnModelCreating là một phương pháp mà thông qua đó dữ liệu chính có thể được đưa vào cơ sở dữ liệu. Vì vậy, hãy thêm phương thức OnModelCreating và thêm một số danh mục mẫu sẽ được thêm vào cơ sở dữ liệu ban đầu vào bảng danh mục khi cơ sở dữ liệu được tạo.



    Mã ProductContext
using Microsoft.EntityFrameworkCore;
using ProductMicroservice.Models;

namespace ProductMicroservice.DBContexts
{
  public class ProductContext : DbContext
  {
    public ProductContext(DbContextOptions<ProductContext> options) : base(options)
    {
    }
    public DbSet<Product> Products { get; set; }
    public DbSet<Category> Categories { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
      modelBuilder.Entity<Category>().HasData(
          new Category
          {
            Id = 1,
            Name = "Electronics",
            Description = "Electronic Items",
          },
          new Category
          {
            Id = 2,
            Name = "Clothes",
            Description = "Dresses",
          },
          new Category
          {
            Id = 3,
            Name = "Grocery",
            Description = "Grocery Items",
          }
      );
    }

  }
}
  • Thêm một chuỗi kết nối trong tệp appsettings.json.

Mở tệp Startup.cs để thêm nhà cung cấp db máy chủ SQL cho EF Core. Thêm mã services.AddDbContext <ProductContext> (o => o.UseSqlServer (Configuration.GetConnectionString ("ProductDB"))); trong phương thức ConfigureServices. Lưu ý rằng trong phương thức GetConnectionString, tên của khóa của chuỗi kết nối được chuyển được thêm vào tệp appsettings.

 

Thêm kho lưu trữ

Kho lưu trữ hoạt động như một thành phần vi mô của microservice bao bọc lớp truy cập dữ liệu và cũng giúp duy trì độ bền và khả năng kiểm tra của dữ liệu.

  1. Thêm một thư mục mới có tên Kho lưu trữ trong dự án và thêm tên Giao diện IProductRepository trong thư mục đó. Thêm các phương thức trong giao diện thực hiện các hoạt động CRUD cho Dịch vụ vi mô của sản phẩm.

  2. Thêm một lớp cụ thể mới có tên là ProductRepository trong cùng một thư mục Repository triển khai IProductRepository. Tất cả những phương pháp này cần:

  3. Thêm triển khai cho các phương thức thông qua truy cập các phương thức ngữ cảnh.

    ProductRepository.cs
using Microsoft.EntityFrameworkCore;
using ProductMicroservice.DBContexts;
using ProductMicroservice.Models;
using System;
using System.Collections.Generic;
using System.Linq;

namespace ProductMicroservice.Repository
{
  public class ProductRepository: IProductRepository
  {
    private readonly ProductContext _dbContext;

    public ProductRepository(ProductContext dbContext)
    {
      _dbContext = dbContext;
    }
    public void DeleteProduct(int productId)
    {
      var product = _dbContext.Products.Find(productId);
      _dbContext.Products.Remove(product);
      Save();
    }

    public Product GetProductByID(int productId)
    {
      return _dbContext.Products.Find(productId);
    }

    public IEnumerable<Product> GetProducts()
    {
      return _dbContext.Products.ToList();
    }

    public void InsertProduct(Product product)
    {
      _dbContext.Add(product);
      Save();    }

    public void Save()
    {
      _dbContext.SaveChanges();
    }

    public void UpdateProduct(Product product)
    {
      _dbContext.Entry(product).State = EntityState.Modified;
      Save();
    }
  }
}
  • Mở lớp Khởi động trong dự án và thêm mã dưới dạng services.AddTransient <IProductRepository, ProductRepository> (); bên trong phương thức ConfigureServices để sự phụ thuộc của kho lưu trữ được giải quyết tại thời điểm chạy khi cần thiết.

Thêm bộ điều khiển

Microservice phải có một điểm cuối cần có bộ điều khiển để hiển thị các phương thức HTTP cho máy khách như là điểm cuối của các phương thức dịch vụ.

  1. Nhấp chuột phải vào thư mục Bộ điều khiển và thêm Bộ điều khiển mới như hình dưới đây.

  2. Chọn tùy chọn “Bộ điều khiển API với các hành động đọc / ghi” để thêm bộ điều khiển.

  3. Đặt tên của bộ điều khiển là ProductController.

  4. Một lớp ProductController sẽ được thêm vào thư mục Bộ điều khiển với các hành động đọc / ghi mặc định sẽ được thay thế sau này bằng các hành động đọc / ghi sản phẩm và các phương thức HTTP được tạo hoạt động như một điểm cuối của dịch vụ.

  5. ValuesController có thể bị xóa khi không cần thiết.

  6. Thêm triển khai vào các phương thức bằng cách gọi các phương thức kho lưu trữ như được hiển thị bên dưới. Việc triển khai cơ bản được hiển thị ở đây để hiểu khái niệm. Các phương thức có thể được định tuyến thuộc tính và có thể được trang trí với nhiều chú thích hơn theo nhu cầu.

    ProductController.cs
using Microsoft.AspNetCore.Mvc;
using ProductMicroservice.Models;
using ProductMicroservice.Repository;
using System;
using System.Collections.Generic;
using System.Transactions;

namespace ProductMicroservice.Controllers
{
  [Route("api/[controller]")]
  [ApiController]
  public class ProductController : ControllerBase
  {

    private readonly IProductRepository _productRepository;

    public ProductController(IProductRepository productRepository)
    {
      _productRepository = productRepository;
    }

    [HttpGet]
    public IActionResult Get()
    {
      var products = _productRepository.GetProducts();
      return new OkObjectResult(products);
    }

    [HttpGet("{id}", Name = "Get")]
    public IActionResult Get(int id)
    {
      var product = _productRepository.GetProductByID(id);
      return new OkObjectResult(product);
    }

    [HttpPost]
    public IActionResult Post([FromBody] Product product)
    {
      using (var scope = new TransactionScope())
      {
        _productRepository.InsertProduct(product);
        scope.Complete();
        return CreatedAtAction(nameof(Get), new { id = product.Id }, product);
      }
    }

    [HttpPut]
    public IActionResult Put([FromBody] Product product)
    {
      if (product != null)
      {
        using (var scope = new TransactionScope())
        {
          _productRepository.UpdateProduct(product);
          scope.Complete();
          return new OkResult();
        }
      }
      return new NoContentResult();
    }

    [HttpDelete("{id}")]
    public IActionResult Delete(int id)
    {
      _productRepository.DeleteProduct(id);
      return new OkResult();
    }
  }
}

Sự di chuyển cốt lõi của Khung thực thể

Di chuyển cho phép chúng tôi cung cấp mã để thay đổi cơ sở dữ liệu từ phiên bản này sang phiên bản khác.

  1. Mở Bảng điều khiển Trình quản lý Gói.

  2. Để kích hoạt quá trình di chuyển, hãy nhập lệnh, Add-Migration và đặt một cái tên có ý nghĩa cho ví dụ: InitialCreate và nhấn enter.

  3. Khi lệnh được thực thi, nếu chúng ta nhìn vào giải pháp của mình bây giờ, chúng ta sẽ thấy có một thư mục Migrations mới. Và nó chứa hai tệp. Một, ảnh chụp nhanh mô hình ngữ cảnh hiện tại của chúng tôi. Hãy kiểm tra các tập tin. Các tập tin rất tự giải thích.

  4. Để đảm bảo rằng việc di chuyển được áp dụng cho cơ sở dữ liệu, có một lệnh khác cho việc đó. Nó được gọi là cập nhật-cơ sở dữ liệu Nếu được thực thi, quá trình di chuyển sẽ được áp dụng cho cơ sở dữ liệu hiện tại.

  5. Kiểm tra SQL Server Management Studio để xác minh xem cơ sở dữ liệu đã được tạo chưa.

  6. Khi dữ liệu của bảng Danh mục được xem, dữ liệu chính mặc định của ba danh mục được hiển thị.

Chạy sản phẩm Microservice

Dịch vụ có thể được chạy qua IIS Express, tức là Visual Studio mặc định hoặc qua vùng chứa Docker.

Qua IIS Express

Chọn IIS Express trong Visual Studio như được hiển thị bên dưới và nhấn F5 hoặc nhấp vào chính nút IIS Express đó.

 

Ứng dụng sẽ hoạt động sau khi trang trình duyệt được khởi chạy. Vì nó không có gì để hiển thị nên nó sẽ trống, nhưng dịch vụ có thể được kiểm tra thông qua bất kỳ ứng dụng thử nghiệm API nào. Ở đây Postman được sử dụng để kiểm tra các điểm cuối của dịch vụ. Giữ nó mở và ứng dụng chạy.

 

Cài đặt Postman nếu nó không có trên máy và khởi chạy nó.

 

BƯU KIỆN

Để kiểm tra phương thức POST; tức là tạo một tài nguyên mới, chọn phương thức là POST trong postman và cung cấp điểm cuối, tức là https: // localhost: 44312 / api / product và trong phần Body, thêm một JSON tương tự như có thuộc tính của Product model như hình dưới đây và nhấp vào Gửi.

 

Phản hồi cũng được trả về cùng với Id của sản phẩm.

 

Phương thức “Đăng” của bộ điều khiển chịu trách nhiệm tạo một tài nguyên trong cơ sở dữ liệu và gửi phản hồi.

Dòng trả về CreatedAtAction (nameof (Get), new {id = product.Id}, product); trả về vị trí của tài nguyên đã tạo có thể được kiểm tra trong thuộc tính Vị trí trong phản hồi dưới tab Tiêu đề.

 

Thực hiện truy vấn chọn trên bảng sản phẩm và một hàng đã thêm được hiển thị cho sản phẩm mới được tạo.

 

Tạo thêm một sản phẩm theo cách tương tự.

 

LẤY

Thực hiện yêu cầu GET ngay bây giờ với cùng một địa chỉ và hai bản ghi được hiển thị dưới dạng phản hồi kết quả JSON.

 

XÓA BỎ

Thực hiện yêu cầu xóa bằng cách chọn XÓA làm động từ và thêm id là 1 (nếu sản phẩm có id 1 cần được xóa) và nhấn Gửi.

 

Trong cơ sở dữ liệu, một bản ghi có Id 1 sẽ bị xóa.

 

ĐẶT

Động từ PUT chịu trách nhiệm cập nhật tài nguyên. Chọn động từ PUT, cung cấp địa chỉ API và trong phần Body, cung cấp thông tin chi tiết về sản phẩm nào cần được cập nhật ở định dạng JSON. Ví dụ: cập nhật sản phẩm với Id 2 và cập nhật tên, mô tả và giá của sản phẩm đó từ Samsung đến iPhone cụ thể. Nhấn Gửi.

 

Kiểm tra cơ sở dữ liệu để xem sản phẩm cập nhật.

 

Qua Docker Container

Việc chạy dịch vụ có thể được thực hiện thông qua các lệnh của docker để chạy trong dấu nhắc lệnh của docker và sử dụng visual studio. Vì chúng tôi đã thêm hỗ trợ docker, nên dễ dàng chạy dịch vụ trong docker container bằng cách sử dụng studio trực quan.

  1. Thêm hỗ trợ bộ điều phối vùng chứa trong giải pháp như được hiển thị bên dưới.

  2. Điều này sẽ yêu cầu người dàn nhạc. Chọn Docker Compose và nhấn OK.



    Sau khi được thêm vào giải pháp, giải pháp sẽ giống như được hiển thị bên dưới có docker-compile với dockerignore và docker-compos.yml và tệp ghi đè của nó.



    Ngay sau khi giải pháp được lưu, nó sẽ xây dựng dự án bên dưới vùng chứa và tạo hình ảnh docker. Tất cả các lệnh thực thi có thể được nhìn thấy trong cửa sổ đầu ra khi giải pháp được lưu.
  3. Mở dấu nhắc lệnh ở chế độ quản trị và điều hướng đến cùng một thư mục chứa các tệp dự án.

  4. Chạy các hình ảnh docker lệnh để xem tất cả các hình ảnh đã tạo. Chúng tôi thấy hình ảnh ProductMicroservice là hình ảnh mới nhất.

  5. Bây giờ hãy chạy ứng dụng với Docker dưới dạng tùy chọn như hình dưới đây.

  6. Bây giờ, chạy ps docker lệnh để xem các vùng chứa đang chạy. Nó cho thấy vùng chứa đang chạy trên cổng 32773: 80.

  7. Vì vùng chứa đang ở trạng thái chạy, nên tốt hơn là bạn nên kiểm tra dịch vụ hiện đang chạy bên dưới vùng chứa. Để kiểm tra dịch vụ, hãy thay thế "giá trị" bằng "sản phẩm" trong địa chỉ như hình dưới đây. Tốt nhất, nó sẽ nhận được các chi tiết sản phẩm. Nhưng nó cho ngoại lệ như hình dưới đây.

  8. Chạy cùng một thứ trong IIS Express hoạt động tốt, tức là trên cổng 44312. Thay thế "giá trị" bằng sản phẩm để nhận thông tin chi tiết về sản phẩm,

  9. Vì trong ứng dụng IIS Express chạy tốt chứ không phải trong bộ chứa docker, lỗi rõ ràng cho thấy có điều gì đó không ổn với máy chủ SQL khiến nó không hiểu vùng chứa docker của chúng tôi hoặc nó không chạy trong vùng chứa docker. Trong trường hợp này, bộ chứa docker đang chạy như một máy riêng biệt bên trong máy tính chủ. Vì vậy, để kết nối với cơ sở dữ liệu SQL trong máy chủ, các kết nối từ xa tới SQL cần được kích hoạt. Chúng tôi có thể sửa lỗi này.
     
  10. Mở Trình quản lý Cấu hình Máy chủ SQL. Bây giờ chọn Giao thức cho MSSQLSERVER và lấy số cổng IPAll trong phần TCP / IP.






  11. Chuỗi kết nối được đề cập trong tệp JSON trỏ đến nguồn dữ liệu là cục bộ mà vùng chứa docker không hiểu. Nó cần địa chỉ IP thích hợp với xác thực cổng và SQL. Vì vậy, hãy cung cấp các chi tiết liên quan tức là Nguồn dữ liệu như địa chỉ Ip, số cổng và chi tiết xác thực SQL như được hiển thị bên dưới.

  12. Bây giờ một lần nữa chạy ứng dụng với Docker như một tùy chọn như đã thực hiện trước đó.



    Lần này nhận được phản hồi.
  13. Thử nghiệm tương tự trong Người đưa thư.

  14. Kiểm tra lại với IIS Express URL.

Điều này chứng tỏ rằng microservice đang chạy trên hai điểm cuối và trên hai hệ điều hành được triển khai cục bộ một cách độc lập.

Sự kết luận

Dịch vụ vi mô là một dịch vụ được xây dựng xung quanh một khả năng kinh doanh cụ thể, có thể được triển khai độc lập được gọi là ngữ cảnh bị ràng buộc. Bài viết này về microservices tập trung vào microservices là gì và lợi thế của chúng so với kiến ​​trúc dịch vụ nguyên khối. Bài viết mô tả chi tiết để phát triển một microservice bằng ASP.NET Core và chạy nó qua IIS và Docker container. Tương tự như vậy, dịch vụ có thể có nhiều hình ảnh và có thể được chạy trên nhiều vùng chứa tại cùng một thời điểm.

Nguồn bài viết gốc tại https://www.c-sharpcorner.com

#microservice #aspdotnet #dotnet #csharp #docker