Getting started
Introduction#
This tutorial is mainly to guide users to create a simple HelloWorld smart contract using wasm language on PlatON, compile, deploy, and call this contract through platon-truffle.If you want to use a richer API.
Platon-truffle Introduction#
Platon-truffle is a tool provided by PlatON that can compile, deploy, and invoke smart contracts locally. For specific installation and usage manuals, refer to:
- Platon-truffle develop toolsspecific installation
- Platon-truffle develop toolsusage manuals
Create HelloWorld Contract#
#include <platon/platon.hpp>#include <string>using namespace platon;
class message { public: std::string head; PLATON_SERIALIZE(message, (head))};
class my_message : public message { public: std::string body; std::string end; PLATON_SERIALIZE_DERIVED(my_message, message, (body)(end))};
CONTRACT HelloWorld : public platon::Contract{ public: ACTION void init(const my_message &one_message){ info.self().push_back(one_message); }
ACTION void add_message(const my_message &one_message){ info.self().push_back(one_message); }
CONST uint8_t get_message_size(){ return info.self().size(); }
CONST std::string get_message_body(const uint8_t index){ return info.self()[index].body; }
private: platon::StorageType<"myvector"_n, std::vector<my_message>> info;};
PLATON_DISPATCH(HelloWorld, (init)(add_message)(get_message_size)(get_message_body))
Contract Files Description:
Each contract file has only one contract class. The contract class is decorated with Contract. It must be publicly inherited from platon :: Contract and must have an init function.
ACTION and CONST qualified member functions represent callable functions, and such member functions cannot be overloaded. The ACTION function will modify the data on the chain. The CONST function just queries the attributes and does not modify the data on the chain.
The type in the callable function parameter list is a custom type. In this type definition, you need to add the PLATON_SERIALIZE macro to declare the serialization function. This type inherits from other types. You need to add the PLATON_SERIALIZE_DERIVED macro to declare the serialization function.
Callable functions can only be called externally if the unified entry function is defined in the PLATON_DISPATCH macro.
At present, platon will persistently store member variables of the contract class. The member variables must be of type platon :: StorageType. The first parameter string of the platon :: StorageType template is followed by _n, and the string must be .12345abcdefghijklmnopqrstuvwxyz. 32 characters Characters. The second parameter is the concrete type of the actual storage. Member function modification member variables need to obtain an instance of a specific type through the self () function, and then execute the corresponding instance function.
The second parameter type of the platon :: StorageType template is a custom type. A PLATON_SERIALIZE macro must be added to this type definition to declare a serialization function. This type inherits from other types. A PLATON_SERIALIZE_DERIVED macro must be added to declare a serialization function.
Compile HelloWorld Contract#
Step1. Creat new directory for HelloWorld project
mkdir HelloWorld && cd HelloWorld- The following commands are performed in the HelloWorld directory without special instructions
Step2. Init project
platon-truffle initAfter the command is executed, project directory structure is as follows:
contracts/wasm contract directorymigrations/depoly file directorytest/test script directorytruffle-config.jsplaton-truffle config
Step3. Move HelloWorld contract compiled in to HelloWorld/contracts/
ls contracts/- HelloWorld.cpp
Step4. Modify the platon-truffle configuration file truffle-config.js and add the compiled wasm contract version number
vim truffle-config.jsTruffle-config.js content is as follows:
compilers: { wasm: { version: "1.0.0" }}Step5. Compile contract
platon-truffle compileAfter the command is executed, project directory structure is as follows:
build/wasm contract directory after compiledbuild/contracts/HelloWorld.abi.jsonHelloWorld contract compiled abi interface filebuild/contracts/HelloWorld.wasmHelloWorld contract compiled binary
Deploly HelloWorld Contract#
Step1. Setting config information for blockchain in truffle-config.js
vim truffle-config.jsSet blockchain network info
networks: { development: { host: "10.1.1.6", // blockchain server address port: 8806, // server port network_id: "*", // Any network (default: none) from: "lat1wxadw8yzr6qxdw5yl3f2surp6ue6f03e07kcqc", gas: 999999, gasPrice: 1000000000, },}step2. Unlock wallet account
Enter the platon-truffle console
platon-truffle consoleImport the private key (you can skip this step if you have already imported it)
web3.platon.personal.importRawKey("Your wallet private key","Your wallet password");Successful import will see the address corresponding to the private key as follows:
'lat1wxadw8yzr6qxdw5yl3f2surp6ue6f03e07kcqc'Unlock wallet account
web3.platon.personal.unlockAccount('Your wallet address','Your wallet password',999999);After unlocking successfully, you will see the following information:
tureStep3. Deploy contract
platon-truffle deploy --wasm --contract-name HelloWorld --params '[[["1"], "2", "3"]]'HelloWorlddeployed contractparamsparameters of contract init function
If deploying successfully,you will see log info as follows:
receipt: { blockHash: '0x266733b693ba650315a59c34e72804c06ca3e27fab145625797bd42259b572c5', blockNumber: 70441, contractAddress: 'lat1nk4errnjlulaz5y57xt4djkx3h4jjl7yy9dzqn', cumulativeGasUsed: 291314, from: 'lat1wxadw8yzr6qxdw5yl3f2surp6ue6f03e07kcqc', gasUsed: 291314, logs: [], logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', status: true, to: null, transactionHash: '0x60946ebf0ccddc76a0234353435de73e7901888227fb2f03922fb0ce265a4e9d', transactionIndex: 0 } contract HelloWorld deployed successfully======================
> transactionHash: 0x60946ebf0ccddc76a0234353435de73e7901888227fb2f03922fb0ce265a4e9d > contract address: lat1nk4errnjlulaz5y57xt4djkx3h4jjl7yy9dzqn > block number: 70441 > block timestamp: 1583247148341 > account: lat1wxadw8yzr6qxdw5yl3f2surp6ue6f03e07kcqc > balance: 3533694129556768659166595001485837031654967793751237866225582808584074296 > gas limit: 100000000 > gas used: 291314 > gas price: 0.000000050000000004 LAT > total cost: 0.014565700001165256 LATCall HelloWorld Contract#
Step1. Enter the platon-truffle console
platon-truffle console- You can execute command in platon-truffle console
Step2. Create contract object
var abi = [{"baseclass":[],"fields":[{"name":"head","type":"string"}],"name":"message","type":"struct"},{"baseclass":["message"],"fields":[{"name":"body","type":"string"},{"name":"end","type":"string"}],"name":"my_message","type":"struct"},{"constant":false,"input":[{"name":"one_message","type":"my_message"}],"name":"init","output":"void","type":"Action"},{"constant":false,"input":[{"name":"one_message","type":"my_message"}],"name":"add_message","output":"void","type":"Action"},{"constant":true,"input":[],"name":"get_message_size","output":"uint8","type":"Action"},{"constant":true,"input":[{"name":"index","type":"uint8"}],"name":"get_message_body","output":"string","type":"Action"}];var contractAddr = 'lat1nk4errnjlulaz5y57xt4djkx3h4jjl7yy9dzqn';
var helloworld = new web3.platon.Contract(abi,contractAddr,{vmType: 1 }); Description:
abithe interface provided by the contract to external calls,the abi in the file compiled :HelloWorld/build/contracts/HelloWorld.jsoncontractAddrcontract addresshelloWorldcontract object created
Step3. Call contract
helloworld.methods.add_message('[[["5"], "6", "7"]]').send({ from: 'lat1wxadw8yzr6qxdw5yl3f2surp6ue6f03e07kcqc',gas: 999999}).on('receipt', function(receipt) { console.log(receipt);}).on('error', console.error);Description:
helloWorldthe contract object createdmethodsspecify the call methodadd_messagemethod in the HelloWorld contract with a custom my_message inputfromcaller's wallet addressonlisten to the result of the contract method executed. If failed, it will print the error info. If succeeded, the console will print the receipt as belows:
{ blockHash: '0x669c7b8cb938cc30845e08dc4ceda08f2e17207c267ade97dc5458b445405736', blockNumber: 74665, contractAddress: null, cumulativeGasUsed: 108549, from: 'lat1wxadw8yzr6qxdw5yl3f2surp6ue6f03e07kcqc', gasUsed: 108549, logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', status: true, to: 'lat1nk4errnjlulaz5y57xt4djkx3h4jjl7yy9dzqn', transactionHash: '0x2b5e590df7e70ad428b1ccb06bda5dcce47f84c4d981c2fb475aca9ec9d0000a', transactionIndex: 0, events: {} }{ blockHash: '0x669c7b8cb938cc30845e08dc4ceda08f2e17207c267ade97dc5458b445405736', blockNumber: 74665, contractAddress: null, cumulativeGasUsed: 108549, from: 'lat1wxadw8yzr6qxdw5yl3f2surp6ue6f03e07kcqc', gasUsed: 108549, logsBloom: '0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000', status: true, to: 'lat1nk4errnjlulaz5y57xt4djkx3h4jjl7yy9dzqn', transactionHash: '0x2b5e590df7e70ad428b1ccb06bda5dcce47f84c4d981c2fb475aca9ec9d0000a', transactionIndex: 0, events: {} }Step4. Query contract
helloworld.methods.get_message_body(0).call()Description:
helloWorldthe contract object createdmethodsspecify the call methodget_message_bodymethod in the HelloWorld contract, which has an input parameter of type intcallspecify the query method
FAQ#
About Compile#
How to use
platon-cppfor compile multiplecppfiles?platon-cpp ./test.cpp ./test1.cppOnly allowing exists one contract class.
How to specified output directory and filename when use
platon-cppto compile contract?Use
-oflag, and must be specified output directory and filename at the same time.platon-cpp ./test.cpp -o ./out/test.wasmWhat data types does ABI support?
Generate ABI supported types and conversion rules as follows:
| Type | ABI |
|---|---|
| bool | bool |
| uint8_t | uint8 |
| uint16_t | uint16 |
| uint32_t | uint32 |
| uint64_t | uint64 |
| int8_t | int8 |
| int16_t | int16 |
| int32_t | int32 |
| int64_t | int64 |
| bytes | uint8[] |
| std::string | string |
| std::vector<T> | T[] |
| std::array[T, N] | T[N] |
| std::pair<T, U> | pair<T, U> |
| std::set<T> | set<T> |
| std::map<T, V> | map<T, V> |
| std::list<T> | list<T> |
| FixedHash<N> | FixedHash<N> |
| u128 | uint128 |
| bigint | uint128 |
About Contract#
How to output contract debug logs in the
platonprocess?Add
#undef NDEBUGat the first line of contract codes, and must before header file included.#undef NDEBUG #include <platon/platon.hpp> //...platonstartup command specifies log level 4 and enable debug flag../platon --debug --verbosity 4 ...
How to write a contract can effectively reduce Gas consumption?
Use reference arguments
void test(const std::string& str) {}Return rvalue reference
std::vector<std::string>&& test() { std::vector<std::string> v; // ... return std::move(v);}- Try not to apply for large blocks of memory
What should I pay attention to when using
StorageType?- Should be initialized in
init()CONTRAT Hello : public Contract { public: ACTION void init() { s_.self() = "test"; } private: StorageType<"test"_n, std::string> s_; };
- It is recommended to use a specialized type of `StorageType` directly + Uint8 + Int8 + Uint16 + Int16 + Uint + Int + Uint64 + Int64 + String + Vector + Set + Map + Array + Tuple- Should be initialized in
What is the difference between
StorageTypeandplaton::db::Map,platon::db::Array?From the underlying storage level, the implementation of
StorageTypeis serialized as a whole, and then stored in the database.platon::db::Mapandplaton::db::Arrayserialize each element of the container as K/V is stored to the database. For large-scale data,platon::db::Mapandplaton::db::Arrayperform better.When implementing a contract, a suitable storage structure should be selected based on the size of the data.
RLP serialization/deserialization What C++ standard library types are supported?
The following C ++ standard library types are supported:
- std::string
- std::vector
- std::map
- std::list
- std::array
- std::set
- std::pair
- std::tuple
How do custom types support RLP serialization/deserialization?
- Macro
PLATON_SERIALIZEfor common types
struct Base { int a; std::string b; PLATON_SERIALIZE(Base, (a)(b)); };- The derived class uses the macro
PLATON_SERIALIZE_DERIVED, and the base class also uses the macroPLATON_SERIALIZE
struct Derived : public Base { int c; int d; PLATON_SERIALIZE_DERIVED(Derived, Base, (c)(d));};- Macro