Skip to content
This repository was archived by the owner on Apr 4, 2023. It is now read-only.

Commit c18cdbd

Browse files
committed
*: refactor
Signed-off-by: Gyuho Lee <[email protected]>
1 parent 7fd94be commit c18cdbd

39 files changed

+2485
-1334
lines changed

README.md

Lines changed: 113 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,14 @@ KVVM is served over RPC with [go-plugin](https://github.com/hashicorp/go-plugin)
1212

1313
At its core, the Avalanche protocol still maintains the immutable ordered sequence of states in a fully permissionless settings. And KVVM defines the rules and data structures to store key-value pairs.
1414

15-
To interact with Avalanche network RPC chain APIs, download and run a [AvalancheGo](https://github.com/ava-labs/avalanchego#installation) node locally, as follows:
15+
Build quarkvm:
16+
17+
```bash
18+
cd ${HOME}/go/src/github.com/ava-labs/quarkvm
19+
./scripts/build.sh
20+
```
21+
22+
*Step 1.* To interact with Avalanche network RPC chain APIs, download and run a [AvalancheGo](https://github.com/ava-labs/avalanchego#installation) node locally, as follows:
1623

1724
```bash
1825
# run 1 avalanchego node in local network
@@ -36,6 +43,110 @@ curl -X POST --data '{
3643
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/health
3744
```
3845

39-
TODO: example commands
46+
*Step 2.* Create a user:
47+
48+
```bash
49+
curl --location --request POST '127.0.0.1:9650/ext/keystore' \
50+
--header 'Content-Type: application/json' \
51+
--data-raw '{
52+
"jsonrpc":"2.0",
53+
"id" :1,
54+
"method" :"keystore.createUser",
55+
"params" :{
56+
"username":"testusername123",
57+
"password":"insecurestring789"
58+
}
59+
}'
60+
```
61+
62+
*Step 3.* Import the pre-funded key for the P-chain:
63+
64+
```bash
65+
curl --location --request POST '127.0.0.1:9650/ext/P' \
66+
--header 'Content-Type: application/json' \
67+
--data-raw '{
68+
"jsonrpc":"2.0",
69+
"id" :1,
70+
"method" :"platform.importKey",
71+
"params" :{
72+
"username":"testusername123",
73+
"password":"insecurestring789",
74+
"privateKey":"PrivateKey-ewoqjP7PxY4yr3iLTpLisriqt94hdyDFNgchSxGGztUrTXtNN"
75+
}
76+
}'
77+
# {"jsonrpc":"2.0","result":{"address":"P-local18jma8ppw3nhx5r4ap8clazz0dps7rv5u00z96u"},"id":1}
78+
```
79+
80+
*Step 4.* Get the list of P-chain addresses:
81+
82+
```bash
83+
curl -X POST --data '{
84+
"jsonrpc": "2.0",
85+
"method": "platform.listAddresses",
86+
"params": {
87+
"username":"testusername123",
88+
"password":"insecurestring789"
89+
},
90+
"id": 1
91+
}' -H 'content-type:application/json;' 127.0.0.1:9650/ext/P
92+
# {"jsonrpc":"2.0","result":{"addresses":["P-local18jma8ppw3nhx5r4ap8clazz0dps7rv5u00z96u"]},"id":1}
93+
```
94+
95+
*Step 5.* Create a subnet:
96+
97+
```bash
98+
curl --location --request POST '127.0.0.1:9650/ext/P' \
99+
--header 'Content-Type: application/json' \
100+
--data-raw '{
101+
"jsonrpc":"2.0",
102+
"id" :1,
103+
"method" :"platform.createSubnet",
104+
"params" :{
105+
"username":"testusername123",
106+
"password":"insecurestring789",
107+
"threshold":1,
108+
"controlKeys":["P-local18jma8ppw3nhx5r4ap8clazz0dps7rv5u00z96u"]
109+
}
110+
}'
111+
# {"jsonrpc":"2.0","result":{"txID":"29uVeLPJB1eQJkzRemU8g8wZDw5uJRqpab5U2mX9euieVwiEbL","changeAddr":"P-local18jma8ppw3nhx5r4ap8clazz0dps7rv5u00z96u"},"id":1}
112+
# 29uVeLPJB1eQJkzRemU8g8wZDw5uJRqpab5U2mX9euieVwiEbL is the subnet blockchain ID
113+
```
114+
115+
*Step 6.* Create a blockchain:
40116

117+
```bash
118+
# TODO: where to get vmID
119+
curl --location --request POST '127.0.0.1:9650/ext/P' \
120+
--header 'Content-Type: application/json' \
121+
--data-raw '{
122+
"jsonrpc":"2.0",
123+
"id" :1,
124+
"method" :"platform.createBlockchain",
125+
"params" :{
126+
"username":"testusername123",
127+
"password":"insecurestring789",
128+
"vmID":"tGas3T58KzdjLHhBDMnH2TvrddhqTji5iZAMZ3RXs2NLpSnhH",
129+
"subnetID":"29uVeLPJB1eQJkzRemU8g8wZDw5uJRqpab5U2mX9euieVwiEbL",
130+
"name":"quarkvm",
131+
"genesisData":"",
132+
"controlKeys":["P-local18jma8ppw3nhx5r4ap8clazz0dps7rv5u00z96u"]
133+
}
134+
}'
135+
#
136+
```
137+
138+
Connect to quarkvm:
41139

140+
```bash
141+
curl --location --request POST '127.0.0.1:9650/ext/vm/tGas3T58KzdjLHhBDMnH2TvrddhqTji5iZAMZ3RXs2NLpSnhH' \
142+
--header 'Content-Type: application/json' \
143+
--data-raw '{
144+
"jsonrpc":"2.0",
145+
"id" :1,
146+
"method" :"quarkvm.put",
147+
"params" :{
148+
"key":"foo",
149+
"value":"bar"
150+
}
151+
}'
152+
```

agent/agent.go

Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
// Copyright (C) 2019-2021, Ava Labs, Inc. All rights reserved.
2+
// See the file LICENSE for licensing terms.
3+
4+
// Package agent implements KVVM agent.
5+
package agent
6+
7+
import (
8+
"context"
9+
"fmt"
10+
"math/big"
11+
"math/rand"
12+
"time"
13+
14+
"ekyu.moe/cryptonight"
15+
"github.com/ava-labs/quarkvm/chain"
16+
"github.com/ava-labs/quarkvm/crypto/ed25519"
17+
"github.com/ava-labs/quarkvm/transaction"
18+
)
19+
20+
type Agent interface {
21+
Run()
22+
}
23+
24+
type agent struct {
25+
ctx context.Context
26+
chain chain.Chain
27+
28+
privateKey ed25519.PrivateKey
29+
publicKey ed25519.PublicKey
30+
}
31+
32+
func New(ctx context.Context, chain chain.Chain) Agent {
33+
prv, err := ed25519.NewPrivateKey()
34+
if err != nil {
35+
panic(err)
36+
}
37+
pub := prv.PublicKey()
38+
39+
fmt.Println("new agent:", pub.Address())
40+
return &agent{
41+
ctx: ctx,
42+
chain: chain,
43+
44+
privateKey: prv,
45+
publicKey: pub,
46+
}
47+
}
48+
49+
func (a *agent) Run() {
50+
for a.ctx.Err() == nil {
51+
prefix := randString(16)
52+
if rand.Intn(100) < 20 {
53+
// claim own address key
54+
prefix = a.publicKey.Address()
55+
fmt.Println("attempting to claim address prefix", prefix)
56+
}
57+
utx := a.claim(prefix)
58+
a.mine(utx)
59+
stx := a.sign(utx)
60+
a.chain.Submit(stx)
61+
62+
// wait for claim to be set or abandon
63+
confirmed := a.confirm(stx)
64+
if !confirmed {
65+
// TODO: try again with same prefix
66+
continue
67+
}
68+
owner, _, err := a.chain.GetPrefixInfo([]byte(prefix))
69+
if err != nil {
70+
panic(err)
71+
}
72+
fmt.Println("prefix claimed:", prefix, "expires:", owner.Expiry, "keys:", owner.Keys)
73+
// TODO: print out "rate of decay"
74+
// TODO: set 2 keys
75+
// TODO: delete 1 key
76+
// TODO: wait for key expiry
77+
// TODO: attempt to set key
78+
// TODO: add lifeline
79+
}
80+
}
81+
82+
func (a *agent) claim(prefix string) transaction.Unsigned {
83+
return transaction.NewClaim(a.publicKey, []byte(prefix))
84+
}
85+
86+
func (a *agent) mine(utx transaction.Unsigned) {
87+
for {
88+
cbID := a.chain.CurrentBlock().ID()
89+
utx.SetBlockID(cbID)
90+
graffiti := big.NewInt(0)
91+
for a.chain.ValidBlockID(cbID) {
92+
utx.SetGraffiti(graffiti.Bytes())
93+
h := cryptonight.Sum(transaction.UnsignedBytes(utx), 2)
94+
if cryptonight.CheckHash(h, a.chain.DifficultyEstimate()) {
95+
return
96+
}
97+
graffiti.Add(graffiti, big.NewInt(1))
98+
}
99+
// Get new block hash if no longer valid
100+
}
101+
}
102+
103+
func (a *agent) sign(utx transaction.Unsigned) *transaction.Transaction {
104+
sig, err := a.privateKey.Sign(transaction.UnsignedBytes(utx))
105+
if err != nil {
106+
panic(err)
107+
}
108+
return transaction.New(utx, sig)
109+
}
110+
111+
func (a *agent) confirm(stx *transaction.Transaction) bool {
112+
loops := 0
113+
for a.ctx.Err() == nil && a.chain.ValidBlockID(stx.Unsigned.GetBlockID()) {
114+
if a.chain.TxConfirmed(stx.ID()) {
115+
return true
116+
}
117+
time.Sleep(1 * time.Second)
118+
loops++
119+
120+
// Resubmit if pending for a while but still valid
121+
if loops%5 == 0 && !a.chain.MempoolContains(stx.ID()) {
122+
a.chain.Submit(stx)
123+
}
124+
}
125+
return false
126+
}
127+
128+
func randString(n int) string {
129+
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")
130+
l := rand.Intn(n) + 1 // ensure never 0
131+
132+
s := make([]rune, l)
133+
for i := range s {
134+
s[i] = letters[rand.Intn(len(letters))]
135+
}
136+
return string(s)
137+
}

0 commit comments

Comments
 (0)