hello 라는 이름의 디렉토리를 contracts directory 에 생성하자.
cd CONTRACTS_DIR
mkdir hello
cd hello
hello.cpp 를 생성하고 에디터로 열자.
touch hello.cpp
필요한 라이브러리를 이 파일에 include 한다.
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
코드를 간결하게 해줄 eosio 네임스페이스를 contract 에 추가한다.
using namespace eosio;
- eosiolib/eosio.hpp 가 EOSIO C 와 C++ API 를 당신의 contract 스코프에 로드한다.
표준 C++11 클래스를 생성한다. 이 contract class 는 eosio::contract 를 확장해야한다.
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
using namespace eosio;
class hello : public contract {};
비어있는 contract 는 좋지 않으니, public 접근 지정자와 using 선언을 추가하자. 이 using 선언은 좀 더 간결한 코드를 쓸 수 있도록 도움을 줄것이다.
이제 contract 는 어떤 작업을 하도록 구성한다. hello world 의 정신을 받아 “name” 파라메터를 수신하고, 파라메터를 출력하는 작업을 해보자.
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
using namespace eosio;
class hello : public contract {
public:
using contract::contract;
[[eosio::action]]
void hi( name user ) {
print( "Hello, ", name{user});
}
};
위의 동작은 user 라는 이름의 파라메터를 name type 으로 전달 받는다.
EOSIO 는 몇개의 typedef 를 선언하고 있는데, 이 중에 흔한 하나가 바로 이 name
이다.
eosio::print
를 사용함으로써, 문자열을 user 파라미터와 붙여 출력한다.
괄호를 이용한 초기화 name{user}
는 user
파라메터가 출력될 수 있도록 해준다.
eosio.cdt 의 abi 생성자는 atttrubite 없이는 hi() 의 동작을 알 수 없다. c++11 스타일의 attribute 를 action 의 상위에 추가하여 abi generator 가 신뢰 할 수 있는 출력을 할 수 있도록 한다.
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
using namespace eosio;
class hello : public contract {
public:
using contract::contract;
[[eosio::action]]
void hi( name user ) {
print( "Hello, ", user);
}
};
EOSIO_DISPATCH( hello, (hi))
마지막으로, EOSIO_DISPATCH 매크로를 추가하여 hello contract 의 dispatch 액션을 처리하도록 한다.
이제 web assembly 를 통해 컴파일해보자.
eosio-cpp -o hello.wasm hello.cpp --abigen
contract 가 배포되면, 계정으로 배포되어 이 계정이 contract 의 인터페이스가 된다.
이 튜토리얼의 이전에 언급하였듯, 같은 public key 를 모든계정에서 사용하여 간단히 할 수 있다.
cleos wallet keys
이 contract 를 위한 계정을 생성하기 위해 cleos create account 를 사용한다.
cleos create account eosio hello YOUR_PUBLIC_KEY -p eosio@active
컴파일된 wasm 을 cleos set contract 를 통해 블록체인으로 broadcast 한다.
cleos set contract hello CONTRACTS_DIR/hello -p hello@active
훌륭하다! 이제 contract 가 설정 되었고, action 을 push 해보자.
cleos push action hello hi '["bob"]' -p bob@active
executed transaction: 28d92256c8ffd8b0255be324e4596b7c745f50f85722d0c4400471bc184b9a16 244 bytes 1000 cycles
# hello.code <= hello.code::hi {"user":"bob"}
>> Hello, bob
예상했던대로 hello, bob 이 출력된다.
이번 경우, “alice” 가 권한이 있고 user
는 단순한 argument 이다. contract 를 수정하여 권한이 있는 유저가 “hi” 를 받을 유저와 동일한 경우에만 동작하도록 해보자.
require_auth
메소드를 사용한다.
이 메소드는 name
을 파라메터로 받아서 action 을 수행하는 사용자가 제공된 파라메터와 일치하는지 확인한다.
void hi( name user ) {
require_auth( user );
print( "Hello, ", name{user} );
}
다시 컴파일 한다.
eosio-cpp -o hello.wasm hello.cpp --abigen
그리고 update 한다.
cleos set contract hello CONTRACTS_DIR/hello -p hello@active
실행하되, 이번에는 권한이 일치 않도록 한다.
cleos push action hello hi '["bob"]' -p alice@active
Error 3090004: Missing required authority
Ensure that you have the related authority inside your transaction!;
If you are currently using 'cleos push action' command, try to add the [relevant](**http://google.com**) authority using -p option.
우리의 contract 수정으로, 제공된 name user
가 승인 유저와 동일한지 확인한다.
다시 실행하되, 이번엔 alice account 의 권한으로 실행해보자.
cleos push action hello hi '["alice"]' -p alice@active
executed transaction: 235bd766c2097f4a698cfb948eb2e709532df8d18458b92c9c6aae74ed8e4518 244 bytes 1000 cycles
# hello <= hello::hi {"user":"alice"}
>> Hello, alice