Blockchain cơ bản – Học về Solidity (P2)

Trong bài trước chúng ta đã khởi động bằng một số concept cơ bản của Solidity bằng cách tạo một contract đơn giản và khám phá một số cấu trúc cùng concept đơn giản. Bây giờ chúng ta sẽ tiếp tục bằng một số concept phức tạp hơn.

Các Mapping

Tiếp nối struct và arrays, chúng ta còn có thể lưu trữ data trên các mapping. Các mapping là nơi chứa key-value. Ví dụ:

mapping(uint => string) public keyUintStringValue;
mapping(address => uint) public addressToUint;

Chúng ta có 2 public mapping. Cái đầu có uint key và string value. Cái thứ 2 có address key và uint value.

Addresses

Ethereum blockchain được tạo nên từ các address. Mỗi account có một address riêng. Nó có dạng dưới đây: 0x0cE440255306E921F41612C46F1v6df9Cc969183. Mỗi address có một lượng Ether nhất định, là số cryptocurrency được dùng trên blockchain, và có thể cho và nhận Ether từ các address khác.

Từ đó tạo một mapping mới cho DeveloperFactory:

pragma solidity ^0.4.22;

contract DeveloperFactory {

    event NewDeveloper(uint devId, string name, uint age);

    uint maxAge = 100;
    uint minAge = 5;

    struct Developer {
        string name;
        uint id;
        uint age;
    }

    Developer[] public developers;

    mapping (address => uint) public ownerDevCount;
    mapping (uint => address) public devToOwner;

    function _createDeveloper( string _name, uint _id, uint _age ) private{
        uint id = developers.push( Developer( _name, _id, _age ) ) - 1;
        NewDeveloper(id, _name, _age);
    }

    function _generateRandomId( string _str ) private pure returns (uint){
        uint rand = uint(keccak256(_str));
        return rand;
    }

    function createRandomDeveloper( string _name, uint _age ) public view {
        require(_age > minAge);
        require(_age < maxAge);
        uint randId = _generateRandomId( _name );
        _createDeveloper(_name, randId, _age );
    }
}

Trong mapping đầu tiên, chúng ta sẽ theo dõi số dev trong mỗi account (address) có. Ngay sau đó sẽ theo dõi được owner cho mỗi dev.

msg.sender

Mỗi contract đều khá bị động, nó sẽ không làm gì trừ phi có ai đụng tới. msg.sender là một global variable cho chúng ta biết address nào phụ trách việc kích hoạt. Nó có thể là account hoặc là một smart contract khác.

Với thông tin này, chúng ta có thể update mapping của mình một cách hợp lí. Trên function _createDeveloper, chúng ta sẽ tăng ownerDevCount cho riêng address này. Trong mapping devToOwner, chúng ta phải chỉ ra developer mới tạo được sở hữu bởi msg.sender address.

pragma solidity ^0.4.22;

contract DeveloperFactory {

    event NewDeveloper(uint devId, string name, uint age);

    uint maxAge = 100;
    uint minAge = 5;

    struct Developer {
        string name;
        uint id;
        uint age;
    }

    Developer[] public developers;

    mapping (address => uint) public ownerDevCount;
    mapping (uint => address) public devToOwner;

    function _createDeveloper( string _name, uint _id, uint _age ) private{
        uint id = developers.push( Developer( _name, _id, _age ) ) - 1;
        ownerDevCount[msg.sender]++;
        devToOwner[id] = msg.sender;
        NewDeveloper(id, _name, _age);
    }

    function _generateRandomId( string _str ) private pure returns (uint){
        uint rand = uint(keccak256(_str));
        return rand;
    }

    function createRandomDeveloper( string _name, uint _age ) public view {
        require(_age > minAge);
        require(_age < maxAge);
        uint randId = _generateRandomId( _name );
        _createDeveloper(_name, randId, _age );
    }
}

Hãy lưu ý kí hiệu ++ để tăng ownerDevCount[msg.sender], giống y như Javascript!

Inheritance và import

Các contract có thể kế thừa từ các contract khác. Nếu bạn mở file mới tên DeveloperLearning.sol, nó cũng có thể kế thừa từ DeveloperFactory.sol:

pragma solidity ^0.4.22;

import "./DeveloperFactory.sol";

contract DeveloperLearning is DeveloperFactory {
    // I have now access to DeveloperFactory functions
}

Hãy xem cách chúng ta import contract DeveloperFactory (giả sử nó nằm cùng folder). Để được kế thừa từ nó, chúng ta dùng keyword  is.

payable

Để một contract nhận được ether, chúng ta cần có keyword payable trong function. Lượng gửi đi có thể access được trong global variable msg.value. Vì thế phải đảm bảo đã gửi trước một lượng ether nhất định trước khi tạo một developer:

pragma solidity ^0.4.22;

contract DeveloperFactory {

    event NewDeveloper(uint devId, string name, uint age);

    uint maxAge = 100;
    uint minAge = 5;

    struct Developer {
        string name;
        uint id;
        uint age;
    }

    Developer[] public developers;

    mapping (address => uint) public ownerDevCount;
    mapping (uint => address) public devToOwner;

    function _createDeveloper( string _name, uint _id, uint _age ) private{
        uint id = developers.push( Developer( _name, _id, _age ) ) - 1;
        ownerDevCount[msg.sender]++;
        devToOwner[id] = msg.sender;
        NewDeveloper(id, _name, _age);
    }

    function _generateRandomId( string _str ) private pure returns (uint){
        uint rand = uint(keccak256(_str));
        return rand;
    }

    function createRandomDeveloper( string _name, uint _age ) public payable {
        require(_age > minAge);
        require(_age < maxAge);
        require(msg.value == 5);
        uint randId = _generateRandomId( _name );
        _createDeveloper(_name, randId, _age );
    }
}

Memory và Storage

Trong Solidity, có 2 chỗ lưu variable: trong storage hoặc trong memory. Một variable lưu trên memory chỉ là tạm thời, nó còn khi function được dùng đến, sau đó sẽ bị xoá. Một variable lưu trên storage thì ở đó vĩnh viễn. Bạn cũng không cần phải lo lắng về việc variable được lưu ở đâu, vì Solidity sẽ xử lý nó giúp bạn.

Ví dụ như, các state variable (maxAge, minAge, Developer), được khai báo ngoài function thì sẽ lưu trên storage. Các variables như randId, id, rand được store trên memory.

Tuy nhiên, trong một số trường hợp, bạn muốn cần chi tiết chỗ lưu một variable nhất định. Solidity sẽ show cho bạn bằng keyword memory và storage.

Tham khảo thêm vị trí tuyển lập trình blockchain lương cao tại đây