Search in sources :

Example 6 with Value

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);
    }
}
Also used : Value(org.aion.rlp.Value)

Example 7 with Value

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();
    }
}
Also used : Value(org.aion.rlp.Value)

Example 8 with Value

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);
}
Also used : Value(org.aion.rlp.Value)

Example 9 with Value

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);
    }
}
Also used : Value(org.aion.rlp.Value)

Example 10 with Value

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);
        }
    }
}
Also used : Value(org.aion.rlp.Value)

Aggregations

Value (org.aion.rlp.Value)11 ByteArrayWrapper (org.aion.base.util.ByteArrayWrapper)2 RLPItem (org.aion.rlp.RLPItem)1 RLPList (org.aion.rlp.RLPList)1