use of org.aion.util.types.ByteArrayWrapper in project aion by aionnetwork.
the class Cache method commit.
private void commit(boolean flushCache) {
// Don't try to commit if it isn't dirty
if ((dataSource == null) || !this.isDirty) {
// clear cache when flush requested
if (flushCache) {
this.nodes.clear();
}
return;
}
Map<byte[], byte[]> batch = new HashMap<>();
List<byte[]> deleteBatch = new ArrayList<>();
for (ByteArrayWrapper nodeKey : this.nodes.keySet()) {
Node node = this.nodes.get(nodeKey);
if (node == null || node.isDirty()) {
byte[] value;
if (node != null) {
node.setDirty(false);
value = node.getValue().encode();
} else {
value = null;
}
byte[] key = nodeKey.toBytes();
batch.put(key, value);
}
}
for (ByteArrayWrapper removedNode : removedNodes) {
deleteBatch.add(removedNode.toBytes());
}
this.dataSource.putBatch(batch);
this.dataSource.deleteBatch(deleteBatch);
this.isDirty = false;
if (flushCache) {
this.nodes.clear();
}
this.removedNodes.clear();
}
use of org.aion.util.types.ByteArrayWrapper in project aion by aionnetwork.
the class TrieImpl method serialize.
@VisibleForTesting
public byte[] serialize() {
lock.lock();
try {
Map<ByteArrayWrapper, Node> map = getCache().getNodes();
int keysTotalSize = 0;
int valsTotalSize = 0;
Set<ByteArrayWrapper> keys = map.keySet();
for (ByteArrayWrapper key : keys) {
Node node = map.get(key);
if (node == null) {
continue;
}
byte[] keyBytes = key.toBytes();
keysTotalSize += keyBytes.length;
byte[] valBytes = node.getValue().getData();
valsTotalSize += valBytes.length + calcElementPrefixSize(valBytes);
}
byte[] root = null;
try {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(this.getRoot());
root = b.toByteArray();
root = RLP.encodeElement(root);
} catch (IOException e) {
e.printStackTrace();
}
byte[] keysHeader = RLP.encodeLongElementHeader(keysTotalSize);
byte[] valsHeader = RLP.encodeListHeader(valsTotalSize);
byte[] listHeader = RLP.encodeListHeader(keysTotalSize + keysHeader.length + valsTotalSize + valsHeader.length + root.length);
byte[] rlpData = new byte[keysTotalSize + keysHeader.length + valsTotalSize + valsHeader.length + listHeader.length + root.length];
// copy headers:
// [ rlp_list_header, rlp_keys_header, rlp_keys, rlp_vals_header,
// rlp_val]
System.arraycopy(listHeader, 0, rlpData, 0, listHeader.length);
System.arraycopy(keysHeader, 0, rlpData, listHeader.length, keysHeader.length);
System.arraycopy(valsHeader, 0, rlpData, (listHeader.length + keysHeader.length + keysTotalSize), valsHeader.length);
System.arraycopy(root, 0, rlpData, (listHeader.length + keysHeader.length + keysTotalSize + valsTotalSize + valsHeader.length), root.length);
int k_1 = 0;
int k_2 = 0;
for (ByteArrayWrapper key : keys) {
Node node = map.get(key);
if (node == null) {
continue;
}
// TODO: make internal wrapper operation
System.arraycopy(key.toBytes(), 0, rlpData, (listHeader.length + keysHeader.length + k_1), key.length());
k_1 += key.length();
byte[] valBytes = RLP.encodeElement(node.getValue().getData());
System.arraycopy(valBytes, 0, rlpData, listHeader.length + keysHeader.length + keysTotalSize + valsHeader.length + k_2, valBytes.length);
k_2 += valBytes.length;
}
return rlpData;
} finally {
lock.unlock();
}
}
use of org.aion.util.types.ByteArrayWrapper in project aion by aionnetwork.
the class SyncMgr method validateAndAddBlocks.
/**
* @param _nodeIdHashcode int
* @param _displayId String
* @param _bodies List<byte[]> Assemble and validate blocks batch and add batch to import queue
* from network response blocks bodies
*/
public void validateAndAddBlocks(int _nodeIdHashcode, String _displayId, final List<SharedRLPList> _bodies) {
if (_bodies == null)
return;
log.debug("<received-bodies size={} node={}>", _bodies.size(), _displayId);
// the requests are made such that the size varies to better map headers to bodies
ByteArrayWrapper firstNodeRoot = ByteArrayWrapper.wrap(BlockUtil.getTxTrieRootFromUnsafeSource(_bodies.get(0)));
List<BlockHeader> headers = syncHeaderRequestManager.matchAndDropHeaders(_nodeIdHashcode, _bodies.size(), firstNodeRoot);
if (headers == null) {
log.debug("<assemble-and-validate-blocks could not match headers for node={} size={} txTrieRoot={}>", _displayId, _bodies.size(), firstNodeRoot);
return;
}
// assemble batch
List<Block> blocks = new ArrayList<>(_bodies.size());
Iterator<BlockHeader> headerIt = headers.iterator();
Iterator<SharedRLPList> bodyIt = _bodies.iterator();
while (headerIt.hasNext() && bodyIt.hasNext()) {
Block block = BlockUtil.newBlockWithHeaderFromUnsafeSource(headerIt.next(), (SharedRLPList) bodyIt.next().get(0));
if (block == null) {
log.debug("<assemble-and-validate-blocks node={} size={}>", _displayId, _bodies.size());
break;
} else {
blocks.add(block);
}
}
int m = blocks.size();
if (m == 0) {
return;
}
log.debug("<assembled-blocks from={} size={} node={}>", blocks.get(0).getNumber(), blocks.size(), _displayId);
// add batch
syncExecutors.execute(() -> filterBlocks(new BlocksWrapper(_nodeIdHashcode, _displayId, blocks)));
}
use of org.aion.util.types.ByteArrayWrapper in project aion by aionnetwork.
the class ResponseTrieData method decode.
/**
* Decodes a message into a trie node response.
*
* @param message a {@code byte} array representing a response to a trie node request.
* @return the decoded trie node response
* @implNote The decoder must return {@code null} if any of the component values are {@code
* null} or invalid.
*/
public static ResponseTrieData decode(final byte[] message) {
if (message == null || message.length == 0) {
return null;
} else {
RLPList list = RLP.decode2(message);
if (list.get(0) instanceof RLPList) {
list = (RLPList) list.get(0);
} else {
return null;
}
if (list.size() != TRIE_DATA_RESPONSE_COMPONENTS) {
return null;
} else {
// decode the key
byte[] hash = list.get(0).getRLPData();
if (hash.length != HASH_SIZE) {
return null;
}
// decode the value
byte[] value = list.get(1).getRLPData();
if (value.length == 0) {
return null;
}
// decode the referenced nodes
RLPElement referenced = list.get(2);
if (!(referenced instanceof RLPList)) {
return null;
}
Map<ByteArrayWrapper, byte[]> nodes = decodeReferencedNodes((RLPList) referenced);
if (nodes == null) {
return null;
}
// decode the db type
byte[] type = list.get(3).getRLPData();
DatabaseType dbType;
try {
dbType = DatabaseType.valueOf(new String(type));
} catch (IllegalArgumentException e) {
return null;
}
return new ResponseTrieData(ByteArrayWrapper.wrap(hash), value, nodes, dbType);
}
}
}
use of org.aion.util.types.ByteArrayWrapper in project aion by aionnetwork.
the class ResponseTrieData method decodeReferencedNodes.
/**
* Decodes the list of key-value pair encodings into a map representation.
*
* @return a map of all the key-value pair encodings
*/
private static Map<ByteArrayWrapper, byte[]> decodeReferencedNodes(RLPList referenced) {
if (referenced.isEmpty()) {
return Collections.emptyMap();
}
RLPList current;
byte[] hash, value;
Map<ByteArrayWrapper, byte[]> nodes = new HashMap<>();
for (RLPElement pair : referenced) {
if (!(pair instanceof RLPList)) {
return null;
}
current = (RLPList) pair;
// decode the key
hash = current.get(0).getRLPData();
if (hash.length != HASH_SIZE) {
return null;
}
// decode the value
value = current.get(1).getRLPData();
if (value.length == 0) {
return null;
}
nodes.put(ByteArrayWrapper.wrap(hash), value);
}
return nodes;
}
Aggregations