package peergos.server.tests; import org.junit.*; import peergos.server.storage.*; import peergos.shared.crypto.asymmetric.*; import peergos.shared.io.ipfs.multihash.*; import peergos.shared.merklebtree.*; import peergos.shared.storage.*; import peergos.shared.util.*; import java.io.*; import java.util.*; import java.util.concurrent.*; public class MerkleBtree { public RAMStorage createStorage() { return new RAMStorage(); } public CompletableFuture<MerkleBTree> createTree(PublicSigningKey user) throws IOException { return createTree(user, new RAMStorage()); } public PublicSigningKey createUser() { return PublicSigningKey.createNull(); } public CompletableFuture<MerkleBTree> createTree(PublicSigningKey user, ContentAddressedStorage dht) throws IOException { return MerkleBTree.create(user, MaybeMultihash.EMPTY(), dht); } public Multihash hash(byte[] in) { return new Multihash(Multihash.Type.sha2_256, RAMStorage.hash(in)); } @Test public void basic() throws Exception { PublicSigningKey user = createUser(); MerkleBTree tree = createTree(user).get(); byte[] key1 = new byte[]{0, 1, 2, 3}; Multihash value1 = hash(new byte[]{1, 1, 1, 1}); tree.put(user, key1, value1).get(); MaybeMultihash res1 = tree.get(key1).get(); if (!res1.get().equals(value1)) throw new IllegalStateException("Results not equal"); } @Test public void basic2() throws Exception { PublicSigningKey user = createUser(); RAMStorage dht = createStorage(); MerkleBTree tree = createTree(user, dht).get(); for (int i=0; i < 16; i++) { byte[] key1 = new byte[]{0, 1, 2, (byte)i}; Multihash value1 = hash(new byte[]{1, 1, 1, (byte)i}); tree.put(user, key1, value1).get(); MaybeMultihash res1 = tree.get(key1).get(); if (! res1.get().equals(value1)) throw new IllegalStateException("Results not equal"); } if (tree.root.keys.size() != 2) throw new IllegalStateException("New root should have two children!"); } @Test public void overwriteValue() throws Exception { PublicSigningKey user = createUser(); MerkleBTree tree = createTree(user).get(); byte[] key1 = new byte[]{0, 1, 2, 3}; Multihash value1 = hash(new byte[]{1, 1, 1, 1}); tree.put(user, key1, value1); MaybeMultihash res1 = tree.get(key1).get(); if (! res1.get().equals(value1)) throw new IllegalStateException("Results not equal"); Multihash value2 = hash(new byte[]{2, 2, 2, 2}); tree.put(user, key1, value2); MaybeMultihash res2 = tree.get(key1).get(); if (! res2.get().equals(value2)) throw new IllegalStateException("Results not equal"); } // @Test public void huge() throws Exception { PublicSigningKey user = createUser(); MerkleBTree tree = createTree(user).get(); long t1 = System.currentTimeMillis(); for (int i=0; i < 1000000; i++) { byte[] key1 = new byte[]{0, 1, 2, (byte)i}; Multihash value1 = hash(new byte[]{1, 1, 1, (byte)i}); tree.put(user, key1, value1).get(); MaybeMultihash res1 = tree.get(key1).get(); if (! res1.get().equals(value1)) throw new IllegalStateException("Results not equal"); } long t2 = System.currentTimeMillis(); for (int i=0; i < 1000000; i++) { byte[] key1 = new byte[]{0, 1, 2, (byte)i}; byte[] value1 = new byte[]{1, 1, 1, (byte)i}; MaybeMultihash res1 = tree.get(key1).get(); if (! res1.get().equals(hash(value1))) throw new IllegalStateException("Results not equal"); } System.out.printf("Put+get rate = %f /s\n", 1000000.0 / (t2 - t1) * 1000); ((RAMStorage)tree.storage).clear(); } @Test public void random() throws Exception { PublicSigningKey user = createUser(); MerkleBTree tree = createTree(user).get(); int keylen = 32; long t1 = System.currentTimeMillis(); Random r = new Random(1); int lim = 140000; for (int i = 0; i < lim; i++) { if (i % (lim/10) == 0) System.out.println((10*i/lim)+"0 %"); byte[] key1 = new byte[keylen]; r.nextBytes(key1); byte[] value1Raw = new byte[keylen]; r.nextBytes(value1Raw); Multihash value1 = hash(value1Raw); tree.put(user, key1, value1).get(); MaybeMultihash res1 = tree.get(key1).get(); if (! res1.get().equals(value1)) throw new IllegalStateException("Results not equal"); } long t2 = System.currentTimeMillis(); System.out.printf("Put+get rate = %f /s\n", (double)lim / (t2 - t1) * 1000); ((RAMStorage)tree.storage).clear(); } // @Test public void delete() throws Exception { PublicSigningKey user = createUser(); MerkleBTree tree = createTree(user).get(); int keylen = 32; Random r = new Random(1); SortedSet<ByteArrayWrapper> keys = new TreeSet<>(); int lim = 10000; for (int i = 0; i < lim; i++) { if (i % (lim/10) == 0) System.out.println((10*i/lim)+"0 % of building"); byte[] key1 = new byte[keylen]; keys.add(new ByteArrayWrapper(key1)); r.nextBytes(key1); byte[] value1Raw = new byte[keylen]; r.nextBytes(value1Raw); Multihash value1 = hash(value1Raw); MaybeMultihash existing = tree.get(key1).get(); if (existing.isPresent()) throw new IllegalStateException("Already present!"); tree.put(user, key1, value1).get(); MaybeMultihash res1 = tree.get(key1).get(); if (! res1.get().equals(value1)) throw new IllegalStateException("Results not equal"); } ByteArrayWrapper[] keysArray = keys.toArray(new ByteArrayWrapper[keys.size()]); long t1 = System.currentTimeMillis(); for (int i = 0; i < lim; i++) { if (i % (lim / 10) == 0) System.out.println((10 * i / lim) + "0 % of deleting"); int size = tree.size().get(); if (size != lim) throw new IllegalStateException("Missing keys from tree!"); ByteArrayWrapper key = keysArray[r.nextInt(keysArray.length)]; MaybeMultihash value = tree.get(key.data).get(); if (! value.isPresent()) throw new IllegalStateException("Key not present!"); tree.delete(user, key.data).get(); if (tree.get(key.data).get().isPresent()) throw new IllegalStateException("Key still present!"); tree.put(user, key.data, value.get()).get(); } long t2 = System.currentTimeMillis(); System.out.printf("size+get+delete+get+put rate = %f /s\n", (double)lim / (t2 - t1) * 1000); ((RAMStorage)tree.storage).clear(); } @Test public void storageSize() throws Exception { PublicSigningKey user = createUser(); MerkleBTree tree = createTree(user).get(); int keylen = 32; Random r = new Random(1); SortedSet<ByteArrayWrapper> keys = new TreeSet<>(); // make a 3 node tree int lim = 22; for (int i = 0; i < lim; i++) { if (i % (lim/10) == 0) System.out.println((10*i/lim)+"0 % of building"); byte[] key1 = toLittleEndian(i); keys.add(new ByteArrayWrapper(key1)); byte[] value1Raw = new byte[keylen]; r.nextBytes(value1Raw); Multihash value1 = hash(value1Raw); tree.put(user, key1, value1).get(); MaybeMultihash res1 = tree.get(key1).get(); if (! res1.get().equals(value1)) throw new IllegalStateException("Results not equal"); } int size = ((RAMStorage)tree.storage).size(); if (size != 30) throw new IllegalStateException("Storage size != 3"); long t1 = System.currentTimeMillis(); for (int i = 16; i < 22; i++) { byte[] key = toLittleEndian(i); MaybeMultihash value = tree.get(key).get(); if (! value.isPresent()) throw new IllegalStateException("Key not present!"); tree.delete(user, key).get(); if (tree.get(key).get().isPresent()) throw new IllegalStateException("Key still present!"); } long t2 = System.currentTimeMillis(); System.out.printf("size+get+delete+get+put rate = %f /s\n", (double)lim / (t2 - t1) * 1000); ((RAMStorage)tree.storage).clear(); } private static byte[] toLittleEndian(int x) { byte[] res = new byte[4]; for (int i=0; i < 4; i++) res[i] = (byte) (x >> 8*i); return res; } }