deploy : 블록체인 네트워크에 등록
compile : 블록체인 네트워크에 등록하기 전에 미리 검사?
블록체인은 전세계적으로 공유되어 트랜잭션이 일어나는 데이터베이스입니다.
local : 함수 내부에 선언, blockchain에 기록 안 됨
state : 함수 외부에 선언, blockchain에 기록됨
=> public 키워드: 접근 제어자일 뿐, 변수 종류에 영향 미치는 건 아님 optional
global : blockchain관련 정보 (block.timestamp, msg.sender)
state 변수를 쓰거나 업데이트하려면 transaction을 보내야 함. 읽는 건 무료로 가능.
transaction은 either로 값을 낸다. gas spent * gas price
gas spent는 transaction에서 사용한 총 gas의 양
gas price는 gas당 얼마의 either를 지불할 것인지
gas price가 높으면 block에 포함될 우선순위 높아짐
남은 gas는 환불됨
gas limit: 내가 설정한 값
block gas limit: 네트워크에서 설정한 값
if/else if/else
for/while/do while: while은 gas 다 써서 실패할 가능성 있으므로 비추
keyType에는 uint, address, bytes가능
valueType에는 제한 없음
멤버 한 번에 하나씩 반환 불가능: 파이썬 dictionary처럼 전체 멤버 순회 불가능하다는 뜻
항상 return값을 가지고 설정 안 하면 default값(맨처음값 반환)
contract NestedMapping {
// Nested mapping (mapping from address to another mapping)
mapping(address => mapping(uint => bool)) public nested;
function get(address _addr1, uint _i) public view returns (bool) {
// You can get values from a nested mapping
// even when it is not initialized
return nested[_addr1][_i];
}
function set(
address _addr1,
uint _i,
bool _boo
) public {
nested[_addr1][_i] = _boo;
}
function remove(address _addr1, uint _i) public {
delete nested[_addr1][_i];
}
}
array를 리턴할 땐 무조건 memory를 써야 하는가? memory 키워드는 필수가 아닌가? -> gas 소모 안 하기 위해
delete arr[idx] : gas소모
arr[idx] = arr[arr.length-1] -> swap인가? 왜 이렇게 하면 gas 소모 안 하지? 소모를 안 하는 건지 적게 하는 건지
// Solidity can return the entire array.
// But this function should be avoided for
// arrays that can grow indefinitely in length.
function getArr() public view returns (uint[] memory) {
return arr;
}
첫번째 요소가 default
언제나 index로 요소 지정 가능함
enum Status {
pending, skipped, accepted
}
struct Todo {
string text;
bool completed;
}
초기화하기
업데이트하기
여러 개 return 가능
public 함수는 map, array input, output 불가능
getter 함수는 view나 pure로 선언 가능
view : 상태변화 없음
pure : 상태변화 없고 읽지도 못함 -> return값을 못읽는다는 거? 매개변수는 읽을 수 있나? 컨트랙트 내부 변수는 안 건드리고 매개변수만 다루는 함수에 사용
함수 호출 전후에 실행
contract 생성할 때 선택적으로 생성
is 로 상속하고 다중상속 가능
overriden할 거면 부모는 virtual 키워드 꼭 쓰고, 자식은 override 키워드 꼭 써야 함
가장 오른쪽에 있는 부모가 덮어쓴다
부모->자식 순으로 써야 한다.
function modifier는 deadlock 막는 용도
접근제어자는 함수의 visibility 제한하는 용도
다른contract와 상호작용하기 위해
함수구현, 생성자, state변수 안 됨
상속 가능
모든 함수는 external로 선언해야 함
========================
interface만 모아 둔 .sol파일을 만들어서 사용해도 되나? 어떻게 import 없이 사용하지?매개변수 주소로 해당 함수와 변수가 선언된 컨트랙트 위치 불러옴
MyContract에서 매개 변수로 받는 _counter는 Counter contract 주소만 가능하다 ㅇㅇ
MyContract의 함수 내부 말고 state 변수처럼 함수 밖에다 ICounter 선언하고 사용하면 안되나? 그러면 값이 고정되기 때문에 변화하는 값을 불러올 수 없음
contract Counter {
uint public count;
function increment() external {
count += 1;
}
}
interface ICounter {
function count() external view returns (uint);
function increment() external;
}
contract MyContract {
function incrementCounter(address _counter) external {
ICounter(_counter).increment();
}
function getCount(address _counter) external view returns (uint) {
return ICounter(_counter).count();
}
}
function이나 address에 사용
보내기
call함수+재입장 방지 제어자 사용 추천
받기
fallback은 매개변수도 없고 return도 안 함
1) 존재하지 않는 함수를 호출하거나
2) 이더를 보내는 데 receive()가 없거나 msg.data가 없으면
자동으로 실행됨
low level 함수
fallback()한테 이더 보낼 때 추천됨
이미 있는 함수로 보낼 땐 비추?
{value: msg.value, gas: 5000} call 함수의 특별한 형식인 듯
// Let's imagine that contract B does not have the source code for
// contract A, but we do know the address of A and the function to call.
function testCallFoo(address payable _addr) public payable {
// You can send ether and specify a custom gas amount
(bool success, bytes memory data) = _addr.call{value: msg.value, gas: 5000}(
abi.encodeWithSignature("foo(string,uint256)", "call foo", 123)
);
emit Response(success, data);
}
contract Callee {
uint public x;
uint public value;
function setX(uint _x) public returns (uint) {
x = _x;
return x;
}
function setXandSendEther(uint _x) public payable returns (uint, uint) {
x = _x;
value = msg.value;
return (x, value);
}
}
contract Caller {
function setX(Callee _callee, uint _x) public {
uint x = _callee.setX(_x);
}
function setXFromAddress(address _addr, uint _x) public {
Callee callee = Callee(_addr);
callee.setX(_x);
}
function setXandSendEther(Callee _callee, uint _x) public payable {
(uint x, uint value) = _callee.setXandSendEther{value: msg.value}(_x);
}
}
메시지 콜은 다양한 변형이 있는데, 델리게이트 콜 의 경우는 대상 주소의 코드가 호출하는 컨트랙트의 컨텍스트 내에서 실행된다는 것과 msg.sender 와 msg.value 가 값이 바뀌지 않는다는 것 외에는 메시지 콜과 동일합니다.
이것은 컨트랙트가 실행 중 다양한 주소의 코드를 동적으로 불러온다는 것을 뜻합니다. 스토리지, 현재 주소와 잔액은 여전히 호출하는 컨트랙트를 참조하지만 코드는 호출된 주소에서 가져옵니다.
=> 코드만 불러오고 데이터는 내 컨트랙트 내의 데이터 사용한다는 뜻
컨트랙트와 비슷하지만, state 변수 선언이나 이더를 보내지는 못함
모든 함수가 internal이어야 함
아니면 deploy한 다음 호출하는 애가 deploy하기 전에 link되어야 함
using 키워드 사용하고 안 하고의 차이는 뭔가?
library Math {
function sqrt(uint y) internal pure returns (uint z) {
if (y > 3) {
z = y;
uint x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
// else z = 0 (default value)
}
}
contract TestSafeMath {
using SafeMath for uint;
uint public MAX_UINT = 2**256 - 1;
function testAdd(uint x, uint y) public pure returns (uint) {
return x.add(y);
}
function testSquareRoot(uint x) public pure returns (uint) {
return Math.sqrt(x);
}
}
mint는 뭔가?
트랜잭션
한 계정에서 다른 계정(같을수도 있고, 비어있을 수도 있습니다. 아래 참조)으로 보내지는 일종의 메시지입니다. 그리고 바이너리 데이터("페이로드"라고 불림)와 Ether 양을 포함할 수 있습니다.
대상 계정이 코드를 포함하고 있으면 코드는 실행되고 페이로드는 입력 데이터로 제공됩니다.
대상 계정이 설정되지 않은 경우(트랜잭션에 받는 사람이 없거나 받는 사람이 null 로 설정된 경우) 일 땐, 트랜잭션은 새로운 컨트랙트 를 생성하며 앞서 말씀드렸던 것처럼 사용자와 "논스"로 불리는 트랜잭션의 수에 의해 주소가 결정됩니다. 각 컨트랙트 생성 트랜잭션 페이로드는 EVM 바이트코드로 실행되기 위해 사용됩니다. 이 실행 데이터는 컨트랙트의 코드로 영구히 저장됩니다. 즉, 컨트랙트를 만들기 위해 실제 코드를 보내는 대신, 실행될 때의 코드를 리턴하는 코드를 보내야 한다는 것을 뜻합니다.
스토리지는 256비트 문자가 키-값 형태로 연결된 저장소입니다. 컨트랙트 내의 스토리지를 탐색하는 건 불가능하며 읽고 수정하는데 비용이 많이 듭니다. 컨트랙트가 소유하지 않은 스토리지는 읽거나 쓸 수 없습니다.
동기/비동기 정의
호출은 1024개의 깊이로 제한되며 이는 복잡한 연산일수록 재귀호출보다 반복문이 선호된다는 것을 뜻합니다