블록체인 TIL-10Week-64Day

디오·2023년 5월 15일
0
post-thumbnail

✅Quiz 풀이.

  • 강사님께서 Quiz2 이어서 풀이과정 진행.
contract QUIZ2 {
    struct User {
        bytes32 hash;
        uint attempts;
    }

    mapping(string => User) ID_PW;

    function getHash(string memory _ID, string memory _PW) public pure returns(bytes32) {
        return keccak256(abi.encodePacked(_ID, _PW));
    }

    
    function userInfo(string memory _ID) public view returns(string memory, User memory){
        return (_ID, ID_PW[_ID]);
    }

    // * 로그인 기능 - ID, PW를 넣으면 로그인 여부를 알려주는 기능
    function logIn(string memory _ID, string memory _PW) public returns(bool){
        // * 비밀번호 5회 이상 오류시 경고 메세지 기능 - 비밀번호 시도 회수가 5회되면 경고 메세지 반환
        require(ID_PW[_ID].attempts < 5, "Too much attempts");
        if(ID_PW[_ID].hash == getHash(_ID, _PW)) {
            ID_PW[_ID].attempts = 0;
            return true;
        } else {
            ID_PW[_ID].attempts++;
            return false;
        }
    }

    // * 회원가입 기능 - 새롭게 회원가입할 수 있는 기능
    function signIn(string memory _ID, string memory _PW) public{
        // * 회원가입시 이미 존재한 아이디 체크 여부 기능 - 이미 있는 아이디라면 회원가입 중지
        require(ID_PW[_ID].hash == 0x0000000000000000000000000000000000000000000000000000000000000000, "Provided ID is already being used");
        // require(ID_PW[_ID].hash == "", "Provided ID is already being used");
        ID_PW[_ID].hash = getHash(_ID, _PW);
    }

    // * 회원탈퇴 기능 - 회원이 자신의 ID와 PW를 넣고 회원탈퇴 기능을 실행하면 관련 정보 삭제 
    function signOut(string memory _ID, string memory _PW) public {
        require(ID_PW[_ID].hash == getHash(_ID, _PW));
        // require(logIn(_ID, _PW) == true); // 추후 수정
        delete ID_PW[_ID];
    }


}
  • 어렵다.






💻Require(기초)

contract REQUIRE {
/* 실습가이드
1. 5, 15 각각 Require()에 넣어보기
2. onlyAlice에 alice 한번, bob 한번 input 값으로 넣어보기
*/

    //10보다 작은 3의배수.(REQUIRE에는 조건문만 들어가야 한다.)
    function Require1(uint _n) public pure returns(uint) {
        //메세지를 넣을 수 있다.
        require(_n<10, "input should be lower than 10");
        return _n*3;
    }

    function getName(string memory _name) public pure returns(bytes32) {
        return keccak256(abi.encodePacked(_name));
    }

    function onlyAlice(string memory _name) public pure returns(bool) {
        require(getName(_name) == 0x9c0257114eb9399a2985f8e75dad7600c5d89fe3824ffa99ec1c3eb8bf3b0501);
        return true;
    }
}
  • if문과 require의 차이

    • if문은 거래를 끝까지 가게한다.
    • require는 거래를 마무리하지 않는다.
  • require

    • require는 가스를 끝까지 쓰지 않는다.
      • require를 사용하는 이유는 가스비를 절약할 수 있기 때문에.
    • 이게 아니면 이걸 할 필요가 없어 할때 require를 사용.
    • require는 안에 조건문만 들어가야 한다.
  • 예시

    • 회원명부가 있고 몇번에 엘리스를 찾고싶을땐 require를 사용하면 안되고 for문과 if문을 사용해야함.
    • 단지 엘리스인지 아닌지만 확인하고 싶을때 require를 사용.






💻Require(응용)


contract REQUIRE2 {
    function getBool() public pure returns(bool) {
        bool _a;
        return _a;
    }

    function Require1() public pure returns(uint) {
        uint _a=1;
        bool b;
        require(b, "Error"); // 통과못함
        return _a;
    }

    function Require2() public pure returns(uint) {
        uint _a=1;
        bool b;
        return _a;
        require(b, "Error"); // Unrecheable code
    }

    uint a = 1;

    function getA() public view returns(uint) {
        return a;
    }

    function Require3() public {
        bool c;
        a = 5;
        require(c, "error"); // a를 5로 바꾼 것도 전부다 다시 revert (원래 상태로 복구) 시킴.
    }

    function Require3_2() public {
        bool c;
        a = 5;
        require(!c, "error"); // a를 5로 바꾼 것도 전부다 다시 revert (원래 상태로 복구) 시킴.
    }

    function setAasFive() public {
        a =5;
    }

    // require 타 함수 호출
    function Require4() public {
        bool c;
        setAasFive(); // a의 값을 5로 설정하는 외부 함수
        require(c, "error"); // 외부함수도 모두 revert
    }
    
//require가 어디까지 뒤집을 수 있는지를 확인하고 싶어서 작성된 코드들.
    // require 조건 2개
    function Require5(uint _n) public pure returns(bool) {
        require(_n%5==0 && _n>10, "Nope");
        return true;
    }

    // if문 안의 require
    function Require6(uint _a) public pure returns(uint) {
        if(_a%3==0) {
            require(_a%3!=0, "nope"); 
        } else if(_a%3==1) {
            return _a%3;
        } else {
            return _a%3;
        }
    }
}
  • REQUIRE의 위치가 어디에 들어가느냐에 따라서 실행되는 범위가 어떻게 되는지 알아보기 위해 여러 방법을 사용.

  • uint가 bytes형태로 변하지 못하는 이유.

    • uint 같은 경우 정적이고, bytes는 동적이기 때문에 변할 수 없다.
  • abi.encodepacked는 uint를 bytes로 변경할 수 있는 과정을 도와준다.

  • if문안에 Require를 넣어 코드가 끝까지 실행되지 않도록 막을 수 있다.

  • Require 안 조건에 "!" 가 들어가면 반대가 되기때문에 조건에 부합하지 않았을 때도 실행된다.






💻Constructor(기초)

contract CONSTRUCTOR {
    uint a;
    uint b;

    constructor() {
        a = 7;
        b = 4;
    }

    function setA() public {
        a = 5;
    }

    function getA() public view returns(uint) {
        return a;
    }

    function getB() public view returns(uint) {
        return b;
    } 
}
//인풋값을 받는것.
contract CONSTRUCTOR2 {
    uint a;

    constructor(uint _a) {
        a = _a;
    }

    function getA() public view returns(uint) {
        return a;
    }
}
// 인풋을 두개 받을 수 있다.
contract CONSTRUCTOR3 {
    struct Student {
        string name;
        uint number;
    }

    Student s;

    constructor(string memory _name, uint _number) {
        s = Student(_name, _number);
    }

    function getStudent() public view returns(Student memory) {
        return s;
    }
}
// 안에 if나 else를 넣을 수 있다.
contract CONSTRUCTOR4 {
    uint a;

    constructor(uint _a) {
        if(_a>5) {
            a = _a;
        } else {
            a = _a*2;
        }
    }

    function getA() public view returns(uint) {
        return a;
    }
}
  • Constructor
    • 시작할때부터 값을 확 정해놓고 시작함.
    • 한 컨트랙트 당 한개밖에 선언을 못함.
    • 변하면 안되는 것들을 넣을때도 Constructor를 사용함.
    • Constructor 안에 if문 이나 for문을 사용할 수도 있다.






💻Constructor(응용)


contract CONSTRUCTOR5 {
    /*
    1. 1번 지갑으로 배포, value는 10eth로
    2. 배포 후 지갑 잔고 확인
    3. 2번 지갑으로 deposit() 1eth // 3,4,5번 지갑으로 똑같이 실행
    4. 지갑 잔고 확인 후, 2번 지갑으로 trnasferTo 시도, _to의 지갑 주소는 6번 지갑 금액은 5eth 
    5. 1번 지갑으로 transferTo 시도, _to의 지갑 주소는 6번 지갑 금액은 5eth
    6. 2번 지갑으로 withdraw 함수 시도, 1번 지갑으로 withdraw 함수 시도
    */
    
    address payable owner;

    constructor() payable {
        payable(this).transfer(msg.value);// 배포할 때 msg.value 만큼 contract에게 바로 입급.
        owner = payable(msg.sender); // 배포하는 지갑주소가 바로 owner로 설정.
    }

    function getOwner() public view returns(address) {
        return owner;
    }

    // 특정 지갑주소에 특정 금액만큼 보내는 함수.(contract가 _to에게 _amount를 보냄)
    function transferTo(address payable _to, uint _amount) public {
        require(msg.sender == owner, "only owner can transfer asset");
        _to.transfer(_amount);
    }

    receive() external payable{}// 일반 거래(별도의 호출되는 함수 없을때)시 해당 contract가 돈을 받을 수 있게 해주는 함수.

    // contract에 돈을 받는 함수.(contract가 msg.value만큼 돈을 받는 함수)
    function deposit() public payable returns(uint){
        return msg.value;
    }
    // withdraw는 돈을 보내는 함수.(contract가 owner에게 전액 돈을 보내는 함수. owner 입장에서는 전액 인출)
    function withdraw() public {
        require(msg.sender == owner, "only owner can transfer asset");
        owner.transfer(address(this).balance); 
    }
    // contract가 owner에게 _amount만큼 보내는 함수.
    function withdraw2(uint _amount) public {
        require(msg.sender == owner, "only owner can transfer asset");
        owner.transfer(_amount); //(_amount * 10**18) 이렇게 eth 단위로도 사용할 수 있음.
    }
    // ether도 넣을 수 있음.
    function withdraw3() public {
        require(msg.sender == owner, "only owner can transfer asset");
        owner.transfer(1 ether); 
    }
}
  • 특정 지갑주소에 특정 금액만큼 보내는 함수. (다시공부)






💻Modifier(기초)


contract MODIFIER {
    uint a;

    modifier lessThanFive() {
        require(a<5, "should be less than five");
        _;// 함수가 실행되는 시점.(자기를 호출한 함수의 코드.)
    }

    function aPlus() public {
        a++;
    }

    function aMinus() public {
        a--;
    }

    function getA() public view returns(uint) {
        return a;
    }

    function doubleA() public lessThanFive {
        a = a*2;
    }

    function plusTen() public lessThanFive {
        a += 10;
    }
}
  • Modifier
    • 똑같은 조건의 require를 여러번 적는게 싫어서 MODIFIER를 사용.
    • 함수를 보조해주는 역할
    • Modifier에서 제일 중요한건 _의 위치.






💻Modifier(응용.1)

contract MODIFIER2 {
    /*
    실습가이드
    1. setAasTwo()로 a 값 2로 만들기
    2. setA() 실행 후 결과 확인, getA()로 A 값 확인
    3. setAasTwo()로 a 값 다시 2로 만들기
    4. setA2() 실행 후 결과 확인, getA()로 A 값 확인
    */
    uint a;

    
    modifier plusOneBefore() {
        a++;
        _;
    }

    modifier plusOneAfter() {
        _;
        a++;
    }

    function setA() public plusOneBefore returns(string memory)  {
        if(a>=3) {
            return "A";
        } else {
            return "B";
        }
    }

    function setA2() public plusOneAfter returns(string memory)  {
        if(a>=3) {
            return "A";
        } else {
            return "B";
        }
    }

    function getA() public view returns(uint) {
        return a;
    }

    function setAasTwo() public {
        a = 2;
    }
}

contract MODIFIER3 {
    /*
    실습가이드
    1. setAasTwo()로 a 값 2로 만들기
    2. setA() 실행 후, getB2() 실행해서 결과 보기
    */
    uint a;
    string b;
    string[] b2;

    
    modifier plusOneBefore {
        _;
        a++;
        _;
    }

    function setA() public plusOneBefore  {
        if(a>=3) {
            b = "A";
            b2.push(b);
        } else {
            b = "B";
            b2.push(b);
        }
    }

    function getA() public view returns(uint) {
        return a;
    }

    function getB() public view returns(string memory) {
        return b;
    }

    function getB2() public view returns(string[] memory) {
        return b2;
    }

    function setAasTwo() public {
        a = 2;
    }
}
  • a++; 언더바; / 언더바; a++;

    • 최종적인 결과는 같지만 코드의 위치에 따라서 과정이 달라지게 할 수 있다.
  • _; 를 여러번 적용해서 사용할수도 있다.






💻Modifier(응용.2)

contract MODIFIER4 {
    struct Person {
        uint age;
        string name;
    }

    Person P;

    modifier overTwenty(uint _age, string memory _criminal) {
        require(_age >20, "Too young");
        require(keccak256(abi.encodePacked(_criminal)) != keccak256(abi.encodePacked("Bob")), "Bob is criminal. She can't buy it");
        _;
    }

    function buyCigar(uint _a, string memory _name) public pure overTwenty(_a, _name) returns(string memory) {
        return "Passed";
    }

    function buyAlcho(uint _a, string memory _name) public pure overTwenty(_a, _name) returns(string memory) {
        return "Passed";
    }

    function buyGun(uint _a, string memory _name) public pure overTwenty(_a, _name) returns(string memory) {
        return "Passed";
    }

    function setP(uint _age, string memory _name) public {
        P = Person(_age, _name);
    }

    function getP() public view returns(Person memory) {
        return P;
    }

    function buyCigar2() public overTwenty(P.age, P.name) view returns(string memory) {
        return "Passed";
    }

    function buyAlcho2() public overTwenty(P.age, P.name) view returns(string memory) {
        return "Passed";
    }

    function buyGun2() public overTwenty(P.age, P.name) view returns(string memory) {
        return "Passed";
    }

}
  • Modifier4~6은 어렴풋이 이해함. (이걸 이해했다고 표현하는게 맞나?)

  • mutex = 화장실, 예시) 누군가 들어가면 다른사람은 못들어옴.






🌜하루를 마치며..

  • Require : 분명 들었는데.. 잘모르겠다.. 테스트에서도 제대로 사용을 못했다.

  • constructor : 기초에서는 어렵지 않다고 생각했는데 응용으로 넘어가니까 좀 헷갈렸다. 그래도 이론적인건 이해를 좀 했다고 생각했는데 써보라고 하면 못쓸 것 같다.

  • Modifier : 왜 써야하는지는 알겠는데 역시나 응용 넘어가니까 너무 헷갈린다. 특히 언더바가 왔다갔다하고 여기갔다 저기갔다 하니까 이건 내가 칠수있으려면 좀 걸릴것 같다;

  • 테스트3 : 오늘 테스트를 또 봤다. 역시나 엉망이였다. 사실 나한테는 테스트는 아직 무리다; 그것보다는 뿌수기를 빨리 해봐야겠다.

profile
개발자가 되어가는 개린이"

0개의 댓글