2019-04-18 03:26:56 +00:00
|
|
|
package main
|
|
|
|
|
|
|
|
import "testing"
|
2019-04-18 03:54:28 +00:00
|
|
|
import "log"
|
2019-04-18 03:26:56 +00:00
|
|
|
import "github.com/cbergoon/merkletree"
|
|
|
|
|
|
|
|
func TestBasicGood(t *testing.T) {
|
|
|
|
// Pre-compute expected tree
|
|
|
|
var list []merkletree.Content
|
|
|
|
list = append(list, TestContent{x: "1"})
|
|
|
|
list = append(list, TestContent{x: "2"})
|
|
|
|
list = append(list, TestContent{x: "3"})
|
|
|
|
list = append(list, TestContent{x: "4"})
|
|
|
|
mt, _ := merkletree.NewTree(list)
|
|
|
|
trustedRoot := toHex(mt.MerkleRoot())
|
|
|
|
|
|
|
|
// Local node setup, partial
|
|
|
|
// Assume has access to trustedRoot
|
|
|
|
var contents []merkletree.Content
|
|
|
|
contents = append(contents, TestContent{x: "1"})
|
|
|
|
contents = append(contents, TestContent{x: "2"})
|
|
|
|
contents = append(contents, TestContent{x: "3"})
|
|
|
|
|
|
|
|
// Byzantine case, currently sending nothing
|
|
|
|
// TODO: Since haves is empty it should return full contents?
|
|
|
|
// XXX: Doesn't make sense to have tree hardcoded in other code
|
|
|
|
var haves []string
|
|
|
|
untrustedPayloads := pull("good", trustedRoot, haves)
|
|
|
|
content := TestContent{x: untrustedPayloads[0]}
|
|
|
|
contents = append(contents, content)
|
|
|
|
|
|
|
|
// XXX: is there no way to append to tree?
|
|
|
|
untrusted := mt
|
|
|
|
_ = untrusted.RebuildTreeWith(contents)
|
|
|
|
untrustedRoot := toHex(untrusted.MerkleRoot())
|
|
|
|
|
|
|
|
expect := (untrustedRoot == trustedRoot)
|
|
|
|
if !expect {
|
|
|
|
t.Errorf("Good basic: Untrusted root %s and trusted root %s should match", untrustedRoot, trustedRoot)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestBasicByzantine(t *testing.T) {
|
|
|
|
// Pre-compute expected tree
|
|
|
|
var list []merkletree.Content
|
|
|
|
list = append(list, TestContent{x: "1"})
|
|
|
|
list = append(list, TestContent{x: "2"})
|
|
|
|
list = append(list, TestContent{x: "3"})
|
|
|
|
list = append(list, TestContent{x: "4"})
|
|
|
|
mt, _ := merkletree.NewTree(list)
|
|
|
|
trustedRoot := toHex(mt.MerkleRoot())
|
|
|
|
|
|
|
|
// Local node setup, partial
|
|
|
|
// Assume has access to trustedRoot
|
|
|
|
var contents []merkletree.Content
|
|
|
|
contents = append(contents, TestContent{x: "1"})
|
|
|
|
contents = append(contents, TestContent{x: "2"})
|
|
|
|
contents = append(contents, TestContent{x: "3"})
|
|
|
|
|
|
|
|
// Byzantine case, currently sending nothing
|
|
|
|
// TODO: Since haves is empty it should return full contents?
|
|
|
|
// XXX: Doesn't make sense to have tree hardcoded in other code
|
|
|
|
var haves []string
|
|
|
|
untrustedPayloads := pull("byzantine", trustedRoot, haves)
|
|
|
|
content := TestContent{x: untrustedPayloads[0]}
|
|
|
|
contents = append(contents, content)
|
|
|
|
|
|
|
|
// XXX: is there no way to append to tree?
|
|
|
|
untrusted := mt
|
|
|
|
_ = untrusted.RebuildTreeWith(contents)
|
|
|
|
untrustedRoot := toHex(untrusted.MerkleRoot())
|
|
|
|
|
|
|
|
expect := (untrustedRoot != trustedRoot)
|
|
|
|
if !expect {
|
|
|
|
t.Errorf("Byzantine basic: Untrusted root %s and trusted root %s shouldn't match", untrustedRoot, trustedRoot)
|
|
|
|
}
|
2019-04-18 03:54:28 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Here's what I want to test:
|
|
|
|
// Full tree: C->A; C->B; B->h(3); B->h(4); h(4)->4
|
|
|
|
// Trusted root: C
|
|
|
|
// Get from untrusted root: A, h(3) ("small") and 4 ("big"). Through these pieces of data we can verify.
|
|
|
|
// What does this mean if you have or don't have e.g. A branch? (which can hide a lot of data)
|
|
|
|
// I guess this is difference between thin and full client.
|
|
|
|
// See: https://bitcoin.stackexchange.com/questions/50674/why-is-the-full-merkle-path-needed-to-verify-a-transaction
|
|
|
|
//
|
2019-04-18 05:23:48 +00:00
|
|
|
// Next question: how do we specify path? Index [0 1], etc.
|
2019-04-18 03:54:28 +00:00
|
|
|
// Lets try GetMerklePath
|
2019-04-18 05:23:48 +00:00
|
|
|
// Not clear exactly how it maps or changes as we rebuild tree but ok for now
|
|
|
|
// Now, how can we do partial rebuild here?
|
|
|
|
//
|
|
|
|
// As a client, I say I have A [x, y], h(3) [x, y]. And a trusted root hash.
|
|
|
|
// So I guess there are two ways the query can go: for a specific piece of data (how know?) and diff.
|
|
|
|
// Lets graph: https://notes.status.im/MLGgpdgqRzeyTqVWkl7gjg#
|
|
|
|
|
|
|
|
// Can use Whisper/mailservers as well for compatibility before Swarm Feeds ready, boom new topic
|
2019-04-18 03:54:28 +00:00
|
|
|
|
|
|
|
func printPath(mt merkletree.MerkleTree, item merkletree.Content, name string) {
|
|
|
|
_, x, err := mt.GetMerklePath(item)
|
|
|
|
log.Println("Path to", name, x)
|
|
|
|
if err != nil {
|
|
|
|
log.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-04-18 05:23:48 +00:00
|
|
|
// 4 nodes
|
|
|
|
// 2019/04/18 11:49:07 Path to 1 [1 1]
|
|
|
|
// 2019/04/18 11:49:07 Path to 2 [0 1]
|
|
|
|
// 2019/04/18 11:49:07 Path to 3 [1 0]
|
|
|
|
// 2019/04/18 11:49:07 Path to 4 [0 0]
|
|
|
|
|
|
|
|
// 5 nodes
|
|
|
|
// 2019/04/18 11:54:36 Path to 1 [1 1 1]
|
|
|
|
// 2019/04/18 11:54:36 Path to 2 [0 1 1]
|
|
|
|
// 2019/04/18 11:54:36 Path to 3 [1 0 1]
|
|
|
|
// 2019/04/18 11:54:36 Path to 4 [0 0 1]
|
|
|
|
// 2019/04/18 11:54:36 Path to 5 [1 1 0]
|
|
|
|
|
|
|
|
// XXX: Probably need a less naive implementation
|
|
|
|
// Yellow paper quote:
|
|
|
|
// > The core of the trie, and its sole requirement in termsof the protocol specification,
|
|
|
|
// > is to provide a single value that identifies a given set of key-value pairs, which may be
|
|
|
|
// > either a 32-byte sequence or the empty byte sequence.
|
|
|
|
//
|
|
|
|
// So let's start there and happily rebuild
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2019-04-18 03:54:28 +00:00
|
|
|
func TestPartialVerification(t *testing.T) {
|
|
|
|
// Pre-compute expected tree
|
|
|
|
|
|
|
|
// XXX: Have you heard of for loops
|
|
|
|
var list []merkletree.Content
|
|
|
|
item1 := TestContent{x: "1"}
|
|
|
|
item2 := TestContent{x: "2"}
|
|
|
|
item3 := TestContent{x: "3"}
|
|
|
|
item4 := TestContent{x: "4"}
|
|
|
|
item5 := TestContent{x: "5"}
|
|
|
|
|
|
|
|
list = append(list, item1)
|
|
|
|
list = append(list, item2)
|
|
|
|
list = append(list, item3)
|
|
|
|
list = append(list, item4)
|
|
|
|
list = append(list, item5)
|
|
|
|
|
|
|
|
mt, _ := merkletree.NewTree(list)
|
|
|
|
//trustedRoot := toHex(mt.MerkleRoot())
|
|
|
|
|
|
|
|
printPath(*mt, item1, "1")
|
|
|
|
printPath(*mt, item2, "2")
|
|
|
|
printPath(*mt, item3, "3")
|
|
|
|
printPath(*mt, item4, "4")
|
|
|
|
printPath(*mt, item5, "5")
|
|
|
|
|
2019-04-18 05:23:48 +00:00
|
|
|
// print tree
|
|
|
|
log.Print("TREE", mt.String())
|
2019-04-18 03:54:28 +00:00
|
|
|
|
|
|
|
// // Local node setup, partial
|
|
|
|
// // Assume has access to trustedRoot
|
|
|
|
// var contents []merkletree.Content
|
|
|
|
// contents = append(contents, TestContent{x: "1"})
|
|
|
|
// contents = append(contents, TestContent{x: "2"})
|
|
|
|
// contents = append(contents, TestContent{x: "3"})
|
|
|
|
|
|
|
|
// // Byzantine case, currently sending nothing
|
|
|
|
// // TODO: Since haves is empty it should return full contents?
|
|
|
|
// // XXX: Doesn't make sense to have tree hardcoded in other code
|
|
|
|
// var haves []string
|
|
|
|
// untrustedPayloads := pull("good", trustedRoot, haves)
|
|
|
|
// content := TestContent{x: untrustedPayloads[0]}
|
|
|
|
// contents = append(contents, content)
|
|
|
|
|
|
|
|
// // XXX: is there no way to append to tree?
|
|
|
|
// untrusted := mt
|
|
|
|
// _ = untrusted.RebuildTreeWith(contents)
|
|
|
|
// untrustedRoot := toHex(untrusted.MerkleRoot())
|
|
|
|
|
|
|
|
// expect := (untrustedRoot == trustedRoot)
|
|
|
|
// if !expect {
|
|
|
|
// t.Errorf("Good basic: Untrusted root %s and trusted root %s should match", untrustedRoot, trustedRoot)
|
|
|
|
// }
|
2019-04-18 03:26:56 +00:00
|
|
|
}
|