dev/Solidity

LV.1 crypto zombies - 3 Advanced Solidity Concepts

_April 2021. 11. 26. 21:54

contract ownership, gas costs, code optimization, and security 등 중요한걸 배운다고한다

궁금했다. 가보자고


(1)Immutability of Contracts

그렇지 이더리움에 한번 올리면 못고치지

after you deploy a contract to Ethereum, it’s immutable, which means that it can never be modified or updated again.

 

his is one reason security is such a huge concern in Solidity. If there's a flaw in your contract code, there's no way for you to patch it later. You would have to tell your users to start using a different smart contract address that has the fix.

스마트컨트랙을 ㅠ 나중에 ㅠ 바꾸는서비스가 ㅠ 어딨어요

한번에 잘해야한다..가 얼마나 불가능한일인지 개발자들은 알것이다.

 

For this reason, it often makes sense to have functions that will allow you to update key portions of the DApp.

가능한한 유연하게, 고칠수있게 만들어야한다.

For example, instead of hard coding the CryptoKitties contract address into our DApp, we should probably have a setKittyContractAddress function that lets us change this address in the future in case something happens to the CryptoKitties contract.

그렇다.. 

 


(2)Ownable Contracts

Ownable — meaning they have an owner (you) who has special privileges.

external이어도 내가만든 컨트랙이 아니면 그 함수 가져다 쓸수없게함

 

OpenZeppelin is a library of secure and community-vetted smart contracts that you can use in your own DApps

 

상속할때처럼 is Ownable하면 됨


(3)Modifier

함수에 붙어서 함수에 어떤 제약을 걸어주기도 하고 부가적인 기능을 만들어준다.(함수를 꾸며준다.)

modifier는 함수를 꾸며주는데 꾸며준 다음에 본래 함수를 어디서 실행할지 결정해야 한다. 이 때 이 ‘어디서 실행할 지' 결정해주는 것이  _ 이다. (placeholder라고도 함)

  modifier onlyOwner() {
    require(isOwner());
    _;
  }

예제를 보면

require(isOwner()); 를 통해

현재 컨트랙트의 함수를 실행한 어드레스의 주소(msg.sender)가 이 컨트랙트에 owner라고 정의된 주소와 같느냐를 물어본다. 그 후에 언더스코어 _; 가 등장한다. 이 때 바로 이 언더스코어 부분에서 onlyOwner가 꾸며준 함수가 실행되는 구조로 동작한다.

 

언제쓰냐:

100개의 함수가 있는데, 그 100개의 함수들은 나이가 성인인지 아닌지 체크를 해야하는 require가 필요 하다고 가정해보자.
 각 함수마다 당연히 require(_age>17, "You are under 18 years old")를 하나하나 일일히 써야한다.
즉 reqire문을 100 번 써야한다. (100번의반복)
 
19세 미만이 아니라 15세 미만으로 나이제한이 바뀌면?
각 함수의 require 마다  require(_age>14, "You are under 15 years old") 라고 고쳐야하는데
100 번이나 고쳐야한다.

이러한 불편함을 극복하기 위해서  Modifier을 쓴다.

 


(4)Gas

그치 뭐할때마다 이더를 가스로 내야하져

In Solidity, your users have to pay every time they execute a function on your DApp using a currency called gas. Users buy gas with Ether (the currency on Ethereum), so your users have to spend ETH in order to execute functions on your DApp.


How much gas is required to execute a function depends on how complex that function's logic is. Each individual operation has a gas cost based roughly on how much computing resources will be required to perform that operation (e.g. writing to storage is much more expensive than adding two integers). The total gas cost of your function is the sum of the gas costs of all its individual operations.

Because running functions costs real money for your users, code optimization is much more important in Ethereum than in other programming languages. If your code is sloppy, your users are going to have to pay a premium to execute your functions — and this could add up to millions of dollars in unnecessary fees across thousands of users.

 

최적화가 곧 돈이다.. 무써운 세계군요

Why is gas necessary?

Ethereum is like a big, slow, but extremely secure computer. 이 비유 좋은듯. When you execute a function, every single node on the network needs to run that same function to verify its output — thousands of nodes verifying every function execution is what makes Ethereum decentralized, and its data immutable and censorship-resistant.

 

The creators of Ethereum wanted to make sure someone couldn't clog up the network with an infinite loop, or hog all the network resources with really intensive computations. So they made it so transactions aren't free, and users have to pay for computation time as well as storage.

이래서 가스비 폭발할때마다 비탈릭이 욕을 바가지로 먹는거군요..

 

그래서 기본 uint대신(256)

uint8, uint16, uint32 쓸수있음 써서최소화 시키라는것임. 완전 몇메가바이트밖에 없던 씨-씨쁠쁠 시절과 똑같은.. 접근이네요..

근데 헬인게 씨쁠쁠은 나중에 숫자가생각보다 커지면 타입바꾸면되는데

솔리디티는 바꾸지도못함.. wow

 

더 황당한거

You'll also want to cluster identical data types together (i.e. put them next to each other in the struct) so that Solidity can minimize the required storage space. For example, a struct with fields uint c; uint32 a; uint32 b; will cost less gas than a struct with fields uint32 a; uint c; uint32 b; because the uint32 fields are clustered together.

???

이건왠지모르겠는데 데이터유형 맞춰야 가스비가 덜든다고함. 솔리디티 최적화 난이도 무엇

 


(5)Time Units

시간 native unit이 있음

The variable now will return the current unix timestamp of the latest block (the number of seconds that have passed since January 1st 1970).

 

 

Note: Unix time is traditionally stored in a 32-bit number. This will lead to the "Year 2038" problem, when 32-bit unix timestamps will overflow and break a lot of legacy systems. So if we wanted our DApp to keep running 20 years from now, we could use a 64-bit number instead — but our users would have to spend more gas to use our DApp in the meantime. Design decisions! ㅋㅋ장난하나용

 

나머지 시간유닛은 seconds, minutes, hours, days, weeks and years

 


(6)Function modifiers with arguments

// A mapping to store a user's age:
mapping (uint => uint) public age;

// Modifier that requires this user to be older than a certain age:
modifier olderThan(uint _age, uint _userId) {
  require(age[_userId] >= _age);
  _;
}

// Must be older than 16 to drive a car (in the US, at least).
// We can call the `olderThan` modifier with arguments like so:
function driveCar(uint _userId) public olderThan(16, _userId) {
  // Some function logic
}

이거 좋아보인다.

 

Note: calldata is somehow similar to memory, but it's only available to external functions.

calldata must be used when declaring an external function's dynamic parameters.


(7) View functions don't cost gas

 

This is because view functions don't actually change anything on the blockchain – they only read the data. 

 


(8)Storage is Expensive

One of the more expensive operations in Solidity is using storage — particularly writes.
This is because every time you write or change a piece of data, it’s written permanently to the blockchain.

 

Avoid writing data to storage except when absolutely necessary. Sometimes this involves seemingly inefficient programming logic — like rebuilding an array in memory every time a function is called instead of simply saving that array in a variable for quick lookups.

In most programming languages, looping over large data sets is expensive. But in Solidity, this is way cheaper than using storage if it's in an external view function, since view functions don't cost your users any gas. (And gas costs your users real money!).

 

어쩐지 블록체인 느리더라..... big O를 이기는 "가스비원칙"

 

그래서 memory를쓰는게 훨싸고, 만약 view안에서 불렀다면 완전 공짜

단,

 memory arrays must be created with a length argument. They currently cannot be resized like storage arrays can with array.push(),


(9)Loops

이건그냥 루프문