use of org.aion.rlp.Value in project aion by aionnetwork.
the class TrieImpl method delete.
private Object delete(Object node, byte[] key) {
if (key.length == 0 || isEmptyNode(node)) {
return "";
}
// New node
Value currentNode = this.getNode(node);
if (currentNode == null) {
throw new RuntimeException("Invalid Trie state, missing node " + new Value(node));
}
// Check for "special" 2 slice type node
if (currentNode.length() == PAIR_SIZE) {
// Decode the key
byte[] k = unpackToNibbles(currentNode.get(0).asBytes());
Object v = currentNode.get(1).asObj();
// Matching key pair (ie. there's already an object with this key)
if (Arrays.equals(k, key)) {
return "";
} else if (Arrays.equals(copyOfRange(key, 0, k.length), k)) {
Object hash = this.delete(v, copyOfRange(key, k.length, key.length));
Value child = this.getNode(hash);
Object newNode;
if (child.length() == PAIR_SIZE) {
byte[] newKey = concatenate(k, unpackToNibbles(child.get(0).asBytes()));
newNode = new Object[] { packNibbles(newKey), child.get(1).asObj() };
} else {
newNode = new Object[] { currentNode.get(0), hash };
}
markRemoved(HashUtil.h256(currentNode.encode()));
return this.putToCache(newNode);
} else {
return node;
}
} else {
// Copy the current node over to a new node
Object[] itemList = copyNode(currentNode);
// Replace the first nibble in the key
itemList[key[0]] = this.delete(itemList[key[0]], copyOfRange(key, 1, key.length));
byte amount = -1;
for (byte i = 0; i < LIST_SIZE; i++) {
if (itemList[i] != "") {
if (amount == -1) {
amount = i;
} else {
amount = -2;
}
}
}
Object[] newNode = null;
if (amount == 16) {
newNode = new Object[] { packNibbles(new byte[] { 16 }), itemList[amount] };
} else if (amount >= 0) {
Value child = this.getNode(itemList[amount]);
if (child.length() == PAIR_SIZE) {
key = concatenate(new byte[] { amount }, unpackToNibbles(child.get(0).asBytes()));
newNode = new Object[] { packNibbles(key), child.get(1).asObj() };
} else if (child.length() == LIST_SIZE) {
newNode = new Object[] { packNibbles(new byte[] { amount }), itemList[amount] };
}
} else {
newNode = itemList;
}
if (!FastByteComparisons.equal(HashUtil.h256(getNode(newNode).encode()), HashUtil.h256(currentNode.encode()))) {
markRemoved(HashUtil.h256(currentNode.encode()));
}
return this.putToCache(newNode);
}
}
use of org.aion.rlp.Value in project aion by aionnetwork.
the class TrieImpl method get.
@Override
public byte[] get(byte[] key) {
synchronized (cache) {
byte[] k = binToNibbles(key);
Value c = new Value(this.get(this.root, k));
return c.asBytes();
}
}
use of org.aion.rlp.Value in project aion by aionnetwork.
the class TrieIterator method getNode.
private void getNode(byte[] node) {
Value currentNode = this.trie.getCache().get(node);
this.workNode(currentNode);
}
use of org.aion.rlp.Value in project aion by aionnetwork.
the class TrieImpl method insert.
/**
* Update or add the item inside a node.
*
* @return the updated node with rlp encoded
*/
private Object insert(Object node, byte[] key, Object value) {
if (key.length == 0) {
return value;
}
if (isEmptyNode(node)) {
Object[] newNode = new Object[] { packNibbles(key), value };
return this.putToCache(newNode);
}
Value currentNode = this.getNode(node);
if (currentNode == null) {
throw new RuntimeException("Invalid Trie state, missing node " + new Value(node));
}
// Check for "special" 2 slice type node
if (currentNode.length() == PAIR_SIZE) {
// Decode the key
byte[] k = unpackToNibbles(currentNode.get(0).asBytes());
Object v = currentNode.get(1).asObj();
// Matching key pair (ie. there's already an object with this key)
if (Arrays.equals(k, key)) {
Object[] newNode = new Object[] { packNibbles(key), value };
return this.putToCache(newNode);
}
Object newHash;
int matchingLength = matchingNibbleLength(key, k);
if (matchingLength == k.length) {
// Insert the hash, creating a new node
byte[] remainingKeypart = copyOfRange(key, matchingLength, key.length);
newHash = this.insert(v, remainingKeypart, value);
} else {
// Expand the 2 length slice to a 17 length slice
// Create two nodes to putToCache into the new 17 length node
Object oldNode = this.insert("", copyOfRange(k, matchingLength + 1, k.length), v);
Object newNode = this.insert("", copyOfRange(key, matchingLength + 1, key.length), value);
// Create an expanded slice
Object[] scaledSlice = emptyStringSlice(17);
// Set the copied and new node
scaledSlice[k[matchingLength]] = oldNode;
scaledSlice[key[matchingLength]] = newNode;
newHash = this.putToCache(scaledSlice);
}
markRemoved(HashUtil.h256(currentNode.encode()));
if (matchingLength == 0) {
// End of the chain, return
return newHash;
} else {
Object[] newNode = new Object[] { packNibbles(copyOfRange(key, 0, matchingLength)), newHash };
return this.putToCache(newNode);
}
} else {
// Copy the current node over to the new node
Object[] newNode = copyNode(currentNode);
// Replace the first nibble in the key
newNode[key[0]] = this.insert(currentNode.get(key[0]).asObj(), copyOfRange(key, 1, key.length), value);
if (!FastByteComparisons.equal(HashUtil.h256(getNode(newNode).encode()), HashUtil.h256(currentNode.encode()))) {
markRemoved(HashUtil.h256(currentNode.encode()));
if (!isEmptyNode(currentNode.get(key[0]))) {
markRemoved(currentNode.get(key[0]).asBytes());
}
}
return this.putToCache(newNode);
}
}
use of org.aion.rlp.Value in project aion by aionnetwork.
the class TrieImpl method scanTree.
public void scanTree(byte[] hash, ScanAction scanAction) {
synchronized (cache) {
Value node = this.getCache().get(hash);
if (node == null) {
throw new RuntimeException("Not found: " + Hex.toHexString(hash));
}
if (node.isList()) {
List<Object> siblings = node.asList();
if (siblings.size() == PAIR_SIZE) {
Value val = new Value(siblings.get(1));
if (val.isHashCode() && !hasTerminator((byte[]) siblings.get(0))) {
scanTree(val.asBytes(), scanAction);
}
} else {
for (int j = 0; j < LIST_SIZE; ++j) {
Value val = new Value(siblings.get(j));
if (val.isHashCode()) {
scanTree(val.asBytes(), scanAction);
}
}
}
scanAction.doOnNode(hash, node);
}
}
}
Aggregations