Blockchain cơ bản – Học lập trình Ethereum (P2)

236

Bài trước chúng ta đã nói khá nhiều về lập trình Ethereum dùng Truffle và command line Ganache. Bài này chúng ta sẽ dùng environment này để nói về 2 concept khác của Solidity: Interface và các Function Modifier.

Cài đặt sẵn sàng

Sau khi bạn đã cài Truffle và ganache-cli, tạo một folder mới và chạy truffle init. Chúng ta sẽ tạo 2 contract trong folder truffle mới tạo.

  • Answers.sol

  • Questions.sol

Contract Answers.sol rất đơn giản. Một variable answerUniverse có cả getter và setter. Lưu ý rằng, bởi vì nó quan trọng rằng setter là nhân tố ngoài, nghĩa là nó phải được call từ ngoài contract, còn getter thì public nghĩa là ai call nó cũng được.

Contract Questions.sol gồm 2 thứ: contract Questions, và interface AnswersInterface. Vậy, interface là gì? Một interface cho phép chúng ta nói về một contract khác trên blockchain. Như bạn có thể thấy, để xác định một interface, bạn phải bắt đầu từ một contract bình thường, với keyword contract. Trong contract này, bạn chỉ xác định các function bạn muốn tương tác không cần phần thân. Các function này cần là public hoặc từ bên ngoài để có thể call chúng từ ngoài contract gốc. Bạn không thể tương tác với các function riêng hoặc nội bộ course được.

Bên trong contract Questions, chúng ta sẽ tạo một interface mẫu trong answersContract. Function setAnswersContractAddress sẽ cho contract biết chỗ tìm được contract Answer gốc. Function whatIsTheAnswerUniverse thu về variable answerUniverse trong contract Answers.

Note: Dĩ nhiên chúng ta cần phải set địa chỉ contract trước khi lấy variable. Nếu không chúng ta sẽ chả biết nó ở đâu trên blockchain!

  • Tiếp đến, trong file truffle-config.js:

Với người dùng Windows, bạn sẽ phải remove file truffle.js để tránh mâu thuẫn. Với hệ khác, bạn có thể giữ lại cả hau và bỏ vào code trong truffle.js, hoặc lằm giống như user Windows chẳng sao cả.

  • Trong folder migrations, tạo 2 file: 2_deploy_questions.js và 3_deploy_answers.js.
  • 2_deploy_questions.js

  • 3_deploy_answers.js

Triển khai thôi

Mở một cửa sổ terminal mới và chạy ganache-cli -p 7545. Quay lại folder của project và chạy:

  • truffle compile
  • truffle migrate --network development
  • truffle console --network development

Bây giờ chúng ta có thể chơi với các contract và interface của nó. Đầu tiên, tạo một instance cho mỗi contract.

Sau khi launch Answers instance, bạn sẽ thấy vài thứ mới xuất hiện trong console. Sẽ có cả field address. Đây là address của contract Answers. Đây có thể là những gì ta cần để call setAnswersContractAddress function:

truffle(development)> Questions.setAnswersContractAddress('0x2e91a07090cfbbc0839e0d76d8110e2518bae18c')

Note: Hãy thế address bằng bất cứ address nào bạn thấy trong field.

Hãy xem answersUniverse variable trong Answers contract:

truffle(development)> Answers.setAnswerUniverse(76)

Và lấy nó từ contract Questions:

Hãy chỉnh lại answer và retrieve lần nữa:

Và bạn đã có một interface rồi.

Các function modifier

Có thể dễ thấy một vấn đề về bảo mật trong project của chúng ta: function setAnswersContractAddress là yếu tố từ bên ngoài, nghĩa là bất kì ai từ ngoài contract cũng gọi nó được, cũng có nghĩa là ai cũng có thể call function và đổi address được cả. Để giải quyết được việc này, chúng ta phải add một function modifier, sẽ được call khi function được thực hiện. Căn bản là, nó sẽ chạy một vài đợt check để đảm bảo rằng mọi thứ vẫn ổn. Trong trường hợp này, chúng ta phải đảm bảo rằng chỉ có người sở hữu mới gọi được function. Để vậy chúng ta sẽ dùng contract từ thư viện OpenZeppelin Solidity gọi là OwnableCopy và dán nó vào.

Đừng hoảng lên nếu bạn không hiểu gì trong contract. Chỉ cần biết rằng nó sẽ đảm bảo cho function chỉ có thể kích hoạt được bởi chủ.

  • Tạo một file Ownable.sol trong các contract

  • Import contract Ownable vào Questions và xác định function modifier cho setAnswersContractAddress:

Relaunch command ganache-cli, và các command truffle. Deploy các contract Answers và Questions. Mặc định chủ contract sẽ là account đầu tiên được tạo bởi  ganache-cli. Sau đó lấy một account khác:

truffle(development)> account = web3.eth.accounts[3]

Bây giờ, nếu chúng ta set interface address từ account này, bạn sẽ bị lỗi:

Nếu bạn remove cái object argument, hoặc dùng accounts[0] address trong key, bạn vẫn có thể set address ổn thoả.

TopDev via dev.to