README.md 17.3 KB
Newer Older
N
Nathan Hourt 已提交
1 2
# Eos

peterwillcn's avatar
peterwillcn 已提交
3 4
[![Build Status](https://travis-ci.org/EOSIO/eos.svg?branch=master)](https://travis-ci.org/EOSIO/eos)

5
Welcome to the EOS.IO source code repository!
N
Nathan Hourt 已提交
6

7 8 9 10
# Table of contents

1. [Getting Started](#gettingstarted)
2. [Setting up a buid/development environment](#setup)
11
	1. [Clean install Ubuntu 16.10](#ubuntu)
12 13 14 15 16 17 18 19 20 21 22 23 24
	2. [macOS Sierra 10.12.6](#macos)
3. [Building and running a node](#runanode)
	1. [Getting the code](#getcode)
	2. [Building from source code](#build)
	3. [Creating and launching a single-node testnet](#singlenode)
4. [Accounts and smart contracts](#accountssmartcontracts)
	1. [Example smart contracts](#smartcontractexample)
	2. [Setting up a wallet and importing account key](#walletimport)
	3. [Creating accounts for your smart contracts](#createaccounts)
	4. [Upload sample contract to blockchain](#uploadsmartcontract)
	5. [Push a message to a sample contract](#pushamessage)
	6. [Reading Currency Contract Balance](#readingcontract)
5. [Running local testnet](#localtestnet)
S
Serg Metelin 已提交
25 26
6. [Doxygen documentation](#doxygen)
7. [Running EOS in Docker](#docker)
27 28
	1. [Run contract in docker example](#dockercontract)

S
Serg Metelin 已提交
29 30
<a name="gettingstarted"></a>
## Getting Started
31
The following instructions overview the process of getting the software, building it, running a simple test network that produces blocks, account creation and uploading a sample contract to the blockchain.
N
Nathan Hourt 已提交
32

S
Serg Metelin 已提交
33 34
<a name="setup"></a>
## Setting up a build/development environment
35
This project is written primarily in C++14 and uses CMake as its build system. An up-to-date Clang and the latest version of CMake is recommended.
N
Nathan Hourt 已提交
36

37
Dependencies:
S
Serg Metelin 已提交
38

39
* Clang 4.0.0
40 41
* CMake 3.5.1
* Boost 1.64
S
Serg Metelin 已提交
42
* OpenSSL
43 44
* LLVM 4.0
* [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git)
S
Serg Metelin 已提交
45
* [binaryen](https://github.com/WebAssembly/binaryen.git)
46

S
Serg Metelin 已提交
47 48
<a name="ubuntu"></a>
### Clean install Ubuntu 16.10 
49 50 51

Install the development toolkit:

52
```commandline
53
sudo apt-get update
54 55 56
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
sudo apt-get install clang-4.0 lldb-4.0 cmake make \
                     libbz2-dev libssl-dev libgmp3-dev \
57
                     autotools-dev build-essential \
58
                     libbz2-dev libicu-dev python-dev \
59 60 61 62 63
                     autoconf libtool git
```

Install Boost 1.64:

64
```commandline
65 66 67 68
cd ~
wget -c 'https://sourceforge.net/projects/boost/files/boost/1.64.0/boost_1_64_0.tar.bz2/download' -O boost_1.64.0.tar.bz2
tar xjf boost_1.64.0.tar.bz2
cd boost_1_64_0/
S
Serg Metelin 已提交
69 70
echo "export BOOST_ROOT=$HOME/opt/boost_1_64_0" >> ~/.bash_profile
source ~/.bash_profile
71 72
./bootstrap.sh "--prefix=$BOOST_ROOT"
./b2 install
S
Serg Metelin 已提交
73
source ~/.bash_profile
74 75
```

76 77 78 79 80 81 82 83 84 85 86 87
Install [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git):
        
```commandline
cd ~
git clone https://github.com/cryptonomex/secp256k1-zkp.git
cd secp256k1-zkp
./autogen.sh
./configure
make
sudo make install
```

88
To use the WASM compiler, EOS has an external dependency on [binaryen](https://github.com/WebAssembly/binaryen.git):
S
Serg Metelin 已提交
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104

```commandline
cd ~
git clone https://github.com/WebAssembly/binaryen.git
cd ~/binaryen
git checkout tags/1.37.14
cmake . && make

```

Add BINARYEN_ROOT to your .bash_profile:

```commandline
echo "export BINARYEN_ROOT=~/binaryen" >> ~/.bash_profile
source ~/.bash_profile
```
D
Daniel Larimer 已提交
105

S
Serg Metelin 已提交
106
By default LLVM and clang do not include the WASM build target, so you will have to build it yourself:
107

108 109 110 111 112 113 114 115 116 117 118
```commandline
mkdir  ~/wasm-compiler
cd ~/wasm-compiler
git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git
cd llvm/tools
git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git
cd ..
mkdir build
cd build
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=.. -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../
make -j4 install
119
```
120

S
Serg Metelin 已提交
121 122
<a name="macos"></a>
### macOS Sierra 10.12.6 
123 124

macOS additional Dependencies:
S
Serg Metelin 已提交
125

126 127 128 129 130 131 132
* Brew
* Newest XCode

Upgrade your XCode to the newest version:

```commandline
xcode-select --install
133 134
```

135
Install homebrew:
136 137

```commandline
138 139 140 141 142 143 144 145
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
```

Install the dependencies:

```commandline
brew update
brew install git automake libtool boost openssl llvm
146
```
147

148 149 150 151 152 153 154 155 156 157
Install [secp256k1-zkp (Cryptonomex branch)](https://github.com/cryptonomex/secp256k1-zkp.git):
        
```commandline
cd ~
git clone https://github.com/cryptonomex/secp256k1-zkp.git
cd secp256k1-zkp
./autogen.sh
./configure
make
sudo make install
158
```
159

S
Serg Metelin 已提交
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
Install [binaryen v1.37.14](https://github.com/WebAssembly/binaryen.git):

```commandline
cd ~
git clone https://github.com/WebAssembly/binaryen.git
cd ~/binaryen
git checkout tags/1.37.14
cmake . && make
```

Add BINARYEN_ROOT to your .bash_profile:

```commandline
echo "export BINARYEN_ROOT=~/binaryen" >> ~/.bash_profile
source ~/.bash_profile
```


178 179 180
Build LLVM and clang for WASM:

```commandline
181 182 183 184 185 186 187 188 189 190 191 192
mkdir  ~/wasm-compiler
cd ~/wasm-compiler
git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/llvm.git
cd llvm/tools
git clone --depth 1 --single-branch --branch release_40 https://github.com/llvm-mirror/clang.git
cd ..
mkdir build
cd build
cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX=.. -DLLVM_TARGETS_TO_BUILD= -DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly -DCMAKE_BUILD_TYPE=Release ../
make -j4 install
```

193 194 195 196 197
Add WASM_LLVM_CONFIG and LLVM_DIR to your .bash_profile:

```commandline
echo "export WASM_LLVM_CONFIG=~/wasm-compiler/llvm/bin/llvm-config" >> ~/.bash_profile
echo "export LLVM_DIR=/usr/local/Cellar/llvm/4.0.1/lib/cmake/llvm" >> ~/.bash_profile
S
Serg Metelin 已提交
198
source ~/.bash_profile
199 200
```

S
Serg Metelin 已提交
201 202
<a name="runanode"></a>
## Building and running a node 
S
Serg Metelin 已提交
203

S
Serg Metelin 已提交
204 205
<a name="getcode"></a>
### Getting the code 
S
Serg Metelin 已提交
206

207
To download all of the code, download EOS source code and a recursion or two of submodules. The easiest way to get all of this is to do a recursive clone:
N
Nathan Hourt 已提交
208 209 210 211 212 213 214

`git clone https://github.com/eosio/eos --recursive`

If a repo is cloned without the `--recursive` flag, the submodules can be retrieved after the fact by running this command from within the repo:

`git submodule update --init --recursive`

S
Serg Metelin 已提交
215 216
<a name="build"></a>
### Building from source code 
217

218 219
The *WASM_LLVM_CONFIG* environment variable is used to find our recently built WASM compiler.
This is needed to compile the example contracts inside `eos/contracts` folder and their respective tests.
220

221
```commandline
S
Serg Metelin 已提交
222
cd ~
223
git clone https://github.com/eosio/eos --recursive
S
Serg Metelin 已提交
224 225
mkdir -p ~/eos/build && cd ~/eos/build
cmake -DBINARYEN_BIN=~/binaryen/bin ..
226 227 228 229
make -j4
```

Out-of-source builds are also supported. To override clang's default choice in compiler, add these flags to the CMake command:
N
Nathan Hourt 已提交
230 231 232 233 234

`-DCMAKE_CXX_COMPILER=/path/to/c++ -DCMAKE_C_COMPILER=/path/to/cc`

For a debug build, add `-DCMAKE_BUILD_TYPE=Debug`. Other common build types include `Release` and `RelWithDebInfo`.

235
To run the test suite after building, run the `chain_test` executable in the `tests` folder.
N
Nathan Hourt 已提交
236

S
Serg Metelin 已提交
237 238 239 240 241
EOS comes with a number of programs you can find in `~/eos/build/programs`. They are listed below:

* eosd - server-side blockchain node component
* eosc - command line interface to interact with the blockchain
* eos-walletd - EOS wallet
S
Serg Metelin 已提交
242
* launcher - application for nodes network composing and deployment; [more on launcher](https://github.com/EOSIO/eos/blob/master/testnet.md)
S
Serg Metelin 已提交
243

S
Serg Metelin 已提交
244 245
<a name="singlenode"></a>
### Creating and launching a single-node testnet 
S
Serg Metelin 已提交
246

247
After successfully building the project, the `eosd` binary should be present in the `programs/eosd` directory. Go ahead and run `eosd` -- it will probably exit with an error, but if not, close it immediately with `Ctrl-C`. Note that `eosd` created a directory named `data-dir` containing the default configuration (`config.ini`) and some other internals. This default data storage path can be overridden by passing `--data-dir /path/to/data` to `eosd`.
N
Nathan Hourt 已提交
248

N
Nathan Hourt 已提交
249
Edit the `config.ini` file, adding the following settings to the defaults already in place:
N
Nathan Hourt 已提交
250 251

```
N
Nathan Hourt 已提交
252 253 254 255 256
# Load the testnet genesis state, which creates some initial block producers with the default key
genesis-json = /path/to/eos/source/genesis.json
# Enable production on a stale chain, since a single-node test chain is pretty much always stale
enable-stale-production = true
# Enable block production with the testnet producers
257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
producer-name = inita
producer-name = initb
producer-name = initc
producer-name = initd
producer-name = inite
producer-name = initf
producer-name = initg
producer-name = inith
producer-name = initi
producer-name = initj
producer-name = initk
producer-name = initl
producer-name = initm
producer-name = initn
producer-name = inito
producer-name = initp
producer-name = initq
producer-name = initr
producer-name = inits
producer-name = initt
producer-name = initu
S
Serg Metelin 已提交
278
# Load the block producer plugin, so you can produce blocks
N
Nathan Hourt 已提交
279
plugin = eos::producer_plugin
S
Serg Metelin 已提交
280
# Wallet plugin
281
plugin = eos::wallet_api_plugin
S
Serg Metelin 已提交
282
# As well as API and HTTP plugins
283 284
plugin = eos::chain_api_plugin
plugin = eos::http_plugin
N
Nathan Hourt 已提交
285 286
```

J
Joel Smith 已提交
287
Now it should be possible to run `eosd` and see it begin producing blocks. At present, the P2P code is not implemented, so only single-node configurations are possible. When the P2P networking is implemented, these instructions will be updated to show how to create an example multi-node testnet.
peterwillcn's avatar
peterwillcn 已提交
288

S
Serg Metelin 已提交
289 290 291 292 293 294 295 296 297 298 299 300 301 302
When running `eosd` you should get log messages similar to below. It means the blocks are successfully produced.

```
1575001ms thread-0   chain_controller.cpp:235      _push_block          ] initm #1 @2017-09-04T04:26:15  | 0 trx, 0 pending, exectime_ms=0
1575001ms thread-0   producer_plugin.cpp:207       block_production_loo ] initm generated block #1 @ 2017-09-04T04:26:15 with 0 trxs  0 pending
1578001ms thread-0   chain_controller.cpp:235      _push_block          ] initc #2 @2017-09-04T04:26:18  | 0 trx, 0 pending, exectime_ms=0
1578001ms thread-0   producer_plugin.cpp:207       block_production_loo ] initc generated block #2 @ 2017-09-04T04:26:18 with 0 trxs  0 pending
1581001ms thread-0   chain_controller.cpp:235      _push_block          ] initd #3 @2017-09-04T04:26:21  | 0 trx, 0 pending, exectime_ms=0
1581001ms thread-0   producer_plugin.cpp:207       block_production_loo ] initd generated block #3 @ 2017-09-04T04:26:21 with 0 trxs  0 pending
1584000ms thread-0   chain_controller.cpp:235      _push_block          ] inite #4 @2017-09-04T04:26:24  | 0 trx, 0 pending, exectime_ms=0
1584000ms thread-0   producer_plugin.cpp:207       block_production_loo ] inite generated block #4 @ 2017-09-04T04:26:24 with 0 trxs  0 pending
1587000ms thread-0   chain_controller.cpp:235      _push_block          ] initf #5 @2017-09-04T04:26:27  | 0 trx, 0 pending, exectime_ms=0
```

S
Serg Metelin 已提交
303 304
<a name="accountssmartcontracts"></a>
## Accounts and smart contracts 
S
Serg Metelin 已提交
305

306
EOS comes with example contracts that can be uploaded and run for testing purposes. To upload and test them, follow the steps below.
S
Serg Metelin 已提交
307

S
Serg Metelin 已提交
308 309
<a name="smartcontractexample"></a>
### Example smart contracts 
310 311 312

To publish sample smart contracts you need to create accounts for them.

S
Serg Metelin 已提交
313 314 315 316
Run the node:

```commandline
cd ~/eos/build/programs/eosd/
S
Serg Metelin 已提交
317
./eosd
S
Serg Metelin 已提交
318
```
319

S
Serg Metelin 已提交
320 321
<a name="walletimport"></a>
### Setting up a wallet and importing account key 
S
Serg Metelin 已提交
322

323
Before running API commands you need to import the private key of an account you will be authorizing the transactions under into the EOS wallet.
S
Serg Metelin 已提交
324

325
As you've previously added `plugin = eos::wallet_api_plugin` into `config.ini`, EOS wallet will be running as a part of `eosd` process.
S
Serg Metelin 已提交
326

327
For testing purposes you can use a pre-created account `inita` from the `genesis.json` file.
S
Serg Metelin 已提交
328 329 330 331 332

To login you need to run a command importing an active (not owner!) private key from `inita` account (you can find it in `~/eos/build/programs/eosd/data-dir/config.ini`) to the wallet.

```commandline
cd ~/eos/build/programs/eosc/
333 334
./eosc wallet create # Outputs a password that you need to save to be able to lock/unlock the wallet
./eosc wallet import 5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3
S
Serg Metelin 已提交
335 336
```

337
Now you can issue API commands under `inita` authority.
S
Serg Metelin 已提交
338

S
Serg Metelin 已提交
339 340
<a name="createaccounts"></a>
### Creating accounts for your smart contracts 
S
Serg Metelin 已提交
341

342
First, generate public/private key pairs for the `owner_key` and `active_key`. You will need them to create an account:
343 344 345 346 347 348 349 350 351 352 353 354 355 356

```commandline
cd ~/eos/build/programs/eosc/
./eosc create key
./eosc create key
```

You will get two pairs of a public and private key:

```
Private key: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
Public key:  XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

357
**Warning:**
358 359 360 361 362
Save the values for future reference.

Run `create` command where `PUBLIC_KEY_1` and `PUBLIC_KEY_2` are the values generated by the `create key` command:

```commandline
363
./eosc create account inita currency PUBLIC_KEY_1 PUBLIC_KEY_2 
364 365 366 367
```

You should get a json response back with a transaction ID confirming it was executed successfully.

368 369 370
Check that account was successfully created: 

```commandline
S
Serg Metelin 已提交
371
./eosc get account currency
372 373 374 375 376 377
```

You should get a response similar to this:

```json
{
S
Serg Metelin 已提交
378
  "name": "currency",
379 380 381 382 383 384 385
  "eos_balance": 0,
  "staked_balance": 1,
  "unstaking_balance": 0,
  "last_unstaking_time": "2106-02-07T06:28:15"
}
```

S
Serg Metelin 已提交
386 387
<a name="uploadsmartcontract"></a>
### Upload sample contract to blockchain 
388

389
Before uploading a contract, you can verify that there is no current contract:
D
Daniel Larimer 已提交
390 391 392 393 394 395

```commandline
./eosc get code currency 
code hash: 0000000000000000000000000000000000000000000000000000000000000000
```

396
With an account for a contract created, you can upload a sample contract:
397 398

```commandline
399
./eosc set contract currency ../../contracts/currency/currency.wast ../../contracts/currency/currency.abi
S
Serg Metelin 已提交
400 401 402 403
```

As a response you should get a json with a `transaction_id` field. Your contract was successfully uploaded!

404
You can also verify that the code has been set:
D
Daniel Larimer 已提交
405 406 407 408 409 410

```commandline
./eosc get code currency
code hash: 9b9db1a7940503a88535517049e64467a6e8f4e9e03af15e9968ec89dd794975
```

411
Next you can verify that the currency contract has the proper initial balance:
D
Daniel Larimer 已提交
412 413 414 415 416 417 418 419 420 421 422 423 424

```commandline
./eosc get table currency currency account
{
  "rows": [{
     "account": "account",
     "balance": 1000000000
     }
  ],
  "more": false
}
```

S
Serg Metelin 已提交
425 426
<a name="pushamessage"></a>
### Push a message to a sample contract 
S
Serg Metelin 已提交
427

428
To send a message to a contract you need to create a new user account who will be sending the message.
S
Serg Metelin 已提交
429 430 431 432 433 434 435

Firstly, generate the keys for the account:

```commandline
cd ~/eos/build/programs/eosc/
./eosc create key
./eosc create key
436 437
```

S
Serg Metelin 已提交
438 439 440
And then create the `tester` account:

```commandline
441
./eosc create account inita tester PUBLIC_USER_KEY_1 PUBLIC_USER_KEY_2 
S
Serg Metelin 已提交
442 443
```

444
After this you can send a message to the contract:
S
Serg Metelin 已提交
445 446

```commandline
447
./eosc push message currency transfer '{"from":"currency","to":"inita","amount":50}' --scope currency,inita --permission currency@active
D
Daniel Larimer 已提交
448 449 450 451
```

As a confirmation of a successfully submitted transaction you will get a json with a `transaction_id` field.

S
Serg Metelin 已提交
452 453
<a name="readingcontract"></a>
### Reading Currency Contract Balance 
D
Daniel Larimer 已提交
454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473

```commandline
./eosc get table inita currency account
{
  "rows": [{
      "account": "account",
      "balance": 50 
       }
    ],
  "more": false
}
./eosc get table currency currency account
{
  "rows": [{
      "account": "account",
      "balance": 999999950
    }
  ],
  "more": false
}
S
Serg Metelin 已提交
474 475
```

S
Serg Metelin 已提交
476 477
<a name="localtestnet"></a>
## Running local testnet 
S
Serg Metelin 已提交
478

S
Serg Metelin 已提交
479
To run a local testnet you can use a `launcher` application provided in `~/eos/build/programs/launcher` folder.
S
Serg Metelin 已提交
480

S
Serg Metelin 已提交
481
For testing purposes you will run 2 local production nodes talking to each other.
S
Serg Metelin 已提交
482 483 484 485

```commandline
cd ~/eos/build
cp ../genesis.json ./
486
./programs/launcher/launcher -p2 -s testnet.json --skip-signature -l local
S
Serg Metelin 已提交
487 488
```

S
Serg Metelin 已提交
489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507
This command will generate 2 data folder for each instance of the node: `tn_data_0` and `tn_data_1`, as well as `testnet.json` file for the testnet configuration.

You should see a following response:

```commandline
adding hostname ip-XXX-XXX-XXX
found interface 127.0.0.1
found interface XXX.XX.XX.XX
spawning child, programs/eosd/eosd --skip-transaction-signatures --data-dir tn_data_0
spawning child, programs/eosd/eosd --skip-transaction-signatures --data-dir tn_data_1
```

To confirm the nodes are running, run following `eosc` commands:
```commandline
~/eos/build/programs/eosc
./eosc -p 8888 get info
./eosc -p 8889 get info
```

S
Serg Metelin 已提交
508
For each you should get a json with a blockchain information.
S
Serg Metelin 已提交
509

S
Serg Metelin 已提交
510 511
You can read more on launcher and its settings [here](https://github.com/EOSIO/eos/blob/master/testnet.md)

S
Serg Metelin 已提交
512 513
<a name="doxygen"></a>
## Doxygen documentation 
S
Serg Metelin 已提交
514 515 516

You can find more detailed API documentation in Doxygen reference: https://eosio.github.io/eos/

S
Serg Metelin 已提交
517 518
<a name="docker"></a>
## Running EOS in Docker 
peterwillcn's avatar
peterwillcn 已提交
519

520
Simple and fast setup of EOS in Docker is also available. Firstly, install dependencies:
521

peterwillcn's avatar
peterwillcn 已提交
522 523 524 525
 - [Docker](https://docs.docker.com)
 - [Docker-compose](https://github.com/docker/compose)
 - [Docker-volumes](https://github.com/cpuguy83/docker-volumes)

526
Build EOS image
peterwillcn's avatar
peterwillcn 已提交
527

S
Serg Metelin 已提交
528 529 530 531 532
```
git clone https://github.com/EOSIO/eos.git --recursive
cd eos
cp genesis.json Docker 
docker build -t eosio/eos -f Docker/Dockerfile .
peterwillcn's avatar
peterwillcn 已提交
533 534
```

S
Serg Metelin 已提交
535 536
We recommend 6GB+ of memory allocated to Docker to successfully build the image.

S
Serg Metelin 已提交
537
Now you can start the Docker container:
peterwillcn's avatar
peterwillcn 已提交
538

S
Serg Metelin 已提交
539
```
peterwillcn's avatar
peterwillcn 已提交
540
sudo rm -rf /data/store/eos # options 
peterwillcn's avatar
peterwillcn 已提交
541
sudo mkdir -p /data/store/eos
S
Serg Metelin 已提交
542
docker-compose -f Docker/docker-compose.yml up
peterwillcn's avatar
peterwillcn 已提交
543 544
```

545
Get chain info:
546 547 548 549 550

```
curl http://127.0.0.1:8888/v1/chain/get_info
```

S
Serg Metelin 已提交
551 552
<a name="dockercontract"></a>
### Run contract in docker example 
S
Serg Metelin 已提交
553

554
You can run the `eosc` commands via `docker exec` command. For example:
S
Serg Metelin 已提交
555

S
Serg Metelin 已提交
556
```
557
docker exec docker_eos_1 eosc contract exchange build/contracts/exchange/exchange.wast build/contracts/exchange/exchange.abi
S
Serg Metelin 已提交
558
```