- https://sabarada.tistory.com/13
프로토콜 확인
url -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":[{see above}],"id":1}'
이 프로토콜에 맞춰 데이터를 전송해주면 됩니다. 잠깐 프로토콜을 설명 드리자면
jsonrpc : json-rpc 2.0을 사용하므로 2.0으로 고정 method : 통신에 사용할 기능(method), 여기서는 이더리움과의 통신을 위해 eth_call을 사용 params : 이더리움과의 통신에 사용되는 부가적인 데이터들입니다. 저희가 하고자 하는 것은 smart contract와의 상호작용이므로 필수로 사용해야할 파라미터는 아래와 같습니다. to : smart contract 주소 data : smart contract에 보내는 데이터
data Parameter 만들기
위의 프로토콜을 분석하여 저희는 어떤 데이터를 ehthereum으로 전송해야하는지 알았습니다. 그리고 data를 제외한 parameter는 알고 있습니다. 그렇다면 data파라미터는 어떻게 만들까요?
순서는 아래와 같습니다.
smart contract의 method를 통해 keccak256해쉬값을 알아낸다. 그 값중 4byte를 발췌한다. Input 파라미터가 있다면 각 타입에 맞게 그 값을 Hash 변환하여 붙여준다. 2번에서 작업한 Hash값과 3번에서 작업한 Hash값을 붙여준다. 위 과정을 통해 data Parameter를 제작할 수 있습니다. 그렇다면 예제를 한번 보겠습니다.
smart contract의 method를 통해 keccak256해쉬값을 알아낸다. 우리가 호출하고자 하는 메서드 리스트 입니다.
getPot() getNumber(uint256 num) getOwner() setPot(uint256 pot) 각각 해시펑션으로 변환 시켜줍니다. 파라미터가 있는 method는 형만 잡아줍니다. 즉 getNumber(uint256 num)의 경우 f(getNumber(uint256)) 이렇게 해주시면 됩니다.
f(getPot()) -> 0x403c9fa819dce134320f54269a156a8eaa90ceca7b487caad97587293b3fce3f f(getNumber(uint256)) -> 0xfc563658d25534cc7119f04ba172e8b25c6ff5cec285bf1f1335183f167c2f49 f(getOwner()) -> 0x893d20e82e7de4dc20ab2c04d17aa0699b89c86c9cd36ed761f937e212e0018a f(setPot(uint256)) -> 0x80b5b80c4cbf8b9faf689bd66aefa0d452dc3ce6f0b2f5f2479fb3ddd627f1b7 저는 변환을 이 사이트를 통해 처리했습니다.
그 값중 4byte를 발췌한다. 해시펑션을 통해 도출 된 값에서 4Byte를 가져옵니다.
getPot -> 0x403c9fa8 getNumber -> 0xfc563658 geOwner -> 0x893d20e8 setPot -> 0x80b5b80c 잘 따라오고 계실거라고 생각합니다.
Input 파라미터가 있다면 각 타입에 맞게 그 값을 Hash 변환하여 붙여준다. getNumber와 setPot의 경우 현재 uint256 형태의 파라미터를 사용하기 때문에 추가해 줄 필요가 있습니다. ethereum은 32Byte를 기본으로 합니다. keccak256 알고리즘의 결과값도 그렇고 Gas계산을 할때도 32Byte를 기준으로 합니다. Input Parameter를 Data로 만들때도 동일하게 사용한다.
위 예제에서 Uint256은 32Byte 해시값으로 나타내면 된다. 즉, 5를 Input값으로 제공하고 싶다면
0x0000000000000000000000000000000000000000000000000000000000000005
이렇게 추가해주면 된다.
2번에서 작업한 Hash값과 3번에서 작업한 Hash값을 붙여준다. 이제 만들어진 Hash값인 2번과 3번을 합치면 Data에 들어갈 값이 만들어진다.
getNumber와 setPot의 Input Parameter를 5라고 하면 아래와 같이 만들어진다.
getPot -> 0x403c9fa8 getNumber -> 0xfc5636580000000000000000000000000000000000000000000000000000000000000005 geOwner -> 0x893d20e8 setPot -> 0x80b5b80c0000000000000000000000000000000000000000000000000000000000000005 이렇게 만들어진 Data 값을 이용하면 된다.
POST 통신
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_call","params":["to" : smart contract Address, "data" : "0x403c9fa8"],"id":1}'
Event 확인
client에서 ehtereum을 통해 정보를 받을 수 있는 방법에는 2가지가 있습니다. 첫번째는 저번시간에 실습해 보았던 get을 이용하여 return값을 직접 받는 것이고 방법입니다. 그리고 두번째는 Event를 통해서 정보를 수신받는 방법입니다.
ethereum은 block에 transaction을 쓰면 해당 transaction에 대해서 Receipt(영수증)를 남깁니다. 이런 Receipt에는 여러정보가 포함되게 됩니다. 이렇게 포함되는 정보중에는 log가 있습니다. 우리는 이 Log를 통해 해당 이더리움으로 들어오는 정보를 알 수 있습니다.
이러한 log는 모니터링하면서 ethereum network로 들어오는 모든 Transaction을 확인할 수 도 있습니다. 대표적으로 etherscan이 그렇게 하고 있지요.
이런 Log에 포함되어 Ethereum Network로부터 정보를 받아 올 수 있는게 Event라고 생각하시면 됩니다.
Event 특징
Client는 event를 구독하고 정보를 가져올 수 있음 Event 메서드를 호출하면 Block Transaction의 log에 저장됨 로그들은 smart contract의 address와 연관이 깊음 해당 block에 접근할 수 있을 때까지 우리는 log를 활용가능 indexed 를 붙이면 topics로 처리가 됨, data로 가지 않고. indexed 된 데이터를 제외하고는 ABI-encoded 되어 data에 포함되어짐
eth_newFilter
이벤트 필터 오브젝트를 생성한다. 그리고 그 필터에 해당하는 Log가 생기면 알려준다. eth_getFilterChange를 통해 변화가 있었는지 주기적인 확인이 필요하다.
- Parameter
fromBlock: QUANTITY | TAG - (optional, default: “latest”) Integer block number, or “latest” for the last mined block or “pending”, “earliest” for not yet mined transactions. |
toBlock: QUANTITY | TAG - (optional, default: “latest”) Integer block number, or “latest” for the last mined block or “pending”, “earliest” for not yet mined transactions. |
address: DATA | Array, 20 Bytes - (optional) Contract address or a list of addresses from which logs should originate. |
topics: Array of DATA, - (optional) Array of 32 Bytes DATA topics. Topics are order-dependent. Each topic can also be an array of DATA with “or” options.
- Return
QUANTITY - A filter id.
- 만들 필터의 설정값으로 어떤 블럭부터 볼껀지 (fromBlock), 어디블럭까지 볼것인지(toBlock), 어떤 contract를 볼것인지(address), 어떤 이벤트를 볼것인지(topics)를 지정해 주면 사용할 수 있는 filterid를 반환하는 것을 알 수 있습니다. filterId는 어떤 blockchain network를 사용하느냐에 따라서 값의 형식이 다릅니다.
ex) geth는 Hash값을 가지지만 ganache는 0 숫자부터 올라갑니다.
eth_getfilterchanges
filter를 위한 polliing method. eth_getfilterchanges는 마지막으로 가져온 log 이후로 발생한 log를 가져온다. eth_newfilter를 통해 topics에 대한 filter를 새로 만든다. eht_getfilterchanges를 통해 만들어진 filter에 걸린 event를 가져온다.
- Parameter
QUANTITY - the filter id.
- return
Array - Array of log objects, or an empty array if nothing has changed since last poll.
removed: TAG - true when the log was removed, due to a chain reorganization. false if its a valid log.
logIndex: QUANTITY - integer of the log index position in the block. null when its pending log.
transactionIndex: QUANTITY - integer of the transactions index position log was created from. null when its pending log.
transactionHash: DATA, 32 Bytes - hash of the transactions this log was created from. null when its pending log.
blockHash: DATA, 32 Bytes - hash of the block where this log was in. null when its pending. null when its pending log.
blockNumber: QUANTITY - the block number where this log was in. null when its pending. null when its pending log.
address: DATA, 20 Bytes - address from which this log originated.
data: DATA - contains the non-indexed arguments of the log.
topics: Array of DATA - Array of 0 to 4 32 Bytes DATA of indexed log arguments. (In solidity: The first topic is the hash of the signature of the event (e.g. Deposit(address,bytes32,uint256)), except you declared the event with the anonymous specifier.)
eth_getfilterchages는 filterId를 이용하여 해당 filter에 걸린 Event에 대한 Log를 출력해 줍니다. 위의 return값 중에서 많이 다루게 되는것은 indexed Data의 값이 들어있는 topics와 실제 데이터가 있는 data정도 입니다.
Post 통신 확인
테스트는 ganache-cli를 통해서 아래와 같이 진행합니다.
smart contract를 배포한다. eth_newFilter로 FilterID를 가져온다. eth_getfilterchanage를 통해 event를 확인해본다. eth_sendtransaction을 통해 event가 들어있는 function을 실행시켜본다. eth_getfilterchagne를 통해 event를 확인한다.
event Filter 생성
curl -X POST --data '{"jsonrpc" : "2.0", "method" : "eth_newFilter", "params" :[{"topics": ["0x29AF742A7D5900C031FDC39A763AFB988BDE5C738356676D8C5CF9D76AEECED7"]}],"id" : 73}' localhost:8545 -H "content-type:application/json"
# {"jsonrpc":"2.0","id":73,"result":"0x11608b118ce7dea85e9fa15c72b165bc"}
- 0x2라는 filterId가 반환되었습니다. 이것은 ganache에서 주는 것이며 geth등 다른 ehtereum network는 다릅니다.
이렇게 만든 필터를 이용하여 log를 확인해보도록 하겠습니다.
Tx 발생
curl -X POST --data '{"jsonrpc":"2.0","method":"eth_sendTransaction","params":[{"from":"0x7d324dbc8fc704881d302da3b264e2243007bdba","to":"0xb763ab5a54892fcbd0a9e49018c2300b1387926a","data":"0x80b5b80c0000000000000000000000000000000000000000000000000000000000000005"}],"id":0,"responseType":"org.blockchain.domain.dto.EthResultVO"}' -H "content-type:application/json" localhost:8545
# {"jsonrpc":"2.0","id":0,"result":"0x6677d8dbd05df5e464e8b01b119073069b4755bca86c803e4000bd4cbbbb6a5b"}
로그 확인
curl -X POST --data '{"jsonrpc" : "2.0", "method" : "eth_getFilterChanges", "params" :["0x11608b118ce7dea85e9fa15c72b165bc"],"id" : 74}' localhost:8545 -H "content-Type:application/json"
# {"jsonrpc":"2.0","id":74,"result":[{"address":"0xb763ab5a54892fcbd0a9e49018c2300b1387926a","topics":["0x29af742a7d5900c031fdc39a763afb988bde5c738356676d8c5cf9d76aeeced7"],"data":"0x0000000000000000000000000000000000000000000000000000000000000005","blockNumber":"0x1609","transactionHash":"0x6677d8dbd05df5e464e8b01b119073069b4755bca86c803e4000bd4cbbbb6a5b","transactionIndex":"0x0","blockHash":"0x1751283f79b87486ec53572dc29e973822555fce7622b8d086beb1dcf1c0fc51","logIndex":"0x0","removed":false}]}
- 발생된 로그가 남음을 확인했습니다. 우리는 이 정보를 모니터링하고 있다가 여러 행위를 할 수 있음을 알 수 있었습니다. 정보는 result#data를 보시면 확인하실 수 있습니다. 만약 indexed되어있는 데이터라면 topic에서 확인할 수 있습니다.