일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- X보다 작은 수
- 함수 사용하기
- 평균은 넘겠지
- 10871
- 시험 성적
- 블록 체인
- for문 사용해보기
- 비트 코인
- 1%d
- 자바스크립트
- 이더리움
- 별 찍기 - 11
- 더하기 사이클
- Mist
- 솔리디티
- Baekjoon
- 가상 화폐
- 2448
- 세 수
- 1546
- Remix
- 그대로 출력하기
- Dapp
- if문 사용해보기
- 1065
- 백준
- 알고리즘 문제풀이
- 10817
- 단계별로 풀어보기
- 1110
- Today
- Total
블링블링 범블링
나도 dApp 개발해보자 강좌 - 4 본문
※ 이 글은 chaintalk의 atomrigs 님이 쓰신 글을 인용하였습니다.
(4) 컨트랙트 엑세스
web3.providers.HttpProvider
web3.eth.accounts
web3.eth.accounts[0]
var contractAddress = '0xc5244053ecA508a11951400fc7Af28738Fd0ce77';
다음은 ABI 를 선언하는 것입니다. ABI 값은 왼쪽 리믹스 스크린에서 카피해옵니다. 내용을 유심히 들여다 보면 컨트랙트에서 선언한 함수의 이름, 입력값, 출력값 변수 타입, 이름등이 망라되어 있습니다. 이 ABI 가 있어야만 컨트랙트에 있는 함수를 어떻게 써야 될지를 알 수 있게 됩니다.
var abi = [{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"}];
var simpleStorageContract = web3.eth.contract(abi);
같은 컨트랙트가 여러개의 주소에 동시에 존재할 수도 있겠지요. 지금 우리의 예제만 해도 똑같은 컨트랙트가 각자 다른 주소에 존재할테니까요.
이 개념을 클래스 - 인스턴트 라고 보통 이야기합니다. 클래스는 어떤 구체적인 대상이 아니라 그것의 개념적 형태, 원형이 됩니다. 반면 그 클래스를 실제로 구현한 개개의 존재는 인스턴스라고 합니다. 예를 들자면, 현대 소나타 GS 라는 모델이 클래스라고 한다면, 실제 존재하는 각각의 소나타 GS 자동차는 그 클라스의 구현, 인스턴스가 됩니다.
그렇다면 위에서 만든 simpleStorageContract 는 ABI 정의를 통해 어떤 함수가 들어 있는지 정의된 클래스입니다. 이 클래스는 여러 주소에 각각 다른 인스턴스로 존재할 수 있습니다. 그래서 우리가 엑세스하려고 하는 인스턴스가 어느 것인지 구체화하려면 컨트랙트 주소를 주어야 합니다.
var simpleStorage = simpleStorageContract.at(contractAddress);
simpleStorageContract에 하나의 구체적인 컨트랙트 주소를 'at' 이라는 함수를 이용해 부여함으로써 simpleStorage 라는 인스턴스를 만들었습니다.
simpleStorage 는 여러분 각자의 주소에 있는 개별 컨트랙트가 됩니다.
이렇게 해서 컨트랙트를 엑세스할 수 있는 모든 준비가 끝났습니다.
이제 이 컨트랙트를 이용해 컨트랙트안에 있는 storedData 라는 변수에 특정한 값을 저장해 봅시다.
위의 스크린에서 첫번째 명령어를 살펴봅시다.
simpleStorage.set(12345);
컨트랙트에서 우리가 만들어 두었던 set() 함수를 이용해 보았습니다. 입력값으로 12345 를 주었습니다. 부호없는 정수값을 받도록 설계했던 것 기억하실 겁니다.
그런데 에러가 납니다.
메타마스크는 synchronous 트랜잭션을 지원하지 않는다는 겁니다. callback 함수를 지정해라 이런 메시지가 나옵니다.
갑자기 난해해지기 시작합니다. 하지만 개념을 잘 파악하면 그리 어려운 내용이 아닙니다.
웹페이지에서 우리가 어떤 함수를 호출해서 서버나 다른 벡엔드(지금의 경우에는 블록체인)에 요청 또는 리퀘스트를 보냈을 때 이를 어떻게 처리햐느냐에 따라 두가지 방식이 있습니다. 동기식 synchronous 과 비동기식 asynchronous (줄여서 async) 이 있습니다.
동기식은 브라우저가 하나의 함수를 불러서 서버에 요청하면, 서버가 답을 해줄 때까지 다른 작업을 중단하고 계속 그 답을 기다리고 있는 방식입니다. 보통은 별 문제가 없지만, 하지만 만일 서버가 답을 빨리 주지 않을 경우, 브라우저에서 다른 것을 전혀 할 수 없고 먹통이 되는 수가 있습니다. 반면 비동기식은 브라우저가 요청을 한 후 답을 안 기다리고 바로 다른 작업을 수행해 버립니다. 대신 서버한테 답이 준비되면 실행해야 할 함수를 미리 줍니다. 이렇게 비동기식으로 처리하면, 브라우저는 서버를 기다리지 않아도 되기 때문에 막힘이 없게 되고, 나중에 답이 오면 그 때 서버한테 부탁했던 함수가 실행되니 따로 더 대기할 필요가 없게 됩니다. 메타마스크가 거의 대부분의 함수를 전부 비동기식으로 처리하기로 한 것은, 블록체인의 특성상, 새 블록이 생성될 때까지 기다려야 할 때도 있고, 메타마스크의 경우 라이트 클라이언트이기 때문에 데이타를 외부 다른 노드에서 받아와야 되는 시간도 필요하기 때문입니다.
앞으로 우리가 볼 예제들에서는 모두 메타마스크를 지원하기 위해 비동기식 호출을 하도록 하겠습니다.
비동기식 호출을 한다는 것은 백엔드 쪽에 미리 실행될 함수를 같이 던져 줘야 한다는 것을 의미하는 것이고, 이 함수를 콜백(callback) 함수라고 부릅니다.
위의 명령어를 비동기식으로 호출하면 다음과 같이 됩니다.
simpleStorage.set(12345, function(e,r){console.log(r);});
동기식으로 호출한 것과의 차이는 12345 값 뒤에 콜백 함수를 던져 준겁니다.
function(e,r){console.log(r);}
함수인데 특별히 이름도 없습니다. 이렇게 이름을 생략해도 상관없습니다. 이 함수는 메타마스크(백엔드)가 클라이언트가 요청한 작업을 완료했을 때 호출하는 함수입니다. 입력값이 두개인데, e 는 에러가 있다면 에러 메시지, r 은 요청한 내용이 있다면 이를 리런해주는 변수입니다. r 이라고 해도 좋고 response 라고 넣어도 좋지만 그냥 간략하게 r 이라고 붙였습니다. console 은 지금 이 명령어들을 넣고 있는 콘솔프롬프트이고 log 라는 명령어는 입력값을 화면에 프린트 해주라는 겁니다.
전체적으로 다시 해석하면 메타마스크가 블록체인의 컨트랙트에 있는 storedData 에 12345 라는 값을 저장하고, 그 결과값 r 을 화면에 뿌려주라는 것이지요.
그럳데 앞 편에서 코딩했던 set 함수를 다시 찾아보면 그 함수에는 리턴값이 없습니다. 그렇다면 r 에는 도대체 어떤 것이 들어오게 될까요?
우리가 선언한 함수 자체에는 리턴값이 없었지만, 메타마스크가 트랜잭션을 보내면, 그 트랜잭션의 주소값을 자동으로 리턴하게 되어 있습니다. 위의 그림에서 호출된 함수 다음에 출력된 0x45... 값은 이 트랜잭션이 기록된 블록체인상의 주소 값입니다.
여기서 한가지 더 짚고 갈 것이 있습니다.
web3 가 처리하는 함수에는 두가지가 있습니다.
하나는 블록체인의 상태를 변화시키는 함수이고, 다른 하나는 상태변화를 일으키지 않는 읽기 전용의 함수입니다.
상태변화를 일으키기 위해서는 개스를 소모하는 트랜잭션을 블록체인에 보내야 하지만, 상태변화가 없는 함수는 트랜잭션을 보낼 필요 없이, 그냥 읽기만 하면 됩니다. 읽는 데에는 개스소모가 없습니다.
상태변화를 일으키는 트랜잭션을 보내는데 사용하는 함수가 sendTransaction() 이고 읽기만 하는 함수를 실행하는 것이 call() 입니다.
어떤 함수를 실행할 때 명시적으로 sendTransaction() 또는 call() 을 선언하지 않으면, web3 는 컨트랙트 상에 정의된 함수의 형태 키워드로 판단해서 둘 중에 적합한 것을 자동으로 골라서 실행합니다. 그 키워드가 constant 입니다. 함수의 리턴 앞에 constant 를 넣으면 이 함수는 읽기 전용이라는 것이 되고 sendTransaction 을 실행하는게 아니라 call() 를 실행합니다. 앞 편에서 정의한 get 함수를 보면 contant가 선언되었음을 확인할 수 있을 겁니다.
function get() constant returns (uint) {
return storedData;
}
반면 set() 함수는 이 키워드를 사용하지 않았습니다.
function set(uint x) {
storedData = x;
}
따라서 set 함수는 상태변화를 포함하는 함수라는 것을 의미하게 되고, ABI 에도 이것이 포함되어 있습니다. 그래서 우리가 simpleStorage.set(12345, function(e,r){console.log(r);}); 실행하면 web3 가 뒤에서 자동으로 sendTransaction 을 실행하고, 이 트랜잭션의 주소값을 리턴해 주는 것입니다.
만일 이렇게 자동으로 처리하는 방식을 따르지 않고 직접 명시적으로 sendTransaction 을 호출하면 다음과 같은 명령어가 됩니다.
simpleStorage.set.sendTransaction(12345, function(e,r){console.log(r);});
이 경우에 sendTransaction 을 넣거나 빼거나 처리 과정과 결과는 동일합니다. 나중에 sendTransaction 에 수동으로 개스값이나 다른 파라미터 셋팅이 필요할 경우에는 이렇게 명시적으로 써야 하는 경우도 있습니다.
이렇게 set() 명령을 사용해 12345 라는 임의의 값을 블록체인위에 저장을 해보았습니다.
다음은 이를 불러오는 함수에 대한 설명해 보겠습니다.
우리가 코딩했던 get 은 입력값을 받지 않고 그냥 storedData 에서 바로 값을 꺼내서 리턴하는 것이었습니다. 그런데 이번에도 비동기식 호출을 위해서 get에 콜백함수를 던져 주었습니다.
simpleStorage.get(function(e,r){console.log(r.toNumber());});
r.toNumber() 라는게 뭔가하면, 돌려 받은 r 의 형식이 자바스크립트의 어브젝트 구조로 되어 있어서 정수형태로 프린트하기 위해 toNumber() 라는 내장함수를 이용해 바꾼 것입니다. 결과값은 우리가 앞에서 set 한 값인 12345 가 출력이 됩니다.
이번에는 get 함수가 constant 라고 미리 컨트랙트 디자인 때 선언해 두었고, 또 ABI 에 이것이 반영되어 있으므로, sendTransaction 은 호출되지 않고 call() 함수가 뒤에서 실행됩니다. call() 함수는 필요한 데이타를 블럭체인에서 읽기만 합니다.
이번의 경우에도 call() 함수를 명시적으로 실행할 수도 있는데, 그렇게 되면 명령문은 다음과 같이 됩니다.
simpleStorage.get.call(function(e,r){console.log(r.toNumber());});
이로써 우리는 브라우저 콘솔 상에서 컨트랙트에 엑세스해서 블록체인상에 있는 변수값을 바꾸고 또 이를 불러 읽어오는 방법을 배웠습니다.
다음 편에서는 이 방법을 실제 웹페이지 상에서 포함시켜서 브라우저에서 직접 함수들을 실행할 수 있도록 사용자 인터페이스에 붙여 보는 작업을 해보겠습니다.
--------------------숙제----------------------
지난편에 각자 작성했던 컨트랙트를 이용해 원하는 숫자를 저장하고, 이를 다시 불러오는 명령어들을 실행해 본후,
블록체인 익스플로러상에 어떠한 변화가 생겼는지 아래처럼 링크를 달아주세요.
https://testnet.etherscan.io/address/0xc5244053eca508a11951400fc7af28738fd0ce77
최소 2개 이상의 트랜잭션이 보이도록 해주세요.
'Technology > 블록 체인' 카테고리의 다른 글
나도 dApp 개발해보자 강좌 - 5 (0) | 2018.04.05 |
---|---|
나도 dApp 개발해보자 강좌 - 3 (0) | 2018.04.03 |
나도 dApp 개발해보자 강좌 - 2 (0) | 2018.04.03 |
나도 dApp 개발해보자 강좌 - 1 (0) | 2018.04.03 |
이더리움 전용 브라우저 - MIST (0) | 2018.04.03 |