Skip to content

Commit

Permalink
unified OSP CLI tool
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaozhou committed May 15, 2020
1 parent 1b6c031 commit fcd6c4b
Show file tree
Hide file tree
Showing 28 changed files with 1,345 additions and 1,265 deletions.
5 changes: 1 addition & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ jobs:
mkdir goceler && pushd goceler
LDFLAG="-s -w -X main.version=${{ steps.get_tag.outputs.TAG }} -X main.commit=${GITHUB_SHA::6}"
go build -ldflags "$LDFLAG" ../server
go build ../tools/osp-admin
go build ../tools/osp-setup
go build ../tools/channel-view
go build ../tools/channel-op
go build ../tools/osp-cli
popd
tar czf goceler-${{ steps.get_tag.outputs.TAG }}-linux-amd64.tar.gz goceler/
Expand Down
24 changes: 13 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,36 +19,38 @@ Make sure you have walked through the [local manual tests](./test/manual/README.
Download prebuit binaries from https://github.com/celer-network/goCeler-oss/releases
Then run
```bash
tar xzf goceler-v0.16.6-linux-amd64.tar.gz
tar xzf goceler-v0.16.7-linux-amd64.tar.gz
export PATH=$PATH:$PWD/goceler
```

### Prepare OSP account
1. Run **`geth account new --keystore .`** to generate a new keystore file, then rename it to `ospks.json`
2. Fund the newly generated ospks.json address some mainnet ETH.
3. Update [deploy/mainnet/profile.json](./deploy/mainnet/profile.json) `gateway` field to your Mainnet RPC (eg. https://mainnet.infura.io/v3/xxxxx), `host` filed to the OSP public RPC hostname:port (default rpc port is 10000), `address` field to the OSP ETH address.
4. Setup OSP: **`osp-setup -profile $GOCELER/deploy/mainnet/profile.json -ks ospks.json -ethpoolamt [ETH amount]`**. This step would do two things. First, deposit OSP's ETH with amount specified by `-ethpoolamt` into the EthPool for future channel opening and deposits. Second, register the OSP on-chain as a state channel network router.
- **note**: currently, OSP has to use ETH in its account (not EthPool) to initiate an open channel request. EthPool balance is used to accept open channel request from peers.
4. Setup OSP: Run **`osp-cli -profile $GOCELER/deploy/mainnet/profile.json -ks ospks.json -ethpooldeposit -amount [ETH amount] -register -blkdelay 2`** to deposit OSP's ETH into the EthPool contract, and register the OSP as a state channel network router.
- **note 1**: EthPool balance is used by OSP to make channel deposits and accept open channel request from peers.
- **note 2**: `-blkdelay` specifies how many blocks to wait to confirm the on-chain transactions.

### Run OSP server
#### Option 1: run OSP using SQLite as storage backend (easier)
5. Create a storage folder `celerdb` (or other location as you prefer). The OSP SQLite data store will be located at `celerdb/[ospAddr]`.
6. Start OSP: **`server -profile $GOCELER/deploy/mainnet/profile.json -ks ospks.json -svrname s0 -storedir celerdb -rtc $GOCELER/deploy/mainnet/rt_config.json -routedata $GOCELER/deploy/mainnet/channels_2020_05_08.json`**.
5. Choose a store path (e.g., `${HOME}/celerdb`), the OSP data will be located at `${HOME}/celerdb/[ospAddr]`.
6. Start OSP: **`server -profile $GOCELER/deploy/mainnet/profile.json -ks ospks.json -svrname s0 -storedir ${HOME}/celerdb -rtc $GOCELER/deploy/mainnet/rt_config.json -routedata $GOCELER/deploy/mainnet/channels_2020_05_08.json`**.
- **note 1**: use `-routedata` only when starting OSP from scracth for the first time.
- **note 2**: the default rpc port is `10000`, default admin http endpoint is `localhost:8090`, use `-port` and `-adminweb` to change those values ([example](./test/manual/run_osp.sh)).
- **note 3**: use [log args](https://github.com/celer-network/goutils/blob/v0.1.2/log/log.go) if needed, e.g., `-logdir logs -logrotate`
- **note 3**: use [log args](https://github.com/celer-network/goutils/blob/v0.1.2/log/log.go) if needed, e.g., `-logdir ${HOME}/logs -logrotate`

#### Option 2: run OSP using CockroachDB as storage backend (higher performance)
5. First install CockroachDB. Then checkout [tools/scripts/cockroachdb.sh](./tools/scripts/cockroachdb.sh), update `STOREPATH` to your preferred storage location, and run **`./cockroachdb.sh start`** to start the cockroachDB process and create database tables.
6. Start OSP: **`server -profile $GOCELER/deploy/mainnet/profile.json -ks ospks.json -svrname s0 -storesql postgresql://celer@localhost:26257/celer?sslmode=disable -rtc $GOCELER/deploy/mainnet/rt_config.json -routedata $GOCELER/deploy/mainnet/channels_2020_05_08.json`**. Be aware of the notes 1-3 above.
6. Start OSP: **`server -profile $GOCELER/deploy/mainnet/profile.json -ks ospks.json -svrname s0 -storesql postgresql://celer@localhost:26257/celer?sslmode=disable -rtc $GOCELER/deploy/mainnet/rt_config.json -routedata $GOCELER/deploy/mainnet/channels_2020_05_08.json`**. Be aware of the **notes 1-3** above.

### Open channel with peer OSP
7. Connect with another OSP through grpc stream: **`osp-admin -adminhostport localhost:8090 -registerstream -peeraddr [peerOspEthAddr] -peerhostport [peerOspHost:Port]`**
8. Open channel with another OSP: **`osp-admin -adminhostport localhost:8090 -openchannel -peeraddr [peerOspEthAddr] -selfdeposit 0.1 -peerdeposit 0.1`**
7. Connect with another OSP through grpc stream: **`osp-cli -adminhostport localhost:8090 -registerstream -peer [peerOspAddr] -peerhostport [peerOspHostPort]`**
8. Open channel with another OSP: **`osp-cli -adminhostport localhost:8090 -openchannel -peer [peerOspAddr] -selfdeposit 0.1 -peerdeposit 0.1`**
9. Query channel from database: **`osp-cli -profile $GOCELER/deploy/mainnet/profile.json -storedir ${HOME}/celerdb/[ospAddr] -dbview channel -peer [peerOspAddr]`**. If using CockroachDB, replace the `-storedir` arg with `-storesql postgresql://celer@localhost:26257/celer?sslmode=disable`.
10. Query channel from blockchain: **`osp-cli -profile $GOCELER/deploy/mainnet/profile.json -onchainview channel -cid [channel ID]`**. You can see the channel ID from the output of step 9 above.

### Apply other OSP operations
9. Use [osp-admin](./tools/osp-admin/README.md), [channel-view](./tools/channel-view/README.md), and [channel-op](./tools/channel-op/README.md) tools to operate the OSP. See [local manual tests](./test/manual/README.md) for example.

11. Use [OSP CLI Commands](./tools/osp-cli/README.md) to operate the OSP. See [local manual tests](./test/manual/README.md) for example.

## Run OSP on Ropsten Testnet

Expand Down
8 changes: 4 additions & 4 deletions storage/dal.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,12 +141,12 @@ func (d *DAL) GetChanViewInfoByID(cid ctype.CidType) (int, *time.Time, *time.Tim
return getChanViewInfoByID(d.st, cid)
}

func (d *DAL) GetAllChanInfoByToken(token *entity.TokenInfo) ([]ctype.CidType, []ctype.Addr, []*entity.TokenInfo, []int, []*time.Time, []*time.Time, []*structs.OnChainBalance, []*entity.SimplexPaymentChannel, []*entity.SimplexPaymentChannel, error) {
return getAllChanInfoByToken(d.st, token)
func (d *DAL) GetAllChansByTokenAndState(token *entity.TokenInfo, state int) ([]ctype.CidType, []ctype.Addr, []*entity.TokenInfo, []*time.Time, []*time.Time, []*structs.OnChainBalance, []*entity.SimplexPaymentChannel, []*entity.SimplexPaymentChannel, error) {
return getAllChansByTokenAndState(d.st, token, state)
}

func (d *DAL) GetInactiveChanInfo(token *entity.TokenInfo, stateTs time.Time) ([]ctype.CidType, []ctype.Addr, []*entity.TokenInfo, []int, []*time.Time, []*time.Time, []*structs.OnChainBalance, []*entity.SimplexPaymentChannel, []*entity.SimplexPaymentChannel, error) {
return getInactiveChanInfo(d.st, token, stateTs)
func (d *DAL) GetInactiveChansByTokenAndState(token *entity.TokenInfo, state int, stateTs time.Time) ([]ctype.CidType, []ctype.Addr, []*entity.TokenInfo, []*time.Time, []*time.Time, []*structs.OnChainBalance, []*entity.SimplexPaymentChannel, []*entity.SimplexPaymentChannel, error) {
return getInactiveChansByTokenAndState(d.st, token, state, stateTs)
}

func (d *DAL) GetChanState(cid ctype.CidType) (int, bool, error) {
Expand Down
31 changes: 14 additions & 17 deletions storage/dal_sql.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,46 +290,44 @@ func getChanViewInfoByID(st SqlStorage, cid ctype.CidType) (
return state, &statets, &opents, chaninit, onChainBalance, selfSimplex, peerSimplex, found, err
}

func getAllChanInfoByToken(st SqlStorage, token *entity.TokenInfo) (
[]ctype.CidType, []ctype.Addr, []*entity.TokenInfo, []int, []*time.Time, []*time.Time, []*structs.OnChainBalance,
func getAllChansByTokenAndState(st SqlStorage, token *entity.TokenInfo, state int) (
[]ctype.CidType, []ctype.Addr, []*entity.TokenInfo, []*time.Time, []*time.Time, []*structs.OnChainBalance,
[]*entity.SimplexPaymentChannel, []*entity.SimplexPaymentChannel, error) {
q := `SELECT cid, peer, token, state, statets, opents, onchainbalance, selfsimplex, peersimplex FROM channels WHERE token = $1 ORDER BY state, statets`
rows, err := st.Query(q, utils.GetTokenAddrStr(token))
q := `SELECT cid, peer, token, statets, opents, onchainbalance, selfsimplex, peersimplex FROM channels WHERE token = $1 AND state = $2 ORDER BY statets`
rows, err := st.Query(q, utils.GetTokenAddrStr(token), state)
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, nil, nil, err
}
defer rows.Close()
return getChanFromRows(rows)
}

func getInactiveChanInfo(st SqlStorage, token *entity.TokenInfo, stateTs time.Time) (
[]ctype.CidType, []ctype.Addr, []*entity.TokenInfo, []int, []*time.Time, []*time.Time, []*structs.OnChainBalance,
func getInactiveChansByTokenAndState(st SqlStorage, token *entity.TokenInfo, state int, stateTs time.Time) (
[]ctype.CidType, []ctype.Addr, []*entity.TokenInfo, []*time.Time, []*time.Time, []*structs.OnChainBalance,
[]*entity.SimplexPaymentChannel, []*entity.SimplexPaymentChannel, error) {
q := `SELECT cid, peer, token, state, statets, opents, onchainbalance, selfsimplex, peersimplex FROM channels WHERE token = $1 AND statets < $2 ORDER BY state, statets`
rows, err := st.Query(q, utils.GetTokenAddrStr(token), stateTs)
q := `SELECT cid, peer, token, statets, opents, onchainbalance, selfsimplex, peersimplex FROM channels WHERE token = $1 AND state = $2 AND statets < $3 ORDER BY statets`
rows, err := st.Query(q, utils.GetTokenAddrStr(token), state, stateTs)
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, nil, nil, err
}
defer rows.Close()
return getChanFromRows(rows)
}

func getChanFromRows(rows *sql.Rows) (
[]ctype.CidType, []ctype.Addr, []*entity.TokenInfo, []int, []*time.Time, []*time.Time, []*structs.OnChainBalance,
[]ctype.CidType, []ctype.Addr, []*entity.TokenInfo, []*time.Time, []*time.Time, []*structs.OnChainBalance,
[]*entity.SimplexPaymentChannel, []*entity.SimplexPaymentChannel, error) {
var cids []ctype.CidType
var peers []ctype.Addr
var tokens []*entity.TokenInfo
var states []int
var stateTses, openTses []*time.Time
var balances []*structs.OnChainBalance
var selfSimplexes, peerSimplexes []*entity.SimplexPaymentChannel

for rows.Next() {
var cidStr, peerStr, tokenStr, stateTsStr, openTsStr string
var onChainBalanceBytes, selfSimplexBytes, peerSimplexBytes []byte
var state int
err := rows.Scan(&cidStr, &peerStr, &tokenStr, &state, &stateTsStr, &openTsStr, &onChainBalanceBytes, &selfSimplexBytes, &peerSimplexBytes)
err := rows.Scan(&cidStr, &peerStr, &tokenStr, &stateTsStr, &openTsStr, &onChainBalanceBytes, &selfSimplexBytes, &peerSimplexBytes)
var onChainBalance *structs.OnChainBalance
var selfSimplex, peerSimplex *entity.SimplexPaymentChannel
var statets, opents time.Time
Expand All @@ -346,20 +344,19 @@ func getChanFromRows(rows *sql.Rows) (
opents, err = str2Time(openTsStr)
}
if err != nil {
return nil, nil, nil, nil, nil, nil, nil, nil, nil, err
return nil, nil, nil, nil, nil, nil, nil, nil, err
}
cids = append(cids, ctype.Hex2Cid(cidStr))
peers = append(peers, ctype.Hex2Addr(peerStr))
tokens = append(tokens, utils.GetTokenInfoFromAddress(ctype.Hex2Addr(tokenStr)))
states = append(states, state)
stateTses = append(stateTses, &statets)
openTses = append(openTses, &opents)
balances = append(balances, onChainBalance)
selfSimplexes = append(selfSimplexes, selfSimplex)
peerSimplexes = append(peerSimplexes, peerSimplex)
}

return cids, peers, tokens, states, stateTses, openTses, balances, selfSimplexes, peerSimplexes, nil
return cids, peers, tokens, stateTses, openTses, balances, selfSimplexes, peerSimplexes, nil
}

func getCidsByTokenAndState(st SqlStorage, token *entity.TokenInfo, state int) ([]ctype.CidType, error) {
Expand Down
77 changes: 47 additions & 30 deletions test/e2e/channel_view.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ func erc20ChannelView(t *testing.T) {
}

func channelView(t *testing.T, tokenType entity.TokenType, tokenAddr string) {
buildPkgBin(outRootDir, "tools/channel-view", "channelview")
ks, addrs, err := tf.CreateAccountsWithBalance(2, accountBalance)
if err != nil {
t.Error(err)
Expand Down Expand Up @@ -67,7 +66,7 @@ func channelView(t *testing.T, tokenType entity.TokenType, tokenAddr string) {
t.Error(err)
return
}
_, err = c2.TcbOpenChannel(c2EthAddr, tokenType, tokenAddr, initialBalance)
_, err = c2.OpenChannel(c2EthAddr, tokenType, tokenAddr, initialBalance, initialBalance)
if err != nil {
t.Error(err)
return
Expand Down Expand Up @@ -165,102 +164,120 @@ func channelView(t *testing.T, tokenType entity.TokenType, tokenAddr string) {
t.Error(err)
return
}
sleep(1)
sleep(2)

fmt.Println()
fmt.Println("-------------------------------------- channel cid")
tf.StartProcess(outRootDir+"channelview",
tf.StartProcess(outRootDir+"ospcli",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-dbview", "channel",
"-cid", cid1.GetChannelId(),
"-allpays",
"-payhistory",
"-logcolor",
"-logprefix", "cv").Wait()
"-logprefix", "cli").Wait()

fmt.Println()
fmt.Println("-------------------------------------- channel peer token")
tf.StartProcess(outRootDir+"channelview",
tf.StartProcess(outRootDir+"ospcli",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-dbview", "channel",
"-peer", c2EthAddr,
"-token", tokenAddr,
"-logcolor",
"-logprefix", "cv").Wait()
"-logprefix", "cli").Wait()

fmt.Println()
fmt.Println("-------------------------------------- allchan")
tf.StartProcess(outRootDir+"channelview",
fmt.Println("-------------------------------------- list all channel details")
tf.StartProcess(outRootDir+"ospcli",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-dbview", "allchan",
"-dbview", "channel",
"-list",
"-detail",
"-token", tokenAddr,
"-logcolor",
"-logprefix", "cv").Wait()
"-logprefix", "cli").Wait()

fmt.Println()
fmt.Println("-------------------------------------- inactive")
tf.StartProcess(outRootDir+"channelview",
fmt.Println("-------------------------------------- list inactive channels")
tf.StartProcess(outRootDir+"ospcli",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-dbview", "allchan",
"-dbview", "channel",
"-list",
"-detail",
"-token", tokenAddr,
"-inactivesec", fmt.Sprintf("%d", int(time.Now().Sub(ts).Seconds())),
"-logcolor",
"-logprefix", "cv").Wait()
"-logprefix", "cli").Wait()

fmt.Println()
fmt.Println("-------------------------------------- list inactive channels")
tf.StartProcess(outRootDir+"ospcli",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-dbview", "channel",
"-list",
"-detail",
"-token", tokenAddr,
"-inactivesec", "1",
"-logcolor",
"-logprefix", "cli").Wait()

fmt.Println()
fmt.Println("-------------------------------------- inactive")
tf.StartProcess(outRootDir+"channelview",
fmt.Println("-------------------------------------- list channel IDs")
tf.StartProcess(outRootDir+"ospcli",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-dbview", "allchan",
"-dbview", "channel",
"-token", tokenAddr,
"-inactivesec", "0",
"-list",
"-logcolor",
"-logprefix", "cv").Wait()
"-logprefix", "cli").Wait()

fmt.Println()
fmt.Println("-------------------------------------- balance")
tf.StartProcess(outRootDir+"channelview",
tf.StartProcess(outRootDir+"ospcli",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-dbview", "balance",
"-dbview", "channel",
"-token", tokenAddr,
"-balance",
"-logcolor",
"-logprefix", "cv").Wait()
"-logprefix", "cli").Wait()

fmt.Println()
fmt.Println("-------------------------------------- route")
tf.StartProcess(outRootDir+"channelview",
tf.StartProcess(outRootDir+"ospcli",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-dbview", "route",
"-dest", c2EthAddr,
"-token", tokenAddr,
"-logcolor",
"-logprefix", "cv").Wait()
"-logprefix", "cli").Wait()

fmt.Println()
fmt.Println("-------------------------------------- pay")
tf.StartProcess(outRootDir+"channelview",
tf.StartProcess(outRootDir+"ospcli",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-dbview", "pay",
"-payid", p2,
"-logcolor",
"-logprefix", "cv").Wait()
"-logprefix", "cli").Wait()

fmt.Println()
fmt.Println("-------------------------------------- pay")
tf.StartProcess(outRootDir+"channelview",
tf.StartProcess(outRootDir+"ospcli",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-dbview", "pay",
"-payid", p4,
"-logcolor",
"-logprefix", "cv").Wait()
"-logprefix", "cli").Wait()

fmt.Println()
}
16 changes: 9 additions & 7 deletions test/e2e/intend_withdraw.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,23 +69,25 @@ func ospIntendWithdraw(t *testing.T, tokenType entity.TokenType, tokenAddr strin
}
sAmtBefore, err := c.GetAccountBalance(tokenAddr, ospEthAddr, cEthClient)
*/
tf.StartProcess(outRootDir+"channelop",
tf.StartProcess(outRootDir+"ospcli",
"-ks", ospKeystore,
"-nopassword",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-intendwithdraw", channel.ChannelId,
"-withdrawamt", "1.1",
"-logprefix", "co").Wait()
"-intendwithdraw",
"-cid", channel.ChannelId,
"-amount", "1.1",
"-logprefix", "cli").Wait()
tf.AdvanceBlocks(10)

tf.StartProcess(outRootDir+"channelop",
tf.StartProcess(outRootDir+"ospcli",
"-ks", ospKeystore,
"-nopassword",
"-profile", noProxyProfile,
"-storedir", sStoreDir+"/"+ospEthAddr,
"-confirmwithdraw", channel.ChannelId,
"-logprefix", "co").Wait()
"-confirmwithdraw",
"-cid", channel.ChannelId,
"-logprefix", "cli").Wait()
tf.AdvanceBlocks(5)

err = c.SyncOnChainChannelStates(tokenType, tokenAddr)
Expand Down
Loading

0 comments on commit fcd6c4b

Please sign in to comment.