wip: misc updates

AddClaim / AddSupport is working with minimal testing done so far.
RemoveClaim / RemoveSupport is implemented, but not tested yet.

Some known issues:

Currently, we update the BestClaim for each node in a lazy fashion.
Each node could add/remove claims/supports without recalculating hash
until its being obeserved externally.

However, due to the "Takeover Delay" bidding rule, as the block number
increases, the bestClaim might changes implicitly. The Trie can't detect
this passively, and would need some mechanism for this.
This commit is contained in:
Tzu-Jung Lee 2018-07-03 17:44:19 -07:00
parent 8eae587539
commit 84c64c1018
8 changed files with 454 additions and 124 deletions

View file

@ -15,12 +15,40 @@ coming soon
This project requires [Go v1.10](https://golang.org/doc/install) or higher.
``` bash
go get -v github.com/lbryio/claimtrie
go get -u -v github.com/lbryio/claimtrie
```
## Examples
Refer to [triesh](https://github.com/lbryio/claimtrie/blob/master/cmd/claimtrie)
Refer to [claimtrie](https://github.com/lbryio/claimtrie/blob/master/cmd/claimtrie) for an interactive CLI tool.
``` bash
NAME:
claimtrie - A CLI tool for ClaimTrie
USAGE:
main [global options] command [command options] [arguments...]
VERSION:
0.0.1
COMMANDS:
add-claim, ac Claim a name with specified amount. (outPoint is generated randomly, if unspecified)
add-support, as Add support to a specified Claim. (outPoint is generated randomly, if unspecified)
spend-claim, sc Spend a specified Claim.
spend-support, ss Spend a specified Support.
show, s Show the Key-Value pairs of the Stage or specified commit. (links nodes are showed if -a is also specified)
merkle, m Show the Merkle Hash of the Stage.
commit, c Commit the current Stage to commit database.
reset, r Reset the Stage to a specified commit.
log, l List the commits in the coommit database.
shell, sh Enter interactive mode
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help
--version, -v print the version
```
## Testing
@ -44,4 +72,4 @@ Our PGP key is [here](https://keybase.io/lbry/key.asc) if you need it.
## Contact
The primary contact for this project is [@lyoshenka](https://github.com/lyoshenka) (grin@lbry.io)
The primary contact for this project is [@roylee17](https://github.com/roylee) (roylee@lbry.io)

View file

@ -1,19 +1,15 @@
package claimtrie
import (
"bytes"
"encoding/binary"
"encoding/hex"
"encoding/json"
"fmt"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
// NewClaim ...
func NewClaim(op wire.OutPoint, amt Amount, accepted Height) *Claim {
return &Claim{
// newClaim ...
func newClaim(op wire.OutPoint, amt Amount, accepted Height) *claim {
return &claim{
op: op,
id: NewClaimID(op),
amt: amt,
@ -21,41 +17,35 @@ func NewClaim(op wire.OutPoint, amt Amount, accepted Height) *Claim {
}
}
// Claim ...
type Claim struct {
type claim struct {
op wire.OutPoint
id ClaimID
amt Amount
effAmt Amount
accepted Height
}
// ActivateAt ...
func (c *Claim) ActivateAt(best *Claim, curr, tookover Height) Height {
if best == nil || best == c {
return c.accepted
}
return calActiveHeight(c.accepted, curr, tookover)
activeAt Height
}
// MarshalJSON customizes the representation of JSON.
func (c *Claim) MarshalJSON() ([]byte, error) {
func (c *claim) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
OutPoint string
ClaimID string
Amount Amount
EffectiveAmount Amount
Accepted Height
ActiveAt Height
}{
OutPoint: c.op.String(),
ClaimID: c.id.String(),
Amount: c.amt,
EffectiveAmount: c.effAmt,
Accepted: c.accepted,
ActiveAt: c.activeAt,
})
}
func (c *Claim) String() string {
func (c *claim) String() string {
b, err := json.MarshalIndent(c, "", " ")
if err != nil {
fmt.Printf("can't marshal, err :%s", err)
@ -63,9 +53,8 @@ func (c *Claim) String() string {
return string(b)
}
// NewSupport ...
func NewSupport(op wire.OutPoint, amt Amount, accepted Height, supported ClaimID) *Support {
return &Support{
func newSupport(op wire.OutPoint, amt Amount, accepted Height, supported ClaimID) *support {
return &support{
op: op,
amt: amt,
accepted: accepted,
@ -73,78 +62,37 @@ func NewSupport(op wire.OutPoint, amt Amount, accepted Height, supported ClaimID
}
}
// Support ...
type Support struct {
type support struct {
op wire.OutPoint
amt Amount
accepted Height
activeAt Height
supportedID ClaimID
supportedClaim *Claim
}
// ActivateAt ...
func (s *Support) ActivateAt(best *Claim, curr, tookover Height) Height {
if best == nil || best == s.supportedClaim {
return s.accepted
}
return calActiveHeight(s.accepted, curr, tookover)
supportedClaim *claim
}
// MarshalJSON ...
func (s *Support) MarshalJSON() ([]byte, error) {
func (s *support) MarshalJSON() ([]byte, error) {
return json.Marshal(&struct {
OutPoint string
SupportedClaimID string
Amount Amount
Accepted Height
ActiveAt Height
}{
OutPoint: s.op.String(),
SupportedClaimID: s.supportedID.String(),
Amount: s.amt,
Accepted: s.accepted,
ActiveAt: s.activeAt,
})
}
func (s *Support) String() string {
func (s *support) String() string {
b, err := json.MarshalIndent(s, "", " ")
if err != nil {
fmt.Printf("can't marshal, err :%s", err)
}
return string(b)
}
// NewClaimID ...
func NewClaimID(p wire.OutPoint) ClaimID {
w := bytes.NewBuffer(p.Hash[:])
if err := binary.Write(w, binary.BigEndian, p.Index); err != nil {
panic(err)
}
var id ClaimID
copy(id[:], btcutil.Hash160(w.Bytes()))
return id
}
// NewClaimIDFromString ...
func NewClaimIDFromString(s string) (ClaimID, error) {
b, err := hex.DecodeString(s)
var id ClaimID
copy(id[:], b)
return id, err
}
// ClaimID ...
type ClaimID [20]byte
func (id ClaimID) String() string {
return hex.EncodeToString(id[:])
}
func calActiveHeight(accepted, curr, tookover Height) Height {
factor := Height(32)
delay := (curr - tookover) / factor
if delay > 4032 {
delay = 4032
}
return accepted + delay
}

45
claimid.go Normal file
View file

@ -0,0 +1,45 @@
package claimtrie
import (
"bytes"
"encoding/binary"
"encoding/hex"
"github.com/btcsuite/btcd/wire"
"github.com/btcsuite/btcutil"
)
// NewClaimID ...
func NewClaimID(op wire.OutPoint) ClaimID {
w := bytes.NewBuffer(op.Hash[:])
if err := binary.Write(w, binary.BigEndian, op.Index); err != nil {
panic(err)
}
var id ClaimID
copy(id[:], btcutil.Hash160(w.Bytes()))
return id
}
// NewClaimIDFromString ...
func NewClaimIDFromString(s string) (ClaimID, error) {
b, err := hex.DecodeString(s)
var id ClaimID
copy(id[:], b)
return id, err
}
// ClaimID ...
type ClaimID [20]byte
func (id ClaimID) String() string {
return hex.EncodeToString(id[:])
}
func calActiveHeight(accepted, curr, tookover Height) Height {
factor := Height(32)
delay := (curr - tookover) / factor
if delay > 4032 {
delay = 4032
}
return accepted + delay
}

View file

@ -60,14 +60,14 @@ func updateStageNode(stg *merkletrie.Stage, name string, modifier func(n *node)
// AddClaim adds a Claim to the Stage of ClaimTrie.
func (ct *ClaimTrie) AddClaim(name string, op wire.OutPoint, amt Amount, accepted Height) error {
return updateStageNode(ct.stg, name, func(n *node) error {
return n.addClaim(NewClaim(op, amt, accepted))
return n.addClaim(newClaim(op, amt, accepted))
})
}
// AddSupport adds a Support to the Stage of ClaimTrie.
func (ct *ClaimTrie) AddSupport(name string, op wire.OutPoint, amt Amount, accepted Height, supported ClaimID) error {
return updateStageNode(ct.stg, name, func(n *node) error {
return n.addSupport(NewSupport(op, amt, accepted, supported))
return n.addSupport(newSupport(op, amt, accepted, supported))
})
}
@ -89,7 +89,9 @@ func (ct *ClaimTrie) SpendSupport(name string, op wire.OutPoint) error {
func (ct *ClaimTrie) Traverse(visit merkletrie.Visit, update, valueOnly bool) error {
// wrapper function to make sure the node is updated before it's observed externally.
fn := func(prefix merkletrie.Key, v merkletrie.Value) error {
v.(*node).updateBestClaim(ct.bestBlock)
if v != nil {
v.(*node).updateBestClaim(ct.bestBlock)
}
return visit(prefix, v)
}
return ct.stg.Traverse(fn, update, valueOnly)
@ -97,6 +99,11 @@ func (ct *ClaimTrie) Traverse(visit merkletrie.Visit, update, valueOnly bool) er
// MerkleHash returns the Merkle Hash of the Stage.
func (ct *ClaimTrie) MerkleHash() chainhash.Hash {
visit := func(prefix merkletrie.Key, v merkletrie.Value) error {
v.(*node).updateBestClaim(ct.bestBlock)
return nil
}
ct.Traverse(visit, true, true)
return ct.stg.MerkleHash()
}
@ -133,6 +140,7 @@ func (ct *ClaimTrie) Reset(h Height) error {
if meta.Height <= h {
ct.head = commit
ct.bestBlock = h
ct.stg = merkletrie.NewStage(commit.MerkleTrie)
return nil
}
}

View file

@ -1,39 +1,39 @@
package claimtrie
import (
"fmt"
"testing"
"github.com/btcsuite/btcd/wire"
"github.com/lbryio/merkletrie"
"github.com/btcsuite/btcd/chaincfg/chainhash"
)
func TestClaimTrie_AddClaim(t *testing.T) {
type fields struct {
stg *merkletrie.Stage
}
type args struct {
name string
outPoint wire.OutPoint
value Amount
height Height
}
func TestClaimTrie_Commit(t *testing.T) {
ct := New()
tests := []struct {
name string
fields fields
args args
wantErr bool
name string
curr Height
amt Amount
want chainhash.Hash
}{
// TODO: Add test cases.
{name: "0-0", curr: 5, amt: 11},
{name: "0-0", curr: 6, amt: 10},
{name: "0-0", curr: 7, amt: 14},
{name: "0-0", curr: 8, amt: 18},
{name: "0-0", curr: 100, amt: 0},
{name: "0-0", curr: 101, amt: 30},
{name: "0-0", curr: 102, amt: 00},
{name: "0-0", curr: 103, amt: 00},
{name: "0-0", curr: 104, amt: 00},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
ct := &ClaimTrie{
stg: tt.fields.stg,
}
if err := ct.AddClaim(tt.args.name, tt.args.outPoint, tt.args.value, tt.args.height); (err != nil) != tt.wantErr {
t.Errorf("ClaimTrie.AddClaim() error = %v, wantErr %v", err, tt.wantErr)
if tt.amt != 0 {
ct.AddClaim("HELLO", *newOutPoint(0), tt.amt, tt.curr)
}
ct.Commit(tt.curr)
fmt.Printf("ct.Merkle[%2d]: %s, amt: %d\n", ct.BestBlock(), ct.MerkleHash(), tt.amt)
})
}
}

211
cmd/claimtrie/README.md Normal file
View file

@ -0,0 +1,211 @@
# ClaimTrie
coming soon
## Installation
coming soon
## Usage
``` bash
NAME:
claimtrie - A CLI tool for ClaimTrie
USAGE:
main [global options] command [command options] [arguments...]
VERSION:
0.0.1
COMMANDS:
add-claim, ac Claim a name with specified amount. (outPoint is generated randomly, if unspecified)
add-support, as Add support to a specified Claim. (outPoint is generated randomly, if unspecified)
spend-claim, sc Spend a specified Claim.
spend-support, ss Spend a specified Support.
show, s Show the Key-Value pairs of the Stage or specified commit. (links nodes are showed if -a is also specified)
merkle, m Show the Merkle Hash of the Stage.
commit, c Commit the current Stage to commit database.
reset, r Reset the Stage to a specified commit.
log, l List the commits in the coommit database.
shell, sh Enter interactive mode
help, h Shows a list of commands or help for one command
GLOBAL OPTIONS:
--help, -h show help
--version, -v print the version
```
## Running from Source
This project requires [Go v1.10](https://golang.org/doc/install) or higher.
``` bash
go get -u -v github.com/lbryio/claimtrie/cmd/claimtrie
go run ${GOPATH}/src/github.com/lbryio/claimtrie/cmd/claimtrie/main.go sh
```
## Examples
Adding claims.
``` bash
claimtrie > add-claim
claimtrie > show
<BestBlock: 0>
Hello : {
"Hash": "91185db0db792a6f6ad60e01e99e27f5263b8c3225137ff3b33bd5d3ebe197bd",
"Tookover": 0,
"BestClaim": {
"OutPoint": "5fed5c7a39d47b4432b55d172b312df87142995e83ef28bf070859e94c916f30:48",
"ClaimID": "911771619d4e6656bc0f08e1dfab5827756ed39d",
"Amount": 44,
"EffectiveAmount": 44,
"Accepted": 0,
"ActiveAt": 0
},
"Claims": [
{
"OutPoint": "5fed5c7a39d47b4432b55d172b312df87142995e83ef28bf070859e94c916f30:48",
"ClaimID": "911771619d4e6656bc0f08e1dfab5827756ed39d",
"Amount": 44,
"EffectiveAmount": 44,
"Accepted": 0,
"ActiveAt": 0
},
{
"OutPoint": "db993d544e0cbea83cff2465d3a8615cfc0750d39aa904a60e8fafab7c315a50:80",
"ClaimID": "013df2835b1b8256ed019cc71df2dfb61fdce63c",
"Amount": 10,
"EffectiveAmount": 10,
"Accepted": 0,
"ActiveAt": 0
}
],
"Supports": []
}
claimtrie > commit
```
Commit another claim.
```bash
claimtrie > add-claim --amount 100
claimtrie > commit
```
Show logs
``` bash
claimtrie > log
height: 2, commit 9e2a2cf0e7f2a60e195ce46b261d6a953a3cbb68ef6b3274543ec8fdbf8a171b
height: 1, commit ce548249c28d61920d69ac759b82f53b5da52fa611f055c4f44c2d94703667a1
height: 0, commit 0000000000000000000000000000000000000000000000000000000000000001
```
Show current status.
```bash
claimtrie > show
<BestBlock: 2>
Hello : {
"Hash": "82629d2e9fb1eb8cc78e9d6712f217d5322f1cd9a3cdd15bf3923ee2d9376e94",
"Tookover": 1,
"BestClaim": {
"OutPoint": "0f2fb103891bdf34344d34a64403537653d344558ebd3138b45e770585950d6e:110",
"ClaimID": "128f9a84dddc87afdb747e04c6ce22726d2a90e7",
"Amount": 100,
"EffectiveAmount": 100,
"Accepted": 1,
"ActiveAt": 1
},
"Claims": [
{
"OutPoint": "5fed5c7a39d47b4432b55d172b312df87142995e83ef28bf070859e94c916f30:48",
"ClaimID": "911771619d4e6656bc0f08e1dfab5827756ed39d",
"Amount": 44,
"EffectiveAmount": 44,
"Accepted": 0,
"ActiveAt": 0
},
{
"OutPoint": "0f2fb103891bdf34344d34a64403537653d344558ebd3138b45e770585950d6e:110",
"ClaimID": "128f9a84dddc87afdb747e04c6ce22726d2a90e7",
"Amount": 100,
"EffectiveAmount": 100,
"Accepted": 1,
"ActiveAt": 1
},
{
"OutPoint": "db993d544e0cbea83cff2465d3a8615cfc0750d39aa904a60e8fafab7c315a50:80",
"ClaimID": "013df2835b1b8256ed019cc71df2dfb61fdce63c",
"Amount": 10,
"EffectiveAmount": 10,
"Accepted": 0,
"ActiveAt": 0
}
],
"Supports": []
}
```
Reset the history to height 1.
``` bash
claimtrie > reset --height 1
claimtrie > show
<BestBlock: 1>
Hello : {
"Hash": "91185db0db792a6f6ad60e01e99e27f5263b8c3225137ff3b33bd5d3ebe197bd",
"Tookover": 0,
"BestClaim": {
"OutPoint": "5fed5c7a39d47b4432b55d172b312df87142995e83ef28bf070859e94c916f30:48",
"ClaimID": "911771619d4e6656bc0f08e1dfab5827756ed39d",
"Amount": 44,
"EffectiveAmount": 44,
"Accepted": 0,
"ActiveAt": 0
},
"Claims": [
{
"OutPoint": "5fed5c7a39d47b4432b55d172b312df87142995e83ef28bf070859e94c916f30:48",
"ClaimID": "911771619d4e6656bc0f08e1dfab5827756ed39d",
"Amount": 44,
"EffectiveAmount": 44,
"Accepted": 0,
"ActiveAt": 0
},
{
"OutPoint": "db993d544e0cbea83cff2465d3a8615cfc0750d39aa904a60e8fafab7c315a50:80",
"ClaimID": "013df2835b1b8256ed019cc71df2dfb61fdce63c",
"Amount": 10,
"EffectiveAmount": 10,
"Accepted": 0,
"ActiveAt": 0
}
],
"Supports": []
}
claimtrie >
```
## Contributing
coming soon
## License
This project is MIT licensed.
## Security
We take security seriously. Please contact security@lbry.io regarding any security issues.
Our PGP key is [here](https://keybase.io/lbry/key.asc) if you need it.
## Contact
The primary contact for this project is [@roylee17](https://github.com/roylee) (roylee@lbry.io)

55
node.go
View file

@ -12,23 +12,24 @@ import (
type node struct {
tookover Height
bestClaim *Claim
bestClaim *claim
claims map[string]*Claim
supports map[string]*Support
claims map[string]*claim
supports map[string]*support
}
func newNode() *node {
return &node{
claims: map[string]*Claim{},
supports: map[string]*Support{},
claims: map[string]*claim{},
supports: map[string]*support{},
}
}
func (n *node) addClaim(c *Claim) error {
func (n *node) addClaim(c *claim) error {
if _, ok := n.claims[c.op.String()]; ok {
return ErrDuplicate
}
c.activeAt = calActiveHeight(c.accepted, c.accepted, n.tookover)
n.claims[c.op.String()] = c
return nil
}
@ -51,12 +52,13 @@ func (n *node) removeClaim(op wire.OutPoint) error {
return nil
}
func (n *node) addSupport(s *Support) error {
func (n *node) addSupport(s *support) error {
if _, ok := n.supports[s.op.String()]; ok {
return ErrDuplicate
}
for _, v := range n.claims {
if v.id == s.supportedID {
s.activeAt = calActiveHeight(s.accepted, s.accepted, n.tookover)
s.supportedClaim = v
n.supports[s.op.String()] = s
return nil
@ -80,20 +82,20 @@ func (n *node) Hash() chainhash.Hash {
// MarshalJSON customizes JSON marshaling of the Node.
func (n *node) MarshalJSON() ([]byte, error) {
c := make([]*Claim, 0, len(n.claims))
c := make([]*claim, 0, len(n.claims))
for _, v := range n.claims {
c = append(c, v)
}
s := make([]*Support, 0, len(n.supports))
s := make([]*support, 0, len(n.supports))
for _, v := range n.supports {
s = append(s, v)
}
return json.Marshal(&struct {
Hash string
Tookover Height
BestClaim *Claim
Claims []*Claim
Supports []*Support
BestClaim *claim
Claims []*claim
Supports []*support
}{
Hash: n.Hash().String(),
Tookover: n.tookover,
@ -117,17 +119,18 @@ func (n *node) updateEffectiveAmounts(curr Height) {
v.effAmt = v.amt
}
for _, v := range n.supports {
if v.ActivateAt(n.bestClaim, curr, n.tookover) <= curr {
if v.supportedClaim == n.bestClaim || v.activeAt <= curr {
v.supportedClaim.effAmt += v.amt
}
}
}
func (n *node) updateBestClaim(curr Height) {
findCandiadte := func() *Claim {
findCandiadte := func() *claim {
candidate := n.bestClaim
for _, v := range n.claims {
if v.ActivateAt(n.bestClaim, curr, n.tookover) > curr {
if v.activeAt > curr {
// Accepted claim, but noy activated yet.
continue
}
if candidate == nil || v.effAmt > candidate.effAmt {
@ -136,15 +139,25 @@ func (n *node) updateBestClaim(curr Height) {
}
return candidate
}
takeover := func(candidate *claim) {
n.bestClaim = candidate
n.tookover = curr
for _, v := range n.claims {
v.activeAt = calActiveHeight(v.accepted, curr, curr)
}
}
for {
n.updateEffectiveAmounts(curr)
candidate := findCandiadte()
if n.bestClaim == nil || n.bestClaim == candidate {
n.bestClaim = candidate
if n.bestClaim == nil {
takeover(candidate)
return
}
if n.bestClaim == candidate {
return
}
n.tookover = curr
n.bestClaim = candidate
takeover(candidate)
}
}
@ -155,11 +168,11 @@ func (n *node) clone() *node {
*clone = *n
// deep copy of reference and pointer fields.
clone.claims = map[string]*Claim{}
clone.claims = map[string]*claim{}
for k, v := range n.claims {
clone.claims[k] = v
}
clone.supports = map[string]*Support{}
clone.supports = map[string]*support{}
for k, v := range n.supports {
clone.supports[k] = v
}

View file

@ -1,6 +1,7 @@
package claimtrie
import (
"crypto/rand"
"reflect"
"testing"
@ -13,6 +14,14 @@ func newHash(s string) *chainhash.Hash {
return h
}
func newOutPoint(idx int) *wire.OutPoint {
var h chainhash.Hash
if _, err := rand.Read(h[:]); err != nil {
return nil
}
return wire.NewOutPoint(&h, uint32(idx))
}
func Test_calNodeHash(t *testing.T) {
type args struct {
op wire.OutPoint
@ -24,22 +33,22 @@ func Test_calNodeHash(t *testing.T) {
want chainhash.Hash
}{
{
name: "test1",
name: "0-1",
args: args{op: wire.OutPoint{Hash: *newHash("c73232a755bf015f22eaa611b283ff38100f2a23fb6222e86eca363452ba0c51"), Index: 0}, h: 0},
want: *newHash("48a312fc5141ad648cb5dca99eaf221f7b1bc4d2fc559e1cde4664a46d8688a4"),
},
{
name: "test2",
name: "0-2",
args: args{op: wire.OutPoint{Hash: *newHash("71c7b8d35b9a3d7ad9a1272b68972979bbd18589f1efe6f27b0bf260a6ba78fa"), Index: 1}, h: 1},
want: *newHash("9132cc5ff95ae67bee79281438e7d00c25c9ec8b526174eb267c1b63a55be67c"),
},
{
name: "test3",
name: "0-3",
args: args{op: wire.OutPoint{Hash: *newHash("c4fc0e2ad56562a636a0a237a96a5f250ef53495c2cb5edd531f087a8de83722"), Index: 0x12345678}, h: 0x87654321},
want: *newHash("023c73b8c9179ffcd75bd0f2ed9784aab2a62647585f4b38e4af1d59cf0665d2"),
},
{
name: "test4",
name: "0-4",
args: args{op: wire.OutPoint{Hash: *newHash("baf52472bd7da19fe1e35116cfb3bd180d8770ffbe3ae9243df1fb58a14b0975"), Index: 0x11223344}, h: 0x88776655},
want: *newHash("6a2d40f37cb2afea3b38dea24e1532e18cade5d1dc9c2f8bd635aca2bc4ac980"),
},
@ -52,3 +61,71 @@ func Test_calNodeHash(t *testing.T) {
})
}
}
func Test_BestClaim(t *testing.T) {
cA := newClaim(*newOutPoint(1), 0, 0)
cB := newClaim(*newOutPoint(2), 0, 0)
cC := newClaim(*newOutPoint(3), 0, 0)
cD := newClaim(*newOutPoint(4), 0, 0)
s1 := newSupport(*newOutPoint(91), 0, 0, cA.id)
var n *node
type operation int
const (
opReset = 1 << iota
opAddClaim
opRemoveClaim
opAddSupport
opRemoveSupport
opCheck
)
tests := []struct {
name string
op operation
claim *claim
support *support
amount Amount
curr Height
want *claim
}{
{name: "0-0", op: opReset},
{name: "0-1", op: opAddClaim, claim: cA, amount: 10, curr: 13, want: cA}, // A(10) is controlling
{name: "0-2", op: opAddClaim, claim: cB, amount: 20, curr: 1001, want: cA}, // A(10) is controlling, B(20) is accepted. Act(B) = 1001 + (1001-13)/32 = 1031
{name: "0-3", op: opAddSupport, claim: cA, support: s1, amount: 14, curr: 1010, want: cA}, // A(10+14) is controlling, B(20) is accepted.
{name: "0-4", op: opAddClaim, claim: cC, amount: 50, curr: 1020, want: cA}, // A(10+14) is controlling, B(20) is accepted, C(50) is accepted. Act(C) = 1020 + (1020-13)/32 = 1051
{name: "0-5", op: opCheck, curr: 1031, want: cA}, // A(10+14) is controlling, B(20) is active, C(50) is accepted.
{name: "0-6", op: opAddClaim, claim: cD, amount: 300, curr: 1040, want: cA}, // A(10+14) is controlling, B(20) is active, C(50) is accepted, D(300) is accepted. Act(C) = 1040 + (1040-13)/32 = 1072
{name: "0-7", op: opCheck, curr: 1051, want: cD}, // A(10+14) is active, B(20) is active, C(50) is active, D(300) is controlling.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var err error
switch tt.op {
case opReset:
n = newNode()
case opAddClaim:
tt.claim.amt = tt.amount
tt.claim.accepted = tt.curr
err = n.addClaim(tt.claim)
case opRemoveClaim:
err = n.removeClaim(tt.claim.op)
case opAddSupport:
tt.support.accepted = tt.curr
tt.support.amt = tt.amount
tt.support.supportedID = tt.claim.id
err = n.addSupport(tt.support)
case opRemoveSupport:
}
if err != nil {
t.Errorf("BestClaim() failed, err: %s", err)
}
n.updateBestClaim(tt.curr)
got := n.bestClaim
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("BestClaim() = %d, want %d", got.op.Index, tt.want.op.Index)
}
})
}
}