2018-07-14 07:10:23 +02:00
|
|
|
package claim
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math"
|
|
|
|
|
|
|
|
"github.com/btcsuite/btcd/chaincfg/chainhash"
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
"github.com/pkg/errors"
|
2018-07-14 07:10:23 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
// Node ...
|
|
|
|
type Node struct {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
name string
|
|
|
|
|
|
|
|
height Height
|
|
|
|
|
|
|
|
best *Claim
|
|
|
|
tookover Height
|
2018-07-14 07:10:23 +02:00
|
|
|
|
2018-08-15 04:50:42 +02:00
|
|
|
claims List
|
|
|
|
supports List
|
2018-07-14 07:10:23 +02:00
|
|
|
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
// refer to updateClaim.
|
2018-08-15 04:50:42 +02:00
|
|
|
removed List
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewNode returns a new Node.
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
func NewNode(name string) *Node {
|
|
|
|
return &Node{name: name}
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
|
2018-08-15 04:50:42 +02:00
|
|
|
// Name returns the Name where the Node blongs.
|
|
|
|
func (n *Node) Name() string {
|
|
|
|
return n.name
|
|
|
|
}
|
|
|
|
|
2018-07-14 07:10:23 +02:00
|
|
|
// Height returns the current height.
|
|
|
|
func (n *Node) Height() Height {
|
|
|
|
return n.height
|
|
|
|
}
|
|
|
|
|
|
|
|
// BestClaim returns the best claim at the current height.
|
|
|
|
func (n *Node) BestClaim() *Claim {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
return n.best
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
|
2018-08-15 04:50:42 +02:00
|
|
|
// Tookover returns the the height at when the current BestClaim tookover.
|
|
|
|
func (n *Node) Tookover() Height {
|
|
|
|
return n.tookover
|
|
|
|
}
|
|
|
|
|
|
|
|
// Claims returns the claims at the current height.
|
|
|
|
func (n *Node) Claims() List {
|
|
|
|
return n.claims
|
|
|
|
}
|
|
|
|
|
|
|
|
// Supports returns the supports at the current height.
|
|
|
|
func (n *Node) Supports() List {
|
|
|
|
return n.supports
|
|
|
|
}
|
|
|
|
|
2018-08-06 02:43:38 +02:00
|
|
|
// AddClaim adds a Claim to the Node.
|
2018-08-15 04:50:42 +02:00
|
|
|
func (n *Node) AddClaim(op OutPoint, amt Amount, val []byte) error {
|
|
|
|
if Find(ByOP(op), n.claims, n.supports) != nil {
|
2018-07-14 07:10:23 +02:00
|
|
|
return ErrDuplicate
|
|
|
|
}
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
accepted := n.height + 1
|
2018-08-15 04:50:42 +02:00
|
|
|
c := New(op, amt).setID(NewID(op)).setAccepted(accepted).setValue(val)
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
c.setActiveAt(accepted + calDelay(accepted, n.tookover))
|
2018-08-15 04:50:42 +02:00
|
|
|
if !IsActiveAt(n.best, accepted) {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
c.setActiveAt(accepted)
|
|
|
|
n.best, n.tookover = c, accepted
|
|
|
|
}
|
|
|
|
n.claims = append(n.claims, c)
|
2018-07-14 07:10:23 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-08-06 02:43:38 +02:00
|
|
|
// SpendClaim spends a Claim in the Node.
|
|
|
|
func (n *Node) SpendClaim(op OutPoint) error {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
var c *Claim
|
2018-08-15 04:50:42 +02:00
|
|
|
if n.claims, c = Remove(n.claims, ByOP(op)); c == nil {
|
2018-07-14 07:10:23 +02:00
|
|
|
return ErrNotFound
|
|
|
|
}
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
n.removed = append(n.removed, c)
|
2018-07-14 07:10:23 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-08-06 02:43:38 +02:00
|
|
|
// UpdateClaim updates a Claim in the Node.
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
// A claim update is composed of two separate commands (2 & 3 below).
|
|
|
|
//
|
|
|
|
// (1) blk 500: Add Claim (opA, amtA, NewID(opA)
|
|
|
|
// ...
|
|
|
|
// (2) blk 1000: Spend Claim (opA, idA)
|
|
|
|
// (3) blk 1000: Update Claim (opB, amtB, idA)
|
|
|
|
//
|
|
|
|
// For each block, all the spent claims are kept in n.removed until committed.
|
|
|
|
// The paired (spend, update) commands has to happen in the same trasaction.
|
2018-08-15 04:50:42 +02:00
|
|
|
func (n *Node) UpdateClaim(op OutPoint, amt Amount, id ID, val []byte) error {
|
|
|
|
if Find(ByOP(op), n.claims, n.supports) != nil {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
return ErrDuplicate
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
var c *Claim
|
2018-08-15 04:50:42 +02:00
|
|
|
if n.removed, c = Remove(n.removed, ByID(id)); c == nil {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
return errors.Wrapf(ErrNotFound, "remove(n.removed, byID(%s)", id)
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
accepted := n.height + 1
|
2018-08-15 04:50:42 +02:00
|
|
|
c.setOutPoint(op).setAmt(amt).setAccepted(accepted).setValue(val)
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
c.setActiveAt(accepted + calDelay(accepted, n.tookover))
|
|
|
|
if n.best != nil && n.best.ID == id {
|
|
|
|
c.setActiveAt(n.tookover)
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
n.claims = append(n.claims, c)
|
2018-07-14 07:10:23 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-08-06 02:43:38 +02:00
|
|
|
// AddSupport adds a Support to the Node.
|
|
|
|
func (n *Node) AddSupport(op OutPoint, amt Amount, id ID) error {
|
2018-08-15 04:50:42 +02:00
|
|
|
if Find(ByOP(op), n.claims, n.supports) != nil {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
return ErrDuplicate
|
|
|
|
}
|
|
|
|
// Accepted by rules. No effects on bidding result though.
|
|
|
|
// It may be spent later.
|
2018-08-15 04:50:42 +02:00
|
|
|
if Find(ByID(id), n.claims, n.removed) == nil {
|
2018-08-06 02:43:38 +02:00
|
|
|
// fmt.Printf("INFO: can't find suooported claim ID: %s for %s\n", id, n.name)
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
accepted := n.height + 1
|
|
|
|
s := New(op, amt).setID(id).setAccepted(accepted)
|
|
|
|
s.setActiveAt(accepted + calDelay(accepted, n.tookover))
|
|
|
|
if n.best != nil && n.best.ID == id {
|
|
|
|
s.setActiveAt(accepted)
|
|
|
|
}
|
|
|
|
n.supports = append(n.supports, s)
|
|
|
|
return nil
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
|
2018-08-06 02:43:38 +02:00
|
|
|
// SpendSupport spends a support in the Node.
|
|
|
|
func (n *Node) SpendSupport(op OutPoint) error {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
var s *Claim
|
2018-08-15 04:50:42 +02:00
|
|
|
if n.supports, s = Remove(n.supports, ByOP(op)); s != nil {
|
2018-07-17 08:20:11 +02:00
|
|
|
return nil
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
return ErrNotFound
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
|
2018-08-06 02:43:38 +02:00
|
|
|
// AdjustTo increments current height until it reaches the specific height.
|
|
|
|
func (n *Node) AdjustTo(ht Height) *Node {
|
|
|
|
if ht <= n.height {
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
for n.height < ht {
|
|
|
|
n.height++
|
|
|
|
n.bid()
|
|
|
|
next := n.NextUpdate()
|
|
|
|
if next > ht || next == n.height {
|
|
|
|
n.height = ht
|
|
|
|
break
|
|
|
|
}
|
|
|
|
n.height = next
|
|
|
|
n.bid()
|
|
|
|
}
|
|
|
|
n.bid()
|
|
|
|
return n
|
|
|
|
}
|
|
|
|
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
// NextUpdate returns the height at which pending updates should happen.
|
|
|
|
// When no pending updates exist, current height is returned.
|
|
|
|
func (n *Node) NextUpdate() Height {
|
|
|
|
next := Height(math.MaxInt32)
|
2018-08-15 04:50:42 +02:00
|
|
|
min := func(l List) Height {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
for _, v := range l {
|
|
|
|
exp := v.expireAt()
|
|
|
|
if n.height >= exp {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if v.ActiveAt > n.height && v.ActiveAt < next {
|
|
|
|
next = v.ActiveAt
|
|
|
|
}
|
|
|
|
if exp > n.height && exp < next {
|
|
|
|
next = exp
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return next
|
|
|
|
}
|
|
|
|
min(n.claims)
|
|
|
|
min(n.supports)
|
|
|
|
if next == Height(math.MaxInt32) {
|
|
|
|
next = n.height
|
|
|
|
}
|
|
|
|
return next
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
func (n *Node) bid() {
|
2018-07-14 07:10:23 +02:00
|
|
|
for {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
if n.best == nil || n.height >= n.best.expireAt() {
|
|
|
|
n.best, n.tookover = nil, n.height
|
|
|
|
updateActiveHeights(n, n.claims, n.supports)
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
updateEffectiveAmounts(n.height, n.claims, n.supports)
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
c := findCandiadte(n.height, n.claims)
|
|
|
|
if equal(n.best, c) {
|
|
|
|
break
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
n.best, n.tookover = c, n.height
|
|
|
|
updateActiveHeights(n, n.claims, n.supports)
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
n.removed = nil
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
|
2018-08-15 04:50:42 +02:00
|
|
|
func updateEffectiveAmounts(ht Height, claims, supports List) {
|
2018-07-14 07:10:23 +02:00
|
|
|
for _, c := range claims {
|
|
|
|
c.EffAmt = 0
|
2018-08-15 04:50:42 +02:00
|
|
|
if !IsActiveAt(c, ht) {
|
2018-07-14 07:10:23 +02:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
c.EffAmt = c.Amt
|
|
|
|
for _, s := range supports {
|
2018-08-15 04:50:42 +02:00
|
|
|
if !IsActiveAt(s, ht) || s.ID != c.ID {
|
2018-07-14 07:10:23 +02:00
|
|
|
continue
|
|
|
|
}
|
|
|
|
c.EffAmt += s.Amt
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-15 04:50:42 +02:00
|
|
|
func updateActiveHeights(n *Node, lists ...List) {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
for _, l := range lists {
|
|
|
|
for _, v := range l {
|
2018-08-15 04:37:59 +02:00
|
|
|
if v.ActiveAt < n.height {
|
|
|
|
continue
|
|
|
|
}
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
v.ActiveAt = v.Accepted + calDelay(n.height, n.tookover)
|
2018-08-15 04:37:59 +02:00
|
|
|
if v.ActiveAt < n.height {
|
|
|
|
v.ActiveAt = n.height
|
|
|
|
}
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-08-15 04:50:42 +02:00
|
|
|
func findCandiadte(ht Height, claims List) *Claim {
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
var c *Claim
|
2018-07-14 07:10:23 +02:00
|
|
|
for _, v := range claims {
|
|
|
|
switch {
|
2018-08-15 04:50:42 +02:00
|
|
|
case !IsActiveAt(v, ht):
|
2018-07-14 07:10:23 +02:00
|
|
|
continue
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
case c == nil:
|
|
|
|
c = v
|
|
|
|
case v.EffAmt > c.EffAmt:
|
|
|
|
c = v
|
|
|
|
case v.EffAmt < c.EffAmt:
|
|
|
|
continue
|
|
|
|
case v.Accepted < c.Accepted:
|
|
|
|
c = v
|
|
|
|
case v.Accepted > c.Accepted:
|
|
|
|
continue
|
|
|
|
case outPointLess(c.OutPoint, v.OutPoint):
|
|
|
|
c = v
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
}
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
return c
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
func calDelay(curr, tookover Height) Height {
|
|
|
|
delay := (curr - tookover) / paramActiveDelayFactor
|
|
|
|
if delay > paramMaxActiveDelay {
|
|
|
|
return paramMaxActiveDelay
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
return delay
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
|
|
|
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
// Hash calculates the Hash value based on the OutPoint and when it tookover.
|
|
|
|
func (n *Node) Hash() *chainhash.Hash {
|
|
|
|
if n.best == nil {
|
|
|
|
return nil
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|
wip: a few updates so far.
(the code is not cleaned up yet, especially DB related part)
1. Separate claim nodes from the Trie to NodeMgr (Node Manager).
The Trie is mainly responsible for rsolving the MerkleHash.
The Node Manager, which manages all the claim nodes implements
KeyValue interface.
type KeyValue interface{
Get(Key) error
Set(Key, Value) error
}
When the Trie traverses to the Value node, it consults the KV
with the prefix to get the value, which is the Hash of Best Claim.
2. Versioined/Snapshot based/Copy-on-Write Merkle Trie.
Every resolved trie node is saved to the TrieDB (leveldb) with it's
Hash as Key and content as Value.
The content has the following format:
Char (1B) Hash (32B) {0 to 256 entries }
VHash (32B) (0 or 1 entry)
The nodes are immutable and content(hash)-addressable. This gives
the benefit of de-dup for free.
3. The NodeManager implements Replay, and can construct any past state.
After experimentng on Memento vs Replay with the real dataset on the
mainnet. I decided to go with Replay (at least for now) for a few reasons:
a. Concurrency and usability.
In the real world scenario, the ClaimTrie is always working on the
Tip of the chain to accept Claim Script, update its own state and
generate the Hash.
On the other hand, most of the client requests are interested in
the past state with minimal number of confirmations required.
With Memento, the ClaimTrie has to either:
a. Pin down the node, and likely the ClaimTrie itself as well, as
it doesn't have the latest state (in terms of the whole Trie) to
resolve the Hash. Undo the changes and redo the changes after
serving the request.
b. Copy the current state of the node and rollback that node to
serve the request in the background.
With Replay, the ClaimTrie can simply spin a background task
without any pause.
The history of the nodes is immutable and read-only, so there is
contention in reconstructing a node.
b. Negligible performance difference.
Most of the nodes only have few commands to playback.
The time to playback is negligible, and will be dominated by the
I/O if the node was flushed to the disk.
c. Simplicity.
Implementing undo saves more changes of states during
the process, and has to pay much more attention to the bidding rules.
2018-08-03 07:15:08 +02:00
|
|
|
return calNodeHash(n.best.OutPoint, n.tookover)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (n *Node) String() string {
|
|
|
|
return nodeToString(n)
|
2018-07-14 07:10:23 +02:00
|
|
|
}
|