diff --git a/.classpath b/.classpath new file mode 100644 index 0000000000..be8c6f5d59 --- /dev/null +++ b/.classpath @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.gitignore b/.gitignore index de3a47420d..96c40d9183 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ native/linux/blake2b/libblake2b.so # ci */report + +.ant-targets-build.xml +modTxPoolImpl/native/ diff --git a/.gitmodules b/.gitmodules index cdb184d7c2..8ee41112c6 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "aion_fastvm"] path = aion_fastvm url = https://github.com/aionnetwork/aion_fastvm +[submodule "aion_api"] + path = aion_api + url = https://github.com/aionnetwork/aion_api diff --git a/.project b/.project new file mode 100644 index 0000000000..7fbe4c4d73 --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + aion0 + + + + + + org.eclipse.jdt.core.javabuilder + + + + + + org.eclipse.jdt.core.javanature + + diff --git a/Jenkinsfile b/Jenkinsfile index 134e1de9ec..d88e6991d6 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -29,7 +29,7 @@ pipeline { stage('Archive build output') { when { - expression { GIT_BRANCH == 'master' } + expression { GIT_BRANCH == 'master' || GIT_BRANCH == 'dev' } } steps { archiveArtifacts artifacts: 'aion-v*.tar.bz2' diff --git a/README.md b/README.md index ad5301d771..f3c47b1559 100644 --- a/README.md +++ b/README.md @@ -8,108 +8,23 @@ The [Aion White Papers](https://aion.network/whitepapers.html) provides more det This repository contains the main kernel implementation and releases for the Aion network. -## System Requirements +### System Requirements * **Ubuntu 16.04** or a later version -## Build the Aion network +### Documentation -Please see the details in this wiki page [Build your Aion network](https://github.com/aionnetwork/aion/wiki/Build-your-Aion-network). +Please refer to the details in the [Build Your Aion Network](https://github.com/aionnetwork/aion/wiki/Build-your-Aion-network) wiki to determine how to start setting up and building your Aion Network. -## Aion Installation +Please refer to the [Installation](https://github.com/aionnetwork/aion/wiki/Installation) wiki for the guide on installing the kernel prior to configuration and launching the kernel. -1. Download the latest Aion kernel release from the [releases page](https://github.com/aionnetwork/aion/releases). +Please refer to [Aion Network Configuration](https://github.com/aionnetwork/aion/wiki/Aion-Network-Configuration) wiki to set up your desired network configuration for the kernel as well as how to launch the kernel. -2. Unarchive the downloaded file by right clicking on it and selecting `Extract Here` from the drop-down menu. -The `aion` folder will be generated in the current folder. - -Alternatively, to extract the file contents, run in a terminal: - -``` -tar xvjf aion-{@version}.tar.bz2 -``` +The [Owner's Manual](https://github.com/aionnetwork/aion/wiki/Aion-Owner's-Manual) wiki will include further instructions and details on working with the kernel. -3. Navigate to the `aion` folder and continue by configuring the network: - -``` -cd aion -``` +Please refer to the [wiki pages](https://github.com/aionnetwork/aion/wiki) for further documentation on mining, using the Web3 API, command line options, etc. -## Aion Network Configuration - - - -To receive tokens for mining blocks, you first need to create an account using: - -``` -./aion.sh -a create -``` - -The [mining wiki](https://github.com/aionnetwork/aion/wiki/Internal-Miner) illustrates how to set this account to be able to receive tokens for mining. - -Now you are ready to start the kernel. - -**Optional:** - -Your kernel will have access to the seed nodes by default. Do not remove these nodes from the configuration. To include additional peers (e.g. friends that are also connected to the network) or get added by peers, update the `config.xml` by adding nodes using the **permanent peer id** (generated as shown below), IP and port of the computers you wish to connect to: - -``` - - - 0.0.0.0 - 30303 - - - p2p://PEER_ID@IP:PORT - - -``` - -**Note:** To allow peers to connect to you, you must also change your configuration IP from **127.0.0.1** to a public IP on your machine. If you are unsure about having a public IP, set it to **0.0.0.0**. - -To get a permanent peer id create a new configuration: - -``` -./aion.sh -c -``` - -This newly made configuration will not have access to seed nodes by default. In order to connect to seed nodes, you will need to edit the `config.xml` file by adding nodes as listed from [here](https://github.com/aionnetwork/aion/wiki/Aion-Seed-nodes): - -``` - - p2p://2da62542-999f-4405-bdb3-50d8c61bed61@52.237.31.69:30303 - p2p://c1f42646-279a-441e-bba7-bfebfc1eec63@52.179.100.107:30303 - p2p://0466a78b-814b-4a5d-844e-7054e48f0d28@191.232.176.213:30303 - p2p://f9ea8c08-6f2d-4e64-91a2-d7186d76e096@52.231.206.150:30303 - p2p://d9242b38-cf4e-4654-9995-2727fee3dd9d@13.95.218.95:30303 - -``` - -You are welcome to add other seed nodes (not solely restricted to what is shown above). - -## Launch Kernel - -In a terminal, from the aion directory, run: - -``` -./aion.sh -``` - -When the kernel starts up, you should see it trying to sync with the latest block. - -**Optional:** To check which peers you are connected to, open another terminal and run the command below: - -``` -netstat -antp | grep java -``` - -Please check the [owner's manual wiki](https://github.com/aionnetwork/aion/wiki/Aion-Owner's-Manual) for further instructions on working with the kernel. - -## Documentation - -Please check the [wiki pages](https://github.com/aionnetwork/aion/wiki) for further documentation on mining, using the Web3 API, command line options, etc. - -## Contact +### Contact [Aion Forum](https://forum.aion.network/) @@ -117,7 +32,7 @@ Please check the [wiki pages](https://github.com/aionnetwork/aion/wiki) for furt [Aion Reddit](https://www.reddit.com/r/AionNetwork/) -## License +### License Aion is released under the [LGPL-V3 license](https://github.com/aionnetwork/aion/blob/dev/LICENSE) diff --git a/aion.sh b/aion.sh index d87e12a5bc..5355050e4e 100755 --- a/aion.sh +++ b/aion.sh @@ -38,4 +38,4 @@ ARG=$@ chmod +x ./rt/bin/* env EVMJIT="-cache=1" ./rt/bin/java -Xms2g \ - -cp "./lib/*:./mod/*" org.aion.Aion "$@" + -cp "./lib/*:./lib/libminiupnp/*:./mod/*" org.aion.Aion "$@" diff --git a/aion_api b/aion_api new file mode 160000 index 0000000000..5472e51cd3 --- /dev/null +++ b/aion_api @@ -0,0 +1 @@ +Subproject commit 5472e51cd31c2186f5b39d75d110383c277ed48e diff --git a/aion_fastvm b/aion_fastvm index fec707cc06..b1852796d4 160000 --- a/aion_fastvm +++ b/aion_fastvm @@ -1 +1 @@ -Subproject commit fec707cc064845d575e3d8ac5f73cd3de142d09c +Subproject commit b1852796d44fb30b82153928a85f6d31411f56ab diff --git a/build.xml b/build.xml index ef8f774441..de427c1ecd 100644 --- a/build.xml +++ b/build.xml @@ -34,6 +34,7 @@ + @@ -44,7 +45,7 @@ - + @@ -76,6 +77,7 @@ + @@ -296,6 +298,7 @@ + @@ -331,7 +334,7 @@ - + @@ -391,6 +394,8 @@ + + diff --git a/eclipse/aion.userlibraries b/eclipse/aion.userlibraries new file mode 100644 index 0000000000..5f8debe86e --- /dev/null +++ b/eclipse/aion.userlibraries @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/lib/libminiupnp/libminiupnpc.so b/lib/libminiupnp/libminiupnpc.so new file mode 100755 index 0000000000..ef2dc3585d Binary files /dev/null and b/lib/libminiupnp/libminiupnpc.so differ diff --git a/lib/libminiupnp/miniupnpc_linux.jar b/lib/libminiupnp/miniupnpc_linux.jar new file mode 100644 index 0000000000..1a0e6b96b2 Binary files /dev/null and b/lib/libminiupnp/miniupnpc_linux.jar differ diff --git a/modAion/build.xml b/modAion/build.xml index 5581494464..7162c6822c 100644 --- a/modAion/build.xml +++ b/modAion/build.xml @@ -1,120 +1,124 @@ - - - - - - - + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - - - - - + + + + + - + - - - - - - - + + + + + + + diff --git a/modAionImpl/src/org/aion/zero/impl/blockchain/AionTxExecSummary.java b/modAion/src/org/aion/zero/types/AionTxExecSummary.java similarity index 97% rename from modAionImpl/src/org/aion/zero/impl/blockchain/AionTxExecSummary.java rename to modAion/src/org/aion/zero/types/AionTxExecSummary.java index f3564a8762..a9cae48fa8 100644 --- a/modAionImpl/src/org/aion/zero/impl/blockchain/AionTxExecSummary.java +++ b/modAion/src/org/aion/zero/types/AionTxExecSummary.java @@ -21,34 +21,26 @@ * Aion foundation. * ******************************************************************************/ -package org.aion.zero.impl.blockchain; - -import static java.util.Collections.emptyList; -import static java.util.Collections.emptyMap; -import static java.util.Collections.unmodifiableList; -import static java.util.Collections.unmodifiableMap; -import static org.aion.base.util.BIUtil.toBI; -import static org.apache.commons.lang3.ArrayUtils.isEmpty; -import static org.apache.commons.lang3.ArrayUtils.isNotEmpty; - -import java.math.BigInteger; -import java.util.*; +package org.aion.zero.types; import org.aion.base.type.Address; import org.aion.base.type.ITxExecSummary; import org.aion.mcf.core.TxTouchedStorage; import org.aion.mcf.db.DetailsDataStore; -import org.aion.vm.ExecutionResult; -import org.aion.vm.VirtualMachine; -import org.aion.zero.types.AionInternalTx; -import org.aion.zero.types.AionTransaction; -import org.aion.zero.types.AionTxReceipt; import org.aion.mcf.vm.types.DataWord; import org.aion.mcf.vm.types.Log; import org.aion.rlp.RLP; import org.aion.rlp.RLPElement; import org.aion.rlp.RLPList; +import java.math.BigInteger; +import java.util.*; + +import static java.util.Collections.*; +import static org.aion.base.util.BIUtil.toBI; +import static org.apache.commons.lang3.ArrayUtils.isEmpty; +import static org.apache.commons.lang3.ArrayUtils.isNotEmpty; + public class AionTxExecSummary implements ITxExecSummary { /** @@ -361,8 +353,7 @@ public static Builder builderFor(AionTxReceipt receipt) { * creation of the transaction summary. Contains all elements useful for * referencing both the transactions and the results of the transaction. * This also includes results like which rows of the storage (account - * storage {@link DetailsDataStore}) were {@code touched} by - * {@link VirtualMachine}. + * storage {@link DetailsDataStore}) were {@code touched} by virtual machine. * * Prefer using this builder, as rules will be enforced and the system will * fast fail. diff --git a/modAion/test/org/aion/types/AionTransacitonTest.java b/modAion/test/org/aion/types/AionTransactionTest.java similarity index 100% rename from modAion/test/org/aion/types/AionTransacitonTest.java rename to modAion/test/org/aion/types/AionTransactionTest.java diff --git a/modAionImpl/build.xml b/modAionImpl/build.xml index 7da654a2d9..f9f79abac9 100644 --- a/modAionImpl/build.xml +++ b/modAionImpl/build.xml @@ -1,149 +1,152 @@ - - - - - - - - + + + + + + + + - - - - + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + + + + + - + - - - - - - - + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - + + + + + + + + + + + - - - - - - - - - - - - - + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - - - - - + + + + + - + - - - - - - - + + + + + + + diff --git a/modAionImpl/module-info.java b/modAionImpl/module-info.java index a7589e816a..43e719807d 100644 --- a/modAionImpl/module-info.java +++ b/modAionImpl/module-info.java @@ -1,5 +1,4 @@ module aion.zero.impl { - requires aion.base; requires aion.mcf; requires aion.log; @@ -14,13 +13,13 @@ requires aion.crypto; requires aion.db.impl; requires aion.zero; + requires aion.fastvm; + exports org.aion.equihash; exports org.aion.zero.impl.blockchain; - exports org.aion.solidity; exports org.aion.zero.impl; exports org.aion.zero.impl.core; exports org.aion.zero.impl.types; exports org.aion.zero.impl.config; - exports org.aion.equihash; exports org.aion.zero.impl.cli; } \ No newline at end of file diff --git a/modAionImpl/src/org/aion/equihash/EquiValidator.java b/modAionImpl/src/org/aion/equihash/EquiValidator.java index d046398503..e005c39e21 100644 --- a/modAionImpl/src/org/aion/equihash/EquiValidator.java +++ b/modAionImpl/src/org/aion/equihash/EquiValidator.java @@ -114,11 +114,6 @@ public boolean isValidSolution(byte[] solution, byte[] blockHeader, byte[] nonce return false; } - // blake instance can be reused inside 512 indiecs loop. - // it save both blake and initState mem cost. - // if use blake in Equivalidator instance level, as it's multi-threaded, - // have to pay a lock cost. - // so still keep it in function level. Blake2b blake = Blake2b.Digest.newInstance(initState); // Create array with 2^k slots diff --git a/modAionImpl/src/org/aion/zero/impl/AionBlockchainImpl.java b/modAionImpl/src/org/aion/zero/impl/AionBlockchainImpl.java index aaa2bf6fa8..e61146eaa8 100644 --- a/modAionImpl/src/org/aion/zero/impl/AionBlockchainImpl.java +++ b/modAionImpl/src/org/aion/zero/impl/AionBlockchainImpl.java @@ -52,7 +52,6 @@ import org.aion.mcf.vm.types.Bloom; import org.aion.rlp.RLP; import org.aion.vm.TransactionExecutor; -import org.aion.zero.impl.blockchain.AionTxExecSummary; import org.aion.zero.impl.blockchain.ChainConfiguration; import org.aion.zero.impl.blockchain.NonceMgr; import org.aion.zero.impl.config.CfgAion; @@ -66,10 +65,7 @@ import org.aion.zero.impl.types.AionTxInfo; import org.aion.zero.impl.types.RetValidPreBlock; import org.aion.zero.impl.valid.TXValidator; -import org.aion.zero.types.A0BlockHeader; -import org.aion.zero.types.AionTransaction; -import org.aion.zero.types.AionTxReceipt; -import org.aion.zero.types.IAionBlock; +import org.aion.zero.types.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -101,7 +97,7 @@ public class AionBlockchainImpl implements IAionBlockchain { private static final int THOUSAND_MS = 1000; private static final int TARGET_BLOCKINTERVAL = 10; // second private static final int DIFFICULTY_BYTES = 16; - + A0BCConfig config; private IRepository repository; diff --git a/modAionImpl/src/org/aion/zero/impl/AionHub.java b/modAionImpl/src/org/aion/zero/impl/AionHub.java index e0fae34677..354d988d42 100644 --- a/modAionImpl/src/org/aion/zero/impl/AionHub.java +++ b/modAionImpl/src/org/aion/zero/impl/AionHub.java @@ -52,7 +52,7 @@ import org.aion.zero.impl.db.AionRepositoryImpl; import org.aion.zero.impl.pow.AionPoW; import org.aion.zero.impl.sync.BlockPropagationHandler; -import org.aion.zero.impl.sync.callback.BroadcastNewBlockCallback; +import org.aion.zero.impl.sync.callback.BroadcastNewBlockHandler; import org.aion.zero.impl.sync.SyncMgr; import org.aion.zero.impl.sync.callback.*; import org.aion.zero.impl.tx.AionTransactionExecThread; @@ -166,14 +166,14 @@ public AionHub() { private void registerCallback() { List cbs = new ArrayList<>(); - cbs.add(new ReqStatusCallback(syncLog, this.blockchain, this.p2pMgr, cfg.getGenesis().getHash())); + cbs.add(new ReqStatusHandler(syncLog, this.blockchain, this.p2pMgr, cfg.getGenesis().getHash())); cbs.add(new ResStatusCallback(syncLog, this.p2pMgr, this.syncMgr)); - cbs.add(new ReqBlocksHeadersCallback(syncLog, this.blockchain, this.p2pMgr)); + cbs.add(new ReqBlocksHeadersHandler(syncLog, this.blockchain, this.p2pMgr)); cbs.add(new ResBlocksHeadersCallback(syncLog, this.syncMgr)); - cbs.add(new ReqBlocksBodiesCallback(syncLog, this.blockchain, this.p2pMgr)); - cbs.add(new ResBlocksBodiesCallback(syncLog, this.syncMgr)); - cbs.add(new BroadcastTxCallback(syncLog, this.mempool, this.p2pMgr)); - cbs.add(new BroadcastNewBlockCallback(syncLog, this.propHandler)); + cbs.add(new ReqBlocksBodiesHandler(syncLog, this.blockchain, this.p2pMgr)); + cbs.add(new ResBlocksBodiesHandler(syncLog, this.syncMgr)); + cbs.add(new BroadcastTxHandler(syncLog, this.mempool, this.p2pMgr)); + cbs.add(new BroadcastNewBlockHandler(syncLog, this.propHandler)); this.p2pMgr.register(cbs); } diff --git a/modAionImpl/src/org/aion/zero/impl/blockchain/AionPendingStateImpl.java b/modAionImpl/src/org/aion/zero/impl/blockchain/AionPendingStateImpl.java index 06913988c7..00970f4450 100644 --- a/modAionImpl/src/org/aion/zero/impl/blockchain/AionPendingStateImpl.java +++ b/modAionImpl/src/org/aion/zero/impl/blockchain/AionPendingStateImpl.java @@ -40,11 +40,7 @@ import org.aion.zero.impl.types.AionBlock; import org.aion.zero.impl.types.AionTxInfo; import org.aion.zero.impl.valid.TXValidator; -import org.aion.zero.types.A0BlockHeader; -import org.aion.zero.types.AionPendingTx; -import org.aion.zero.types.AionTransaction; -import org.aion.zero.types.AionTxReceipt; -import org.aion.zero.types.IAionBlock; +import org.aion.zero.types.*; import org.aion.crypto.HashUtil; import org.aion.mcf.db.IBlockStorePow; import org.aion.mcf.db.TransactionStore; diff --git a/modAionImpl/src/org/aion/zero/impl/blockchain/NonceMgr.java b/modAionImpl/src/org/aion/zero/impl/blockchain/NonceMgr.java index 7664a5723a..79ea7892a4 100644 --- a/modAionImpl/src/org/aion/zero/impl/blockchain/NonceMgr.java +++ b/modAionImpl/src/org/aion/zero/impl/blockchain/NonceMgr.java @@ -30,7 +30,6 @@ import java.math.BigInteger; import java.util.AbstractMap; import java.util.Collections; -import java.util.HashMap; import java.util.Map; import org.apache.commons.collections4.map.LRUMap; @@ -128,7 +127,7 @@ public int hashCode() { return super.hashCode(); } - public void flush() { + public synchronized void flush() { if (LOG.isTraceEnabled()) { LOG.trace("NonceMgr- flush start"); @@ -213,7 +212,7 @@ public void flush() { } } - public BigInteger getRepoNonce(Address addr) { + public synchronized BigInteger getRepoNonce(Address addr) { if (map.get(addr) == null) { return repo.getNonce(addr); } else { diff --git a/modAionImpl/src/org/aion/zero/impl/db/AionRepositoryImpl.java b/modAionImpl/src/org/aion/zero/impl/db/AionRepositoryImpl.java index 68debe674a..5685672e3a 100644 --- a/modAionImpl/src/org/aion/zero/impl/db/AionRepositoryImpl.java +++ b/modAionImpl/src/org/aion/zero/impl/db/AionRepositoryImpl.java @@ -27,6 +27,7 @@ import org.aion.base.db.*; import org.aion.base.type.Address; import org.aion.base.util.Hex; +import org.aion.db.impl.AbstractDatabaseWithCache; import org.aion.mcf.core.AccountState; import org.aion.mcf.db.AbstractRepository; import org.aion.mcf.db.ContractDetailsCacheImpl; @@ -242,6 +243,13 @@ public void flush() { if (databaseGroup != null) { for (IByteArrayKeyValueDatabase db : databaseGroup) { + if (db instanceof AbstractDatabaseWithCache) { + // printing heap cache stats when enabled + AbstractDatabaseWithCache dbwc = (AbstractDatabaseWithCache) db; + if (dbwc.isStatsEnabled()) { + LOG.debug(dbwc.getName().get() + ": " + dbwc.getStats().toString()); + } + } if (!db.isAutoCommitEnabled()) { db.commit(); } diff --git a/modAionImpl/src/org/aion/zero/impl/sync/BlockPropagationHandler.java b/modAionImpl/src/org/aion/zero/impl/sync/BlockPropagationHandler.java index b84828181f..08104d7038 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/BlockPropagationHandler.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/BlockPropagationHandler.java @@ -85,7 +85,7 @@ public void propagateNewBlock(final AionBlock block) { this.p2pManager.getActiveNodes().values().forEach(n -> { if (log.isDebugEnabled()) - log.debug("sending new block" + block.getShortHash() + " to: " + n.getIdHash()); + log.debug(""); this.p2pManager.send(n.getIdHash(), new BroadcastNewBlock(block)); }); } @@ -148,7 +148,7 @@ private boolean send(AionBlock block, int nodeId) { .filter(n -> n.getBestBlockNumber() <= block.getNumber()) .forEach(n -> { if (log.isDebugEnabled()) - log.debug("sending new block" + block.getShortHash() + " to: " + n.getIdHash()); + log.debug(""); this.p2pManager.send(n.getIdHash(), new BroadcastNewBlock(block)); sent.getAndSet(true); }); diff --git a/modAionImpl/src/org/aion/zero/impl/sync/HeaderQuery.java b/modAionImpl/src/org/aion/zero/impl/sync/HeaderQuery.java new file mode 100644 index 0000000000..bf1d18a590 --- /dev/null +++ b/modAionImpl/src/org/aion/zero/impl/sync/HeaderQuery.java @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017-2018 Aion foundation. + * + * This file is part of the aion network project. + * + * The aion network project is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or any later version. + * + * The aion network project is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the aion network project source files. + * If not, see . + * + * The aion network project leverages useful source code from other + * open source projects. We greatly appreciate the effort that was + * invested in these projects and we thank the individual contributors + * for their work. For provenance information and contributors + * please see . + * + * Contributors to the aion source files in decreasing order of code volume: + * Aion foundation. + * team through the ethereumJ library. + * Ether.Camp Inc. (US) team through Ethereum Harmony. + * John Tromp through the Equihash solver. + * Samuel Neves through the BLAKE2 implementation. + * Zcash project team. + * Bitcoinj team. + */ + +package org.aion.zero.impl.sync; + +/** + * @author chris + */ +final class HeaderQuery{ + + String fromNode; + + long from; + + int take; + + HeaderQuery(String _fromNode, long _from, int _take){ + this.fromNode = _fromNode; + this.from = _from; + this.take = _take; + } +} \ No newline at end of file diff --git a/modAionImpl/src/org/aion/zero/impl/sync/HeadersWrapper.java b/modAionImpl/src/org/aion/zero/impl/sync/HeadersWrapper.java new file mode 100644 index 0000000000..0a951f5db5 --- /dev/null +++ b/modAionImpl/src/org/aion/zero/impl/sync/HeadersWrapper.java @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2017-2018 Aion foundation. + * + * This file is part of the aion network project. + * + * The aion network project is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or any later version. + * + * The aion network project is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the aion network project source files. + * If not, see . + * + * The aion network project leverages useful source code from other + * open source projects. We greatly appreciate the effort that was + * invested in these projects and we thank the individual contributors + * for their work. For provenance information and contributors + * please see . + * + * Contributors to the aion source files in decreasing order of code volume: + * Aion foundation. + * team through the ethereumJ library. + * Ether.Camp Inc. (US) team through Ethereum Harmony. + * John Tromp through the Equihash solver. + * Samuel Neves through the BLAKE2 implementation. + * Zcash project team. + * Bitcoinj team. + */ + +package org.aion.zero.impl.sync; + +import org.aion.zero.types.A0BlockHeader; +import java.util.List; + +/** + * @author chris + */ +final class HeadersWrapper { + + private int nodeIdHash; + + private long timeout; + + private List headers; + + /** + * + * @param _nodeIdHash int + * @param _headers List + */ + HeadersWrapper(int _nodeIdHash, final List _headers){ + this.nodeIdHash = _nodeIdHash; + this.headers = _headers; + this.timeout = System.currentTimeMillis(); + } + + /** + * @return int - node id hash + */ + int getNodeIdHash(){ + return this.nodeIdHash; + } + + /** + * @return long + * used to compare and drop from queue if expired + */ + long getTimeout(){ + return this.timeout; + } + + /** + * @return List + */ + List getHeaders(){ + return this.headers; + } + +} diff --git a/modAionImpl/src/org/aion/zero/impl/sync/SequentialHeaders.java b/modAionImpl/src/org/aion/zero/impl/sync/SequentialHeaders.java deleted file mode 100644 index 251df4431a..0000000000 --- a/modAionImpl/src/org/aion/zero/impl/sync/SequentialHeaders.java +++ /dev/null @@ -1,134 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017-2018 Aion foundation. - * - * This file is part of the aion network project. - * - * The aion network project is free software: you can redistribute it - * and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or any later version. - * - * The aion network project is distributed in the hope that it will - * be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aion network project source files. - * If not, see . - * - * Contributors: - * Aion foundation. - * - ******************************************************************************/ - -package org.aion.zero.impl.sync; - -import java.util.*; - -import org.aion.mcf.types.AbstractBlockHeader; - -/** - * - * @author chris Grow-able sequential list of blocks headers - * @inspector yao - */ - -public final class SequentialHeaders extends ArrayList { - - private final static long serialVersionUID = 1L; - - private class SortByBlockNumber implements Comparator { - @Override - public int compare(H h0, H h1) { - return Long.compare(h0.getNumber(), h1.getNumber()); - } - } - - private final Comparator comparator = new SortByBlockNumber(); - - /** - * Adds a list of headers to the current list, this will try to add append - * the list given that there are elements for which:
- * {@code h[i] >= s[-1]} within the input collections. - * - * Given that there is a subset of input h such that the lowest member of h - * (h_0) such that h_0 is adjacent to s[-1] (s[-1] + 1), and the subset is - * defined such that all elements are uniquely adjacent, then the sequential - * header will append such a set to itself sorted in ascending order. - * - * @param _headers - */ - @Override - public boolean addAll(final Collection _headers) { - if (_headers != null && _headers.size() > 0) { - final List l = new ArrayList<>(_headers); - - l.sort(comparator); - int currentSize = this.size(); - - int offset = 0; - if (currentSize > 0) { - long existLastBlockNumber = this.get(currentSize - 1).getNumber(); - - // TODO: refactor this to use number + 1, simplifies logic - int index = Collections.binarySearch(l, this.get(currentSize - 1), comparator); - - // case where our latest element is higher than the list - if (index == l.size()) { - return false; - } - - // did not found our element, but convert the positional index - // back, to an index (this should give us the index of the next - // largest - // value) - if (index < 0) { - index = Math.abs(index + 1); - } - - /* - * we may end up in any position, so its important for us to - * ensure that we always find the earliest number + 1 element in - * the array. This means iterating through all of the same - * values - */ - offset = index; - Iterator it = l.listIterator(index); - boolean found = false; - while (it.hasNext()) { - H h = it.next(); - if (h.getNumber() == existLastBlockNumber + 1) { - found = true; - break; - } - offset++; - } - - if (!found) - return false; - } - - H firstHeader = l.get(offset); - super.add(firstHeader); - long highestNumber = firstHeader.getNumber(); - - for (int i = offset + 1, m = l.size(); i < m; i++) { - H currentHeader = l.get(i); - if (currentHeader.getNumber() != highestNumber + 1) { - continue; - } - - highestNumber = highestNumber + 1; - super.add(currentHeader); - } - return true; - } - return false; - } - - public boolean containsElement(final H h) { - return (Collections.binarySearch(this, h, comparator) > -1); - } - -} \ No newline at end of file diff --git a/modAionImpl/src/org/aion/zero/impl/sync/SyncMgr.java b/modAionImpl/src/org/aion/zero/impl/sync/SyncMgr.java index 6c6e55fcbb..d34f675970 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/SyncMgr.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/SyncMgr.java @@ -1,40 +1,45 @@ -/******************************************************************************* +/* * Copyright (c) 2017-2018 Aion foundation. * - * This file is part of the aion network project. + * This file is part of the aion network project. * - * The aion network project is free software: you can redistribute it - * and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or any later version. + * The aion network project is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or any later version. * - * The aion network project is distributed in the hope that it will - * be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. + * The aion network project is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. * - * You should have received a copy of the GNU General Public License - * along with the aion network project source files. - * If not, see . + * You should have received a copy of the GNU General Public License + * along with the aion network project source files. + * If not, see . * - * Contributors: - * Aion foundation. - * - ******************************************************************************/ + * The aion network project leverages useful source code from other + * open source projects. We greatly appreciate the effort that was + * invested in these projects and we thank the individual contributors + * for their work. For provenance information and contributors + * please see . + * + * Contributors to the aion source files in decreasing order of code volume: + * Aion foundation. + */ package org.aion.zero.impl.sync; +import java.math.BigInteger; import java.util.*; import java.util.concurrent.*; import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; + import org.apache.commons.collections4.map.LRUMap; import org.slf4j.Logger; import org.aion.base.util.ByteArrayWrapper; -import org.aion.base.util.Hex; import org.aion.mcf.blockchain.IChainCfg; import org.aion.mcf.core.ImportResult; import org.aion.evtmgr.IEvent; @@ -46,7 +51,6 @@ import org.aion.p2p.IP2pMgr; import org.aion.zero.impl.AionBlockchainImpl; import org.aion.zero.impl.blockchain.ChainConfiguration; -import org.aion.zero.impl.sync.msg.BroadcastNewBlock; import org.aion.zero.impl.sync.msg.ReqBlocksBodies; import org.aion.zero.impl.sync.msg.ReqBlocksHeaders; import org.aion.zero.impl.sync.msg.ReqStatus; @@ -56,43 +60,62 @@ /** * @author chris + * TODO: pre selected peers list based on target total difficult */ public final class SyncMgr { - private static final long FETCH_INTERVAL = 1000; + // interval time get peer status + private static final int STATUS_INTERVAL = 500; + + // timeout sent headers + private static final int SENT_HEADERS_TIMEOUT = 5000; + private final static Logger LOG = AionLoggerFactory.getLogger(LogEnum.SYNC.name()); - private boolean showStatus = false; - private int syncBackwardMax = 128; + // re-use same req status + private final static ReqStatus reqStatus = new ReqStatus(); + + // default how many blocks forward to sync based on current block number private int syncForwardMax = 192; + private int blocksQueueMax = 2000; - private AtomicBoolean start = new AtomicBoolean(true); - //private AtomicBoolean newBlockUpdated = new AtomicBoolean(false); private AionBlockchainImpl blockchain; private IP2pMgr p2pMgr; private IEventMgr evtMgr; private BlockHeaderValidator blockHeaderValidator; + private AtomicBoolean start = new AtomicBoolean(true); - private AtomicInteger selectedNodeIdHashcode = new AtomicInteger(0); - private AtomicLong longestHeaders = new AtomicLong(0); - private AtomicLong networkBestBlockNumber = new AtomicLong(0); - private AtomicReference networkBestBlockHash = new AtomicReference<>(new byte[0]); + // set as last block number within one batch import when first block + // imported success as best + // reset to 0 as any block import result as no parent (side chain) + private AtomicLong jump = new AtomicLong(0); - private static final int GET_STATUS_SLEEP = 1; + class NetBestStatus { + // network best block number for self node perspective + long blockNumber = 0L; - private ConcurrentHashMap> importedHeaders = new ConcurrentHashMap<>(); - private ConcurrentHashMap> sentHeaders = new ConcurrentHashMap<>(); - private final BlockingQueue importedBlocksQueue = new LinkedBlockingQueue<>(); + // network best block hash for self node perspective + byte[] blockHash = new byte[0]; - private Map importedBlocksCache = Collections.synchronizedMap(new LRUMap<>(1024)); + BigInteger totalDiff = BigInteger.ZERO; + + } + + private AtomicReference netBestStatus = new AtomicReference<>(new NetBestStatus()); + + // store headers that has been sent to fetch block bodies + private final ConcurrentHashMap sentHeaders = new ConcurrentHashMap<>(); + + // store validated headers from network + private final BlockingQueue importedHeaders = new LinkedBlockingQueue<>(); + + // store blocks that ready to save to db + private final BlockingQueue importedBlocks = new LinkedBlockingQueue<>(); + + // filter based on imported blocks + private final Map savedHashes = Collections.synchronizedMap(new LRUMap<>(1024)); - /** - * Threads - */ - private Thread getHeadersThread; - private Thread getBodiesThread; - private Thread importBlocksThread; private ScheduledThreadPoolExecutor scheduledWorkers; private static final class AionSyncMgrHolder { @@ -103,51 +126,50 @@ public static SyncMgr inst() { return AionSyncMgrHolder.INSTANCE; } - public void updateNetworkBestBlock(final long _nodeBestBlockNumber, final byte[] _nodeBestBlockHash) { + // Attation: + // update best block is callback function from p2p thread pool. even the + // blocknumber and blockhash is atomic, but still need sync to prevent + // blocknumber link to wrong block hash. + public synchronized void updateNetworkBestBlock(String _displayId, long _nodeBestBlockNumber, + final byte[] _nodeBestBlockHash, final byte[] _totalDiff) { long selfBestBlockNumber = this.blockchain.getBestBlock().getNumber(); + BigInteger totalDiff = new BigInteger(1, _totalDiff); + if (_nodeBestBlockNumber > this.netBestStatus.get().blockNumber) { + if (netBestStatus.get().totalDiff.compareTo(totalDiff) < 0) { + netBestStatus.get().blockNumber = _nodeBestBlockNumber; + netBestStatus.get().blockHash = _nodeBestBlockHash; + netBestStatus.get().totalDiff = totalDiff; + if (_nodeBestBlockNumber > this.blockchain.getBestBlock().getNumber()) + getHeaders(); - // switch to new selected node event on equal highest block - if (_nodeBestBlockNumber > this.networkBestBlockNumber.get()) { - this.networkBestBlockNumber.set(_nodeBestBlockNumber); - this.networkBestBlockHash.set(_nodeBestBlockHash); - - // fire the init push - // if(headersLatch != null) - // headersLatch.countDown(); - //newBlockUpdated.set(true); + } else { + if (LOG.isDebugEnabled()) { + LOG.debug( + "", + _displayId, _nodeBestBlockNumber, totalDiff, netBestStatus.get().totalDiff, + selfBestBlockNumber, this.netBestStatus.get().blockNumber); + } + } } - if (this.networkBestBlockNumber.get() <= selfBestBlockNumber) { + if (this.netBestStatus.get().blockNumber <= selfBestBlockNumber){ this.evtMgr.newEvent(new EventConsensus(EventConsensus.CALLBACK.ON_SYNC_DONE)); if (LOG.isDebugEnabled()) { - LOG.debug("", _nodeBestBlockNumber, - selfBestBlockNumber); + LOG.debug( + "", + _nodeBestBlockNumber, selfBestBlockNumber, this.netBestStatus.get().blockNumber); } } else { - if (LOG.isDebugEnabled()) { - LOG.debug("", _nodeBestBlockNumber, - selfBestBlockNumber); - } + if (LOG.isDebugEnabled()) + LOG.debug( + "", + _nodeBestBlockNumber, selfBestBlockNumber, this.netBestStatus.get().blockNumber); } } - private void updateSentHeaders(int _nodeIdHashcode, final List _receivedBlocksHeaders) { - if (_receivedBlocksHeaders != null && _receivedBlocksHeaders.size() > 0) - this.sentHeaders.put(_nodeIdHashcode, _receivedBlocksHeaders); - } - - public void clearSentHeaders(int _nodeIdHashcode) { - this.sentHeaders.remove(_nodeIdHashcode); - } - - public List getSentHeaders(int _nodeIdHashcode) { - return this.sentHeaders.get(_nodeIdHashcode); - } - public void init(final IP2pMgr _p2pMgr, final IEventMgr _evtMgr, final int _syncForwardMax, final int _blocksQueueMax, final boolean _showStatus) { - showStatus = _showStatus; this.p2pMgr = _p2pMgr; this.blockchain = AionBlockchainImpl.inst(); this.evtMgr = _evtMgr; @@ -158,215 +180,310 @@ public void init(final IP2pMgr _p2pMgr, final IEventMgr _evtMgr, final int _sync setupEventHandler(); - getHeadersThread = new Thread(this::processGetHeaders, "sync-headers"); - getHeadersThread.start(); - getBodiesThread = new Thread(this::processGetBlocks, "sync-blocks"); + Thread getBodiesThread = new Thread(this::processGetBlocks, "sync-blocks"); + getBodiesThread.setPriority(Thread.MAX_PRIORITY); getBodiesThread.start(); - importBlocksThread = new Thread(this::processImportBlocks, "sync-import"); + + Thread importBlocksThread = new Thread(this::processImportBlocks, "sync-import"); + importBlocksThread.setPriority(Thread.MAX_PRIORITY); importBlocksThread.start(); + scheduledWorkers = new ScheduledThreadPoolExecutor(1); scheduledWorkers.allowCoreThreadTimeOut(true); - if (showStatus) + if (_showStatus) scheduledWorkers.scheduleWithFixedDelay(() -> { Thread.currentThread().setName("sync-status"); - if (LOG.isDebugEnabled()) { - LOG.debug( - "", - blockchain.getBestBlock().getNumber(), networkBestBlockNumber.get(), - Hex.toHexString(networkBestBlockHash.get()).substring(0, 6), longestHeaders.get(), - importedHeaders.entrySet().stream() - .map((entry) -> entry.getKey() + "-" + entry.getValue().size()) - .collect(Collectors.joining(",")), - sentHeaders.entrySet().stream() - .map((entry) -> entry.getKey() + "-" + entry.getValue().size()) - .collect(Collectors.joining(",")), - importedBlocksQueue.size()); - } - }, 0, 5, TimeUnit.SECONDS); + AionBlock blk = blockchain.getBestBlock(); + System.out.println("[sync-status self=" + blk.getNumber() + "/" + + this.blockchain.getTotalDifficulty().toString(10) + " network=" + + this.netBestStatus.get().blockNumber + "/" + + netBestStatus.get().totalDiff.toString(10) + + " blocks-queue-size=" + importedBlocks.size() + "]"); + }, 0, 5000, TimeUnit.MILLISECONDS); scheduledWorkers.scheduleWithFixedDelay(() -> { - INode node = p2pMgr.getRandom(); - if (node != null) - p2pMgr.send(node.getIdHash(), new ReqStatus()); - }, 0, GET_STATUS_SLEEP, TimeUnit.SECONDS); + Set ids = new HashSet<>(); + for (int i = 0; i < 3; i++) { + INode node = p2pMgr.getRandom(); + if (node != null && !ids.contains(node.getIdHash())) { + ids.add(node.getIdHash()); + p2pMgr.send(node.getIdHash(), reqStatus); + } + } + + }, 1000, STATUS_INTERVAL, TimeUnit.MILLISECONDS); } - /** - * Oct 12, 2017 jay void - */ private void setupEventHandler() { - List evts = new ArrayList<>(); - evts.add(new EventConsensus(EventConsensus.CALLBACK.ON_SYNC_DONE)); - this.evtMgr.registerEvent(evts); + List events = new ArrayList<>(); + events.add(new EventConsensus(EventConsensus.CALLBACK.ON_SYNC_DONE)); + this.evtMgr.registerEvent(events); } - @SuppressWarnings("unchecked") - public void validateAndAddHeaders(int _nodeIdHashcode, final List _headers) { + /** + * + * @param _nodeIdHashcode + * int + * @param _displayId + * String + * @param _headers + * List validate headers batch and add batch to imported headers + */ + public void validateAndAddHeaders(int _nodeIdHashcode, String _displayId, final List _headers) { - if (_headers == null || _headers.isEmpty()) + if (_headers == null || _headers.isEmpty()) { return; + } - boolean headersValid = true; - for (A0BlockHeader _header : _headers) { - if (!this.blockHeaderValidator.validate(_header)) { - headersValid = false; - break; + _headers.sort((h1, h2) -> (int) (h1.getNumber() - h2.getNumber())); + Iterator it = _headers.iterator(); + while (it.hasNext()) { + + A0BlockHeader h = it.next(); + boolean valid = this.blockHeaderValidator.validate(h); + boolean imported = savedHashes.containsKey(new ByteArrayWrapper(h.getHash())); + + // drop all batch + if (!valid) { + return; + } + if (imported) { + it.remove(); } } - if (!headersValid) - return; - SequentialHeaders headers = this.importedHeaders.get(_nodeIdHashcode); - if (headers == null) - headers = new SequentialHeaders<>(); - - headers.addAll(_headers); - importedHeaders.putIfAbsent(_nodeIdHashcode, headers); - int size = headers.size(); - if (size > this.longestHeaders.get()) { - this.longestHeaders.set(size); - this.selectedNodeIdHashcode.set(_nodeIdHashcode); - } + + importedHeaders.add(new HeadersWrapper(_nodeIdHashcode, _headers)); + if (LOG.isDebugEnabled()) { - LOG.debug("", _headers.size(), - _headers.get(0).getNumber(), _headers.get(_headers.size() - 1).getNumber(), headers.size()); + LOG.debug("", _headers.size(), + _headers.get(0).getNumber(), _headers.get(_headers.size() - 1).getNumber(), _displayId); } } - public void validateAndAddBlocks(int _nodeIdHashcode, final List _blocks, boolean ifNewBlockBroadcast) { - if (_blocks == null || _blocks.isEmpty()) - return; - int m = _blocks.size(); - /* - * sort if sync batch - */ - if (m > 1) - _blocks.sort((b1, b2) -> b1.getNumber() > b2.getNumber() ? 1 : 0); - if (LOG.isDebugEnabled()) { - LOG.debug("", _blocks.size(), _blocks.get(0).getNumber(), - _blocks.get(_blocks.size() - 1).getNumber()); - } + /** + * @param _nodeIdHashcode + * int + * @param _displayId + * String + * @param _bodies + * List 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 _bodies) { - for (AionBlock b : _blocks) { - importedBlocksQueue.add(b); - } + if (importedBlocks.size() > blocksQueueMax) + return; - } + HeadersWrapper hw = this.sentHeaders.remove(_nodeIdHashcode); + if (hw == null || _bodies == null) + return; - private void processGetHeaders() { - while (start.get()) { + // assemble batch + List headers = hw.getHeaders(); + List blocks = new ArrayList<>(_bodies.size()); + Iterator headerIt = headers.iterator(); + Iterator bodyIt = _bodies.iterator(); + while (headerIt.hasNext() && bodyIt.hasNext()) { + AionBlock block = AionBlock.createBlockFromNetwork(headerIt.next(), bodyIt.next()); + if (block == null) { + LOG.error("", _displayId); + break; + } else + blocks.add(block); + } - try { - Thread.sleep(FETCH_INTERVAL); - } catch (InterruptedException e) { - } + int m = blocks.size(); + if (m == 0) + return; - AionBlock selfBlock = this.blockchain.getBestBlock(); - long selfBest = selfBlock.getNumber(); + // sort this batch + if (m > 1) + blocks.sort((b1, b2) -> b1.getNumber() > b2.getNumber() ? 1 : 0); + if (LOG.isDebugEnabled()) { + LOG.debug("", m, blocks.get(0).getNumber(), + blocks.get(blocks.size() - 1).getNumber(), _displayId); + } - INode node = p2pMgr.getRandom(); + // add batch + importedBlocks.addAll(blocks); + } - if (node != null) { - long remoteBest = node.getBestBlockNumber(); - long diff = remoteBest - selfBest; - if (diff > 0) { - long from = Math.max(1, selfBest - syncBackwardMax); - long to = selfBest + (diff > this.syncForwardMax ? this.syncForwardMax : diff); - this.p2pMgr.send(node.getIdHash(), new ReqBlocksHeaders(from, (int) (to - from) + 1)); - if (LOG.isDebugEnabled()) { - LOG.debug("", - node.getIdHash(), from, to, selfBest, remoteBest); - } + /** + * fetch headers routine + */ + private void getHeaders() { + + AionBlock selfBlock = this.blockchain.getBestBlock(); + long selfNum = selfBlock.getNumber(); + long retargetNum = jump.get(); + + // retarget future if its higher than self + long selfBest = Math.max(selfNum, retargetNum); + + Set ids = new HashSet<>(); + + List filtered = p2pMgr.getActiveNodes().values().stream().filter( + (n) -> netBestStatus.get().totalDiff != null && + n.getTotalDifficulty() != null && + (new BigInteger(1, n.getTotalDifficulty())).compareTo(netBestStatus.get().totalDiff) >= 0).collect(Collectors.toList()); + + Random r = new Random(System.currentTimeMillis()); + for (int i = 0; i < 3; i++) { + if (filtered.size() > 0) { + INode node = filtered.get(r.nextInt(filtered.size())); + if (!ids.contains(node.getIdHash())) { + long from = Math.max(1, selfBest - 128); + long to = selfBest + this.syncForwardMax; + int take = (int) (to - from) + 1; + ids.add(node.getIdHash()); + this.p2pMgr.send(node.getIdHash(), new ReqBlocksHeaders(from, take)); + // ids.put(node.getIdHash(), new HeaderQuery(node.getIdShort(), from, take)); } } } +// ids.forEach((k, v) -> { +// // System.out.println("head req from " + v.from + " take " + v.take); +// this.p2pMgr.send(k, new ReqBlocksHeaders(v.from, v.take)); +// }); } private void processGetBlocks() { while (start.get()) { - + HeadersWrapper hw; try { - Thread.sleep(FETCH_INTERVAL * 2); + hw = importedHeaders.take(); } catch (InterruptedException e) { + return; } - List headers = importedHeaders.get(selectedNodeIdHashcode.get()); - if (importedBlocksQueue.size() < blocksQueueMax && headers != null) { - List blockHashes = new ArrayList<>(); - for (A0BlockHeader header : headers) { - blockHashes.add(header.getHash()); - } - clearSentHeaders(selectedNodeIdHashcode.get()); - updateSentHeaders(selectedNodeIdHashcode.get(), headers); - if (headers.size() > 0) { + int idHash = hw.getNodeIdHash(); + List headers = hw.getHeaders(); + synchronized (sentHeaders) { + HeadersWrapper hw1 = sentHeaders.get(idHash); + // already sent, check timeout and add it back if not timeout + // yet + if (hw1 != null) { + // expired + if ((System.currentTimeMillis() - hw1.getTimeout()) > SENT_HEADERS_TIMEOUT) { + sentHeaders.put(idHash, hw); + List headerHashes = new ArrayList<>(); + for (A0BlockHeader h : headers) { + headerHashes.add(h.getHash()); + } + this.p2pMgr.send(idHash, new ReqBlocksBodies(headerHashes)); + } + } else { + this.sentHeaders.put(idHash, hw); + List headerHashes = new ArrayList<>(); + for (A0BlockHeader h : headers) { + headerHashes.add(h.getHash()); + } + this.p2pMgr.send(idHash, new ReqBlocksBodies(headerHashes)); if (LOG.isDebugEnabled()) { - LOG.debug("", headers.get(0).getNumber(), blockHashes.size()); + LOG.debug("", headers.get(0).getNumber(), headerHashes.size()); } - importedHeaders.clear(); - this.p2pMgr.send(selectedNodeIdHashcode.get(), new ReqBlocksBodies(blockHashes)); } } } } private void processImportBlocks() { + while (start.get()) { try { - AionBlock b = importedBlocksQueue.take(); + long start = System.currentTimeMillis(); + long blockNumberIndex = 0; - // TODO: is it possible the import result of a block may change - // over time? - if (importedBlocksCache.containsKey(ByteArrayWrapper.wrap(b.getHash()))) { - continue; - } + List batch = new ArrayList<>(); - if (LOG.isDebugEnabled()) { + while ((System.currentTimeMillis() - start) < 10) { - LOG.debug("", b.getNumber(), b.getShortHash(), - Hex.toHexString(b.getParentHash()).substring(0, 6)); - } + AionBlock b = importedBlocks.peek(); - ImportResult importResult = this.blockchain.tryToConnect(b); - switch (importResult) { - case IMPORTED_BEST: - if (LOG.isInfoEnabled()) { - LOG.info("", b.getNumber(), b.getShortHash(), - b.getTransactionsList().size()); - } - importedBlocksCache.put(ByteArrayWrapper.wrap(b.getHash()), null); - break; - case IMPORTED_NOT_BEST: - if (LOG.isInfoEnabled()) { - LOG.info("", b.getNumber(), b.getShortHash(), - b.getTransactionsList().size()); + // continue on batched blocks + if (b == null) { + continue; } - importedBlocksCache.put(ByteArrayWrapper.wrap(b.getHash()), null); - break; - case NO_PARENT: - if (LOG.isDebugEnabled()) { - LOG.debug("", b.getNumber(), - b.getShortHash()); - } - break; - case INVALID_BLOCK: - if (LOG.isDebugEnabled()) { - LOG.debug("", b.getNumber(), - b.getShortHash(), b.getTransactionsList().size()); + + // break if start of next batch + if (blockNumberIndex > 0 && b.getNumber() != (blockNumberIndex + 1)) { + start = 0; + continue; } - break; - case EXIST: - if (LOG.isDebugEnabled()) { - LOG.debug("", b.getNumber(), - b.getShortHash(), b.getTransactionsList().size()); + + b = importedBlocks.take(); + blockNumberIndex = b.getNumber(); + ByteArrayWrapper hash = new ByteArrayWrapper(b.getHash()); + if (!savedHashes.containsKey(hash)) { + batch.add(b); + savedHashes.put(hash, null); } - importedBlocksCache.put(ByteArrayWrapper.wrap(b.getHash()), null); - break; - default: - if (LOG.isDebugEnabled()) { - LOG.debug(""); + } + + // sleep if no batch empty then continue + if (batch.size() == 0) { + Thread.sleep(1000); + continue; + } + + + + boolean fetchAheadTriggerUsed = false; + + for (AionBlock b : batch) { + ImportResult importResult = this.blockchain.tryToConnect(b); + switch (importResult) { + case IMPORTED_BEST: + if (LOG.isInfoEnabled()) { + LOG.info("", b.getNumber(), b.getShortHash(), + b.getTransactionsList().size()); + } + + // re-targeting for next batch blocks headers + if (!fetchAheadTriggerUsed) { + jump.set(batch.get(batch.size() - 1).getNumber()); + fetchAheadTriggerUsed = true; + getHeaders(); + } + break; + case IMPORTED_NOT_BEST: + if (LOG.isInfoEnabled()) { + LOG.info("", b.getNumber(), b.getShortHash(), + b.getTransactionsList().size()); + } + + savedHashes.put(ByteArrayWrapper.wrap(b.getHash()), null); + break; + case EXIST: + // still exist + if (LOG.isDebugEnabled()) { + LOG.debug("", b.getNumber(), + b.getShortHash(), b.getTransactionsList().size()); + } + break; + case NO_PARENT: + if (LOG.isDebugEnabled()) { + LOG.debug("", b.getNumber(), b.getShortHash()); + } + + // reset and skip current batch + jump.set(0); + continue; + case INVALID_BLOCK: + if (LOG.isDebugEnabled()) { + LOG.debug("", b.getNumber(), + b.getShortHash(), b.getTransactionsList().size()); + } + break; + default: + if (LOG.isDebugEnabled()) { + LOG.debug(""); + } + break; } - break; } - } catch (InterruptedException e) { + } catch (Exception ex) { + return; } } } @@ -377,6 +494,6 @@ public void shutdown() { } public long getNetworkBestBlockNumber() { - return this.networkBestBlockNumber.get(); + return this.netBestStatus.get().blockNumber; } } diff --git a/modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastNewBlockCallback.java b/modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastNewBlockHandler.java similarity index 88% rename from modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastNewBlockCallback.java rename to modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastNewBlockHandler.java index cb5a633854..d63f5f5518 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastNewBlockCallback.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastNewBlockHandler.java @@ -35,23 +35,20 @@ package org.aion.zero.impl.sync.callback; -import java.util.Collections; - import org.aion.p2p.Ctrl; import org.aion.p2p.Handler; import org.aion.p2p.Ver; import org.aion.zero.impl.sync.Act; - import org.aion.zero.impl.sync.BlockPropagationHandler; -import org.aion.zero.impl.sync.SyncMgr; import org.aion.zero.impl.sync.msg.BroadcastNewBlock; import org.aion.zero.impl.types.AionBlock; import org.slf4j.Logger; /** * @author jay + * handler for new block broadcasted from network */ -public final class BroadcastNewBlockCallback extends Handler { +public final class BroadcastNewBlockHandler extends Handler { private final Logger log; @@ -63,7 +60,7 @@ public final class BroadcastNewBlockCallback extends Handler { * @see org.aion.net.nio.ICallback#getCtrl() change param * IPendingStateInternal later */ - public BroadcastNewBlockCallback(final Logger _log, final BlockPropagationHandler propHandler) { + public BroadcastNewBlockHandler(final Logger _log, final BlockPropagationHandler propHandler) { super(Ver.V0, Ctrl.SYNC, Act.BROADCAST_NEWBLOCK); this.log = _log; this.propHandler = propHandler; @@ -85,7 +82,7 @@ public void receive(int _nodeIdHashcode, String _displayId, final byte[] _msgByt if (this.log.isDebugEnabled()) { String hash = block.getShortHash(); hash = hash != null ? hash : "null"; - this.log.debug("blockProp: [node: " + _nodeIdHashcode + " | " + "hash: " + hash + " | status: " + result.name() + "]"); + this.log.debug(""); } } } diff --git a/modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastTxCallback.java b/modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastTxHandler.java similarity index 93% rename from modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastTxCallback.java rename to modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastTxHandler.java index 783f89d23e..b5d5b86bab 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastTxCallback.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/callback/BroadcastTxHandler.java @@ -50,8 +50,9 @@ /** * @author chris + * handler for new transaction broadcasted from network */ -public final class BroadcastTxCallback extends Handler { +public final class BroadcastTxHandler extends Handler { private final Logger log; @@ -65,7 +66,7 @@ public final class BroadcastTxCallback extends Handler { * @see org.aion.net.nio.ICallback#getCtrl() change param * IPendingStateInternal later */ - public BroadcastTxCallback(final Logger _log, final IPendingStateInternal _pendingState, final IP2pMgr _p2pMgr) { + public BroadcastTxHandler(final Logger _log, final IPendingStateInternal _pendingState, final IP2pMgr _p2pMgr) { super(Ver.V0, Ctrl.SYNC, Act.BROADCAST_TX); this.log = _log; this.pendingState = _pendingState; diff --git a/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksBodiesCallback.java b/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksBodiesHandler.java similarity index 92% rename from modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksBodiesCallback.java rename to modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksBodiesHandler.java index 91a71fdb0c..12940a2107 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksBodiesCallback.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksBodiesHandler.java @@ -49,8 +49,9 @@ /** * @author chris + * handler for request block bodies broadcasted from network */ -public final class ReqBlocksBodiesCallback extends Handler { +public final class ReqBlocksBodiesHandler extends Handler { private final Logger log; @@ -58,7 +59,7 @@ public final class ReqBlocksBodiesCallback extends Handler { private final IP2pMgr p2pMgr; - public ReqBlocksBodiesCallback(final Logger _log, final IAionBlockchain _blockchain, final IP2pMgr _p2pMgr) { + public ReqBlocksBodiesHandler(final Logger _log, final IAionBlockchain _blockchain, final IP2pMgr _p2pMgr) { super(Ver.V0, Ctrl.SYNC, Act.REQ_BLOCKS_BODIES); this.log = _log; this.blockchain = _blockchain; diff --git a/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksHeadersCallback.java b/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksHeadersHandler.java similarity index 93% rename from modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksHeadersCallback.java rename to modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksHeadersHandler.java index f7ca775492..60a7238ccf 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksHeadersCallback.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqBlocksHeadersHandler.java @@ -51,9 +51,10 @@ /** * * @author chris + * handler for request block headers from network * */ -public final class ReqBlocksHeadersCallback extends Handler { +public final class ReqBlocksHeadersHandler extends Handler { /** * self guardian @@ -66,7 +67,7 @@ public final class ReqBlocksHeadersCallback extends Handler { private final IP2pMgr p2pMgr; - public ReqBlocksHeadersCallback(final Logger _log, final IAionBlockchain _blockchain, final IP2pMgr _p2pMgr) { + public ReqBlocksHeadersHandler(final Logger _log, final IAionBlockchain _blockchain, final IP2pMgr _p2pMgr) { super(Ver.V0, Ctrl.SYNC, Act.REQ_BLOCKS_HEADERS); this.log = _log; this.blockchain = _blockchain; diff --git a/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqStatusCallback.java b/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqStatusHandler.java similarity index 91% rename from modAionImpl/src/org/aion/zero/impl/sync/callback/ReqStatusCallback.java rename to modAionImpl/src/org/aion/zero/impl/sync/callback/ReqStatusHandler.java index 69fc9f4992..ddb336668b 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqStatusCallback.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/callback/ReqStatusHandler.java @@ -44,7 +44,11 @@ import org.aion.zero.impl.sync.msg.ResStatus; import org.slf4j.Logger; -public final class ReqStatusCallback extends Handler { +/** + * @author chris + * handler for status request from network + */ +public final class ReqStatusHandler extends Handler { private final Logger log; @@ -54,7 +58,7 @@ public final class ReqStatusCallback extends Handler { private byte[] genesisHash; - public ReqStatusCallback(final Logger _log, final IAionBlockchain _chain, final IP2pMgr _mgr, final byte[] _genesisHash) { + public ReqStatusHandler(final Logger _log, final IAionBlockchain _chain, final IP2pMgr _mgr, final byte[] _genesisHash) { super(Ver.V0, Ctrl.SYNC, Act.REQ_STATUS); this.log = _log; this.chain = _chain; diff --git a/modAionImpl/src/org/aion/zero/impl/sync/callback/ResBlocksBodiesCallback.java b/modAionImpl/src/org/aion/zero/impl/sync/callback/ResBlocksBodiesHandler.java similarity index 58% rename from modAionImpl/src/org/aion/zero/impl/sync/callback/ResBlocksBodiesCallback.java rename to modAionImpl/src/org/aion/zero/impl/sync/callback/ResBlocksBodiesHandler.java index 529c685119..bdfe3c4947 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/callback/ResBlocksBodiesCallback.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/callback/ResBlocksBodiesHandler.java @@ -35,65 +35,40 @@ package org.aion.zero.impl.sync.callback; -import java.util.ArrayList; -import java.util.Iterator; import java.util.List; - import org.aion.p2p.Handler; import org.aion.p2p.Ctrl; import org.aion.p2p.Ver; import org.aion.zero.impl.sync.Act; import org.aion.zero.impl.sync.SyncMgr; import org.aion.zero.impl.sync.msg.ResBlocksBodies; -import org.aion.zero.types.A0BlockHeader; -import org.aion.zero.impl.types.AionBlock; import org.slf4j.Logger; /** * * @author chris + * handler for blocks bodies received from network * */ -public final class ResBlocksBodiesCallback extends Handler { +public final class ResBlocksBodiesHandler extends Handler { private final Logger log; private final SyncMgr syncMgr; - public ResBlocksBodiesCallback(final Logger _log, final SyncMgr _syncMgr) { + public ResBlocksBodiesHandler(final Logger _log, final SyncMgr _syncMgr) { super(Ver.V0, Ctrl.SYNC, Act.RES_BLOCKS_BODIES); this.log = _log; this.syncMgr = _syncMgr; } @Override - public void receive(int _nodeIdHashcode,String _displayId, final byte[] _msgBytes) { + public void receive(int _nodeIdHashcode, String _displayId, final byte[] _msgBytes) { ResBlocksBodies resBlocksBodies = ResBlocksBodies.decode(_msgBytes); - List headers = this.syncMgr.getSentHeaders(_nodeIdHashcode); List bodies = resBlocksBodies.getBlocksBodies(); - if (headers != null && bodies != null && headers.size() == bodies.size()) { - List blocks = new ArrayList<>(bodies.size()); - Iterator headerIt = headers.iterator(); - Iterator bodyIt = bodies.iterator(); - boolean pass = true; - while (headerIt.hasNext() && bodyIt.hasNext()) { - AionBlock block = AionBlock.createBlockFromNetwork(headerIt.next(), bodyIt.next()); - if (block == null) { - pass = false; - break; - } else - blocks.add(block); - } - this.syncMgr.clearSentHeaders(_nodeIdHashcode); - if (pass) { - this.log.debug( - "", - blocks.size(), - _displayId - ); - this.syncMgr.validateAndAddBlocks(_nodeIdHashcode, blocks, false); - } - } else - this.log.error(""); + if(bodies != null && bodies.size() > 0) + this.syncMgr.validateAndAddBlocks(_nodeIdHashcode, _displayId, bodies); + else + this.log.error(""); } } diff --git a/modAionImpl/src/org/aion/zero/impl/sync/callback/ResBlocksHeadersCallback.java b/modAionImpl/src/org/aion/zero/impl/sync/callback/ResBlocksHeadersCallback.java index 9cb1918edc..8240b3dfec 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/callback/ResBlocksHeadersCallback.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/callback/ResBlocksHeadersCallback.java @@ -48,6 +48,7 @@ /** * * @author chris + * handler for block headers response from network * */ public final class ResBlocksHeadersCallback extends Handler { @@ -63,20 +64,25 @@ public ResBlocksHeadersCallback(final Logger _log, final SyncMgr _syncMgr) { } @Override - public void receive(int _nodeIdHashcode,String _displayId, final byte[] _msgBytes) { + public void receive(int _nodeIdHashcode, String _displayId, final byte[] _msgBytes) { if(_msgBytes == null || _msgBytes.length == 0) return; ResBlocksHeaders resHeaders = ResBlocksHeaders.decode(_msgBytes); if(resHeaders != null) { List headers = resHeaders.getHeaders(); - if(headers.size() > 0){ + if(headers != null && headers.size() > 0){ this.log.debug( "", headers.get(0).getNumber(), headers.size(), _displayId ); - this.syncMgr.validateAndAddHeaders(_nodeIdHashcode, headers); + this.syncMgr.validateAndAddHeaders(_nodeIdHashcode, _displayId, headers); + } else { + this.log.error( + "", + _displayId + ); } } else this.log.error( diff --git a/modAionImpl/src/org/aion/zero/impl/sync/callback/ResStatusCallback.java b/modAionImpl/src/org/aion/zero/impl/sync/callback/ResStatusCallback.java index 76e8baaef8..1414c1d267 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/callback/ResStatusCallback.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/callback/ResStatusCallback.java @@ -60,27 +60,24 @@ public ResStatusCallback(final Logger _log, final IP2pMgr _p2pMgr, final SyncMgr } @Override - public void receive(int _nodeIdHashcode,String _displayId, final byte[] _msgBytes) { + public void receive(int _nodeIdHashcode, String _displayId, final byte[] _msgBytes) { if (_msgBytes == null || _msgBytes.length == 0) return; ResStatus rs = ResStatus.decode(_msgBytes); + INode node = this.p2pMgr.getActiveNodes().get(_nodeIdHashcode); + + INodeMgr nmgr = this.p2pMgr.getNodeMgr(); + + nmgr.updateAllNodesInfo(node); + if (node != null) { - this.log.debug( - "", - rs.getBestBlockNumber(), - _displayId - ); + this.log.debug("", rs.getBestBlockNumber(), _displayId); long nodeBestBlockNumber = rs.getBestBlockNumber(); byte[] nodeBestBlockHash = rs.getBestHash(); - long nodeTotalDifficulty = 0;//rs.getTotalDifficulty(); - node.updateStatus( - nodeBestBlockNumber, - nodeBestBlockHash, - nodeTotalDifficulty - ); - syncMgr.updateNetworkBestBlock(nodeBestBlockNumber, rs.getBestHash()); + byte[] nodeTotalDifficulty = rs.getTotalDifficulty(); + node.updateStatus(nodeBestBlockNumber, nodeBestBlockHash, nodeTotalDifficulty); + syncMgr.updateNetworkBestBlock(_displayId, nodeBestBlockNumber, rs.getBestHash(), nodeTotalDifficulty); } } - } \ No newline at end of file diff --git a/modAionImpl/src/org/aion/zero/impl/sync/msg/BroadcastNewBlock.java b/modAionImpl/src/org/aion/zero/impl/sync/msg/BroadcastNewBlock.java index a9bb85daa6..d0189102c2 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/msg/BroadcastNewBlock.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/msg/BroadcastNewBlock.java @@ -42,6 +42,9 @@ import org.aion.p2p.Ver; import org.aion.rlp.RLP; +/** + * @author chris + */ public final class BroadcastNewBlock extends Msg { @SuppressWarnings("rawtypes") diff --git a/modAionImpl/src/org/aion/zero/impl/sync/msg/ReqBlocksBodies.java b/modAionImpl/src/org/aion/zero/impl/sync/msg/ReqBlocksBodies.java index 897f53a7a1..54493ef4d8 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/msg/ReqBlocksBodies.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/msg/ReqBlocksBodies.java @@ -43,6 +43,9 @@ import org.aion.p2p.Ver; import org.aion.zero.impl.sync.Act; +/** + * @author chris + */ public final class ReqBlocksBodies extends Msg { private final List blocksHashes; diff --git a/modAionImpl/src/org/aion/zero/impl/sync/msg/ReqBlocksHeaders.java b/modAionImpl/src/org/aion/zero/impl/sync/msg/ReqBlocksHeaders.java index d874187b35..53fe999ccf 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/msg/ReqBlocksHeaders.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/msg/ReqBlocksHeaders.java @@ -41,6 +41,9 @@ import org.aion.p2p.Ver; import org.aion.zero.impl.sync.Act; +/** + * @author chris + */ public final class ReqBlocksHeaders extends Msg { /** diff --git a/modAionImpl/src/org/aion/zero/impl/sync/msg/ResBlocksBodies.java b/modAionImpl/src/org/aion/zero/impl/sync/msg/ResBlocksBodies.java index 1e5ca6c2af..7b137623f5 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/msg/ResBlocksBodies.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/msg/ResBlocksBodies.java @@ -47,8 +47,9 @@ /** * - * @author chris TODO: follow same construction, decode & encode rule as - * ResBlocksHeaders in future. Need to update INcBlockchain + * @author chris + * TODO: follow same construction, decode & encode rule as + * ResBlocksHeaders in future. Need to update INcBlockchain */ public final class ResBlocksBodies extends Msg { diff --git a/modAionImpl/src/org/aion/zero/impl/sync/msg/ResStatus.java b/modAionImpl/src/org/aion/zero/impl/sync/msg/ResStatus.java index dc9199d192..4dee5b2ffe 100644 --- a/modAionImpl/src/org/aion/zero/impl/sync/msg/ResStatus.java +++ b/modAionImpl/src/org/aion/zero/impl/sync/msg/ResStatus.java @@ -50,7 +50,7 @@ public final class ResStatus extends Msg { private final long bestBlockNumber; // 8 - private final int totalDifficultyLen; // 1 + private final byte totalDifficultyLen; // 1 private final byte[] totalDifficulty; // >= 1 @@ -58,23 +58,53 @@ public final class ResStatus extends Msg { private final byte[] genesisHash; // 32 - public ResStatus(final long bestBlockNumber, final byte[] _totalDifficulty, final byte[] _bestHash, byte[] _genesisHash) { + /** + * + * @param bestBlockNumber long + * @param _totalDifficulty byte[] + * @param _bestHash byte[] + * @param _genesisHash byte[] + */ + public ResStatus(long bestBlockNumber, final byte[] _totalDifficulty, final byte[] _bestHash, final byte[] _genesisHash) { super(Ver.V0, Ctrl.SYNC, Act.RES_STATUS); this.bestBlockNumber = bestBlockNumber; - this.totalDifficultyLen = _totalDifficulty.length; + this.totalDifficultyLen = _totalDifficulty.length > Byte.MAX_VALUE ? 1 : (byte)_totalDifficulty.length; this.totalDifficulty = _totalDifficulty; this.bestHash = _bestHash; this.genesisHash = _genesisHash; } + /** + * @return long + */ public long getBestBlockNumber() { return this.bestBlockNumber; } + /** + * @return byte[] + */ public byte[] getBestHash() { return this.bestHash; } + /** + * @return byte[] + */ + public byte[] getTotalDifficulty() { return this.totalDifficulty; } + + /** + * @return byte[] + */ + public byte[] getGenesisHash() { return this.genesisHash; } + + /** + * @return byte[] + */ + public byte[] getTotalDiff() { + return this.totalDifficulty; + } + public static ResStatus decode(final byte[] _bytes) { if (_bytes == null || _bytes.length < minLen) return null; @@ -93,12 +123,10 @@ public static ResStatus decode(final byte[] _bytes) { @Override public byte[] encode() { - if (this.totalDifficultyLen > 127) - return new byte[0]; int _len = 8 + 1 + totalDifficultyLen + 32 + 32; ByteBuffer bb = ByteBuffer.allocate(_len); bb.putLong(this.bestBlockNumber); - bb.put((byte) this.totalDifficultyLen); + bb.put(this.totalDifficultyLen); bb.put(this.totalDifficulty); bb.put(this.bestHash); bb.put(this.genesisHash); diff --git a/modAionImpl/src/org/aion/zero/impl/types/AionBlockSummary.java b/modAionImpl/src/org/aion/zero/impl/types/AionBlockSummary.java index 15500f4095..5174e0d105 100644 --- a/modAionImpl/src/org/aion/zero/impl/types/AionBlockSummary.java +++ b/modAionImpl/src/org/aion/zero/impl/types/AionBlockSummary.java @@ -31,8 +31,8 @@ import org.aion.base.type.Address; import org.aion.base.type.IBlockSummary; import org.aion.mcf.types.AbstractBlockSummary; -import org.aion.zero.impl.blockchain.AionTxExecSummary; import org.aion.zero.types.AionTransaction; +import org.aion.zero.types.AionTxExecSummary; import org.aion.zero.types.AionTxReceipt; import org.aion.zero.types.IAionBlock; diff --git a/modAionImpl/src/org/aion/zero/impl/types/RetValidPreBlock.java b/modAionImpl/src/org/aion/zero/impl/types/RetValidPreBlock.java index fc5b41945e..f632c8adb6 100644 --- a/modAionImpl/src/org/aion/zero/impl/types/RetValidPreBlock.java +++ b/modAionImpl/src/org/aion/zero/impl/types/RetValidPreBlock.java @@ -29,8 +29,8 @@ import java.util.Map; import org.aion.base.type.Address; -import org.aion.zero.impl.blockchain.AionTxExecSummary; import org.aion.zero.types.AionTransaction; +import org.aion.zero.types.AionTxExecSummary; import org.aion.zero.types.AionTxReceipt; public class RetValidPreBlock { diff --git a/modAionImpl/src_fvm b/modAionImpl/src_fvm deleted file mode 120000 index 6a8bd1c035..0000000000 --- a/modAionImpl/src_fvm +++ /dev/null @@ -1 +0,0 @@ -../../aion_fastvm/java/src \ No newline at end of file diff --git a/modAionImpl/test/org/aion/zero/impl/blockchain/AionTxExecSummaryTest.java b/modAionImpl/test/org/aion/zero/impl/blockchain/AionTxExecSummaryTest.java index 8d1478dacc..b2eaf62878 100644 --- a/modAionImpl/test/org/aion/zero/impl/blockchain/AionTxExecSummaryTest.java +++ b/modAionImpl/test/org/aion/zero/impl/blockchain/AionTxExecSummaryTest.java @@ -37,8 +37,8 @@ import org.aion.base.type.Address; import org.aion.crypto.HashUtil; import org.aion.mcf.vm.types.Bloom; -import org.aion.zero.impl.blockchain.AionTxExecSummary; import org.aion.zero.types.AionTransaction; +import org.aion.zero.types.AionTxExecSummary; import org.aion.zero.types.AionTxReceipt; import org.junit.Test; diff --git a/modAionImpl/test/org/aion/zero/impl/sync/BlockPropagationTest.java b/modAionImpl/test/org/aion/zero/impl/sync/BlockPropagationTest.java index 2dc9e7acc2..97db7acb4f 100644 --- a/modAionImpl/test/org/aion/zero/impl/sync/BlockPropagationTest.java +++ b/modAionImpl/test/org/aion/zero/impl/sync/BlockPropagationTest.java @@ -3,10 +3,7 @@ import org.aion.crypto.ECKey; import org.aion.crypto.ECKeyFac; import org.aion.crypto.HashUtil; -import org.aion.p2p.Handler; -import org.aion.p2p.INode; -import org.aion.p2p.IP2pMgr; -import org.aion.p2p.Msg; +import org.aion.p2p.*; import org.aion.zero.impl.StandaloneBlockchain; import org.aion.zero.impl.types.AionBlock; import org.junit.Test; @@ -46,6 +43,11 @@ public long getBestBlockNumber() { return this.latestBlockNumber; } + @Override + public byte[] getTotalDifficulty() { + return new byte[0]; + } + @Override public byte[] getIp() { return new byte[0]; @@ -67,12 +69,7 @@ public int getPort() { } @Override - public long getTotalDifficulty() { - return 0; - } - - @Override - public void updateStatus(long _bestBlockNumber, byte[] _bestBlockHash, long _totalDifficulty) { + public void updateStatus(long _bestBlockNumber, byte[] _bestBlockHash, byte[] _totalDifficulty) { } } @@ -91,7 +88,7 @@ public Map getActiveNodes() { } @Override - public INode getRandom() { + public INodeMgr getNodeMgr() { return null; } @@ -115,6 +112,11 @@ public void register(List _hs) { } + @Override + public INode getRandom() { + return null; + } + @Override public void send(int _id, Msg _msg) { diff --git a/modAionImpl/test/org/aion/zero/impl/sync/TestSequentialHeaders.java b/modAionImpl/test/org/aion/zero/impl/sync/TestSequentialHeaders.java deleted file mode 100644 index bb64bca296..0000000000 --- a/modAionImpl/test/org/aion/zero/impl/sync/TestSequentialHeaders.java +++ /dev/null @@ -1,172 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017-2018 Aion foundation. - * - * This file is part of the aion network project. - * - * The aion network project is free software: you can redistribute it - * and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or any later version. - * - * The aion network project is distributed in the hope that it will - * be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aion network project source files. - * If not, see . - * - * The aion network project leverages useful source code from other - * open source projects. We greatly appreciate the effort that was - * invested in these projects and we thank the individual contributors - * for their work. For provenance information and contributors - * please see . - * - * Contributors to the aion source files in decreasing order of code volume: - * Aion foundation. - * team through the ethereumJ library. - * Ether.Camp Inc. (US) team through Ethereum Harmony. - * John Tromp through the Equihash solver. - * Samuel Neves through the BLAKE2 implementation. - * Zcash project team. - * Bitcoinj team. - ******************************************************************************/ -package org.aion.zero.impl.sync; - -import static com.google.common.truth.Truth.assertThat; -import static org.junit.Assert.assertEquals; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -import org.aion.zero.impl.sync.SequentialHeaders; -import org.aion.zero.types.A0BlockHeader; -import org.junit.Test; - -public class TestSequentialHeaders { - - @Test - public void testUniqueAndSequential() { - List headers = new ArrayList(); - SequentialHeaders hs = new SequentialHeaders(); - - /** - * Missing block 5,6,9 - */ - headers.add(new A0BlockHeader.Builder().withNumber(0).build()); - headers.add(new A0BlockHeader.Builder().withNumber(1).build()); - headers.add(new A0BlockHeader.Builder().withNumber(2).build()); - headers.add(new A0BlockHeader.Builder().withNumber(10).build()); - headers.add(new A0BlockHeader.Builder().withNumber(3).build()); - headers.add(new A0BlockHeader.Builder().withNumber(7).build()); - headers.add(new A0BlockHeader.Builder().withNumber(4).build()); - headers.add(new A0BlockHeader.Builder().withNumber(8).build()); - headers.add(new A0BlockHeader.Builder().withNumber(2).build()); - headers.add(new A0BlockHeader.Builder().withNumber(1).build()); - headers.add(new A0BlockHeader.Builder().withNumber(0).build()); - hs.addAll(headers); - assertThat(hs.size()).isEqualTo(5); - - headers.add(new A0BlockHeader.Builder().withNumber(5).build()); - headers.add(new A0BlockHeader.Builder().withNumber(6).build()); - headers.add(new A0BlockHeader.Builder().withNumber(9).build()); - hs.addAll(headers); - assertThat(hs.size()).isEqualTo(11); - - for(int i = 0, m = hs.size(); i < m; i++ ) { - assertEquals(i, hs.get(i).getNumber()); - } - } - - @Test - public void testAllLesserThan() { - SequentialHeaders hs = new SequentialHeaders(); - - // place in 3 - hs.addAll(Arrays.asList(new A0BlockHeader.Builder().withNumber(3).build())); - - assertThat(hs.size()).isEqualTo(1); - - // now try adding in 0, 1, 2 - hs.addAll(Arrays.asList( - new A0BlockHeader.Builder().withNumber(0).build(), - new A0BlockHeader.Builder().withNumber(1).build(), - new A0BlockHeader.Builder().withNumber(2).build() - )); - assertThat(hs.size()).isEqualTo(1); - assertThat(hs.get(0).getNumber()).isEqualTo(3); - } - - @Test - public void testAddEmpty() { - SequentialHeaders hs = new SequentialHeaders<>(); - hs.addAll(Collections.emptyList()); - assertThat(hs.size()).isEqualTo(0); - } - - @Test - public void testSameElementMultiple() { - SequentialHeaders hs = new SequentialHeaders<>(); - hs.addAll(Arrays.asList(new A0BlockHeader.Builder().withNumber(3).build())); - - assertThat(hs.size()).isEqualTo(1); - - hs.addAll(Arrays.asList( - new A0BlockHeader.Builder().withNumber(3).build(), - new A0BlockHeader.Builder().withNumber(3).build() - )); - assertThat(hs.size()).isEqualTo(1); - } - - @Test - public void testSameAsTipAndHigher() { - SequentialHeaders hs = new SequentialHeaders<>(); - hs.addAll(Arrays.asList( - new A0BlockHeader.Builder().withNumber(1).build(), - new A0BlockHeader.Builder().withNumber(1).build(), - new A0BlockHeader.Builder().withNumber(2).build() - )); - - assertThat(hs.size()).isEqualTo(2); - assertThat(hs.get(0).getNumber()).isEqualTo(1); - assertThat(hs.get(1).getNumber()).isEqualTo(2); - } - - @Test - public void testSomeSmallerThanTip() { - SequentialHeaders hs = new SequentialHeaders<>(); - hs.addAll(Arrays.asList( - new A0BlockHeader.Builder().withNumber(1).build() - )); - - hs.addAll(Arrays.asList( - new A0BlockHeader.Builder().withNumber(0).build(), - new A0BlockHeader.Builder().withNumber(1).build(), - new A0BlockHeader.Builder().withNumber(2).build() - )); - - assertThat(hs.size()).isEqualTo(2); - assertThat(hs.get(0).getNumber()).isEqualTo(1); - assertThat(hs.get(1).getNumber()).isEqualTo(2); - } - - @Test - public void testLowerAndSameAsTip() { - SequentialHeaders hs = new SequentialHeaders<>(); - hs.addAll(Arrays.asList( - new A0BlockHeader.Builder().withNumber(1).build() - )); - - hs.addAll(Arrays.asList( - new A0BlockHeader.Builder().withNumber(0).build(), - new A0BlockHeader.Builder().withNumber(1).build(), - new A0BlockHeader.Builder().withNumber(1).build() - )); - - assertThat(hs.size()).isEqualTo(1); - assertThat(hs.get(0).getNumber()).isEqualTo(1); - } -} diff --git a/modAionImpl/test/org/aion/zero/impl/sync/msg/TestBroadcastNewBlock.java b/modAionImpl/test/org/aion/zero/impl/sync/msg/BroadcastNewBlockTest.java similarity index 98% rename from modAionImpl/test/org/aion/zero/impl/sync/msg/TestBroadcastNewBlock.java rename to modAionImpl/test/org/aion/zero/impl/sync/msg/BroadcastNewBlockTest.java index 2d70deaa50..6acd654e46 100644 --- a/modAionImpl/test/org/aion/zero/impl/sync/msg/TestBroadcastNewBlock.java +++ b/modAionImpl/test/org/aion/zero/impl/sync/msg/BroadcastNewBlockTest.java @@ -40,7 +40,7 @@ import static org.junit.Assert.assertEquals; -public class TestBroadcastNewBlock { +public class BroadcastNewBlockTest { @Test public void test() { diff --git a/modAionImpl/test/org/aion/zero/impl/sync/msg/ReqHeadersTest.java b/modAionImpl/test/org/aion/zero/impl/sync/msg/ReqHeadersTest.java new file mode 100644 index 0000000000..940b7b9515 --- /dev/null +++ b/modAionImpl/test/org/aion/zero/impl/sync/msg/ReqHeadersTest.java @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017-2018 Aion foundation. + * + * This file is part of the aion network project. + * + * The aion network project is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or any later version. + * + * The aion network project is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the aion network project source files. + * If not, see . + * + * Contributors to the aion source files in decreasing order of code volume: + * + * Aion foundation. + * team through the ethereumJ library. + * Ether.Camp Inc. (US) team through Ethereum Harmony. + * John Tromp through the Equihash solver. + * Samuel Neves through the BLAKE2 implementation. + * Zcash project team. + * Bitcoinj team. + * + */ + +package org.aion.zero.impl.sync.msg; + +import static org.junit.Assert.*; +import org.junit.Test; + +/** + * @author chris + */ +public class ReqHeadersTest { + + @Test + public void test() { + long from = 7571; + int take = 192; + + ReqBlocksHeaders rh = new ReqBlocksHeaders(from, take); + ReqBlocksHeaders rhNew = ReqBlocksHeaders.decode(rh.encode()); + assertEquals(from, rhNew.getFromBlock()); + assertEquals(take, rhNew.getTake()); + } + +} diff --git a/modAionImpl/test/org/aion/zero/impl/sync/msg/TestResBlocksHeaders.java b/modAionImpl/test/org/aion/zero/impl/sync/msg/ResBlocksHeadersTest.java similarity index 99% rename from modAionImpl/test/org/aion/zero/impl/sync/msg/TestResBlocksHeaders.java rename to modAionImpl/test/org/aion/zero/impl/sync/msg/ResBlocksHeadersTest.java index 9683968d57..e33cd5611f 100644 --- a/modAionImpl/test/org/aion/zero/impl/sync/msg/TestResBlocksHeaders.java +++ b/modAionImpl/test/org/aion/zero/impl/sync/msg/ResBlocksHeadersTest.java @@ -45,7 +45,7 @@ import org.aion.zero.types.A0BlockHeader; import org.junit.Test; -public class TestResBlocksHeaders { +public class ResBlocksHeadersTest { private static A0BlockHeader bh1; diff --git a/modAionImpl/test/org/aion/zero/impl/sync/msg/ResStatusTest.java b/modAionImpl/test/org/aion/zero/impl/sync/msg/ResStatusTest.java new file mode 100644 index 0000000000..47f483e3df --- /dev/null +++ b/modAionImpl/test/org/aion/zero/impl/sync/msg/ResStatusTest.java @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017-2018 Aion foundation. + * + * This file is part of the aion network project. + * + * The aion network project is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or any later version. + * + * The aion network project is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the aion network project source files. + * If not, see . + * + * Contributors to the aion source files in decreasing order of code volume: + * + * Aion foundation. + * team through the ethereumJ library. + * Ether.Camp Inc. (US) team through Ethereum Harmony. + * John Tromp through the Equihash solver. + * Samuel Neves through the BLAKE2 implementation. + * Zcash project team. + * Bitcoinj team. + * + */ + +package org.aion.zero.impl.sync.msg; + +import org.junit.Test; + +import java.util.Arrays; +import java.util.concurrent.ThreadLocalRandom; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +/** + * @author chris + */ +public class ResStatusTest { + + @Test + public void test() { + + long bestBlockNumber = ThreadLocalRandom.current().nextLong(); + byte[] totalDifficulty = new byte[Byte.MAX_VALUE]; + ThreadLocalRandom.current().nextBytes(totalDifficulty); + byte[] bestBlockHash = new byte[32]; + ThreadLocalRandom.current().nextBytes(bestBlockHash); + byte[] genesisHash = new byte[32]; + + ResStatus rs1 = new ResStatus(bestBlockNumber, totalDifficulty, bestBlockHash, genesisHash); + ResStatus rs2 = ResStatus.decode(rs1.encode()); + + assertEquals(bestBlockNumber, rs2.getBestBlockNumber()); + assertTrue(Arrays.equals(totalDifficulty, rs2.getTotalDifficulty())); + assertTrue(Arrays.equals(bestBlockHash, rs2.getBestHash())); + assertTrue(Arrays.equals(genesisHash, rs2.getGenesisHash())); + + } + +} diff --git a/modAionImpl/test/org/aion/zero/impl/sync/msg/TestReqHeaders.java b/modAionImpl/test/org/aion/zero/impl/sync/msg/TestReqHeaders.java deleted file mode 100644 index 3bce0299b4..0000000000 --- a/modAionImpl/test/org/aion/zero/impl/sync/msg/TestReqHeaders.java +++ /dev/null @@ -1,55 +0,0 @@ -/******************************************************************************* - * Copyright (c) 2017-2018 Aion foundation. - * - * This file is part of the aion network project. - * - * The aion network project is free software: you can redistribute it - * and/or modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation, either version 3 of - * the License, or any later version. - * - * The aion network project is distributed in the hope that it will - * be useful, but WITHOUT ANY WARRANTY; without even the implied - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with the aion network project source files. - * If not, see . - * - * The aion network project leverages useful source code from other - * open source projects. We greatly appreciate the effort that was - * invested in these projects and we thank the individual contributors - * for their work. For provenance information and contributors - * please see . - * - * Contributors to the aion source files in decreasing order of code volume: - * Aion foundation. - * team through the ethereumJ library. - * Ether.Camp Inc. (US) team through Ethereum Harmony. - * John Tromp through the Equihash solver. - * Samuel Neves through the BLAKE2 implementation. - * Zcash project team. - * Bitcoinj team. - ******************************************************************************/ -package org.aion.zero.impl.sync.msg; - -import static org.junit.Assert.*; - -import org.aion.zero.impl.sync.msg.ReqBlocksHeaders; -import org.junit.Test; - -public class TestReqHeaders { - - @Test - public void test() { - long from = 7571; - int take = 192; - - ReqBlocksHeaders rh = new ReqBlocksHeaders(from, take); - ReqBlocksHeaders rhNew = ReqBlocksHeaders.decode(rh.encode()); - assertEquals(from, rhNew.getFromBlock()); - assertEquals(take, rhNew.getTake()); - } - -} diff --git a/modApiServer/build.xml b/modApiServer/build.xml index ffd64931c2..7ac4566097 100644 --- a/modApiServer/build.xml +++ b/modApiServer/build.xml @@ -1,116 +1,120 @@ - - - - - - - + + + + + + + - - - - + + + + - - - - - + + + + + - - - - - + + + + + - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - + + + + + - - - - - - - - + + + + + + + + - - - - - + + + + + - + - - - - - - - + + + + + + + diff --git a/modApiServer/module-info.java b/modApiServer/module-info.java index 4e7ca14d80..3e15690301 100644 --- a/modApiServer/module-info.java +++ b/modApiServer/module-info.java @@ -1,5 +1,4 @@ module aion.apiserver { - requires aion.base; requires aion.zero.impl; requires aion.log; @@ -10,6 +9,7 @@ requires slf4j.api; requires aion.evtmgr; requires aion.evtmgr.impl; + requires aion.fastvm; exports org.aion.api.server.pb; exports org.aion.api.server.http; diff --git a/modApiServer/src/org/aion/api/server/IRpc.java b/modApiServer/src/org/aion/api/server/IRpc.java index 311997b289..5da5d53161 100644 --- a/modApiServer/src/org/aion/api/server/IRpc.java +++ b/modApiServer/src/org/aion/api/server/IRpc.java @@ -46,7 +46,7 @@ enum Method { eth_getTransactionByHash, eth_getTransactionReceipt, eth_getTransactionCount, - eth_getWork, + //eth_getWork, eth_estimateGas, eth_sendTransaction, eth_sendRawTransaction, diff --git a/modApiServer/src/org/aion/api/server/http/ApiWeb3Aion.java b/modApiServer/src/org/aion/api/server/http/ApiWeb3Aion.java index 3082e6d38f..8a0e02563e 100644 --- a/modApiServer/src/org/aion/api/server/http/ApiWeb3Aion.java +++ b/modApiServer/src/org/aion/api/server/http/ApiWeb3Aion.java @@ -154,7 +154,7 @@ AionBlock getBlockRaw(int bn) { private JSONObject blockToJson(AionBlock block, BigInteger totalDifficulty, boolean fullTransaction) { JSONObject obj = new JSONObject(); - obj.put("blockNumber", block.getNumber()); + obj.put("number", block.getNumber()); obj.put("hash", TypeConverter.toJsonHex(block.getHash())); obj.put("parentHash", TypeConverter.toJsonHex(block.getParentHash())); obj.put("logsBloom", TypeConverter.toJsonHex(block.getLogBloom())); @@ -172,8 +172,9 @@ private JSONObject blockToJson(AionBlock block, BigInteger totalDifficulty, bool obj.put("solution", TypeConverter.toJsonHex(block.getHeader().getSolution())); obj.put("gasUsed", TypeConverter.toJsonHex(block.getHeader().getEnergyConsumed())); obj.put("gasLimit", TypeConverter.toJsonHex(block.getHeader().getEnergyLimit())); - obj.put("energyConsumed", TypeConverter.toJsonHex(block.getHeader().getEnergyConsumed())); - obj.put("energyLimit", TypeConverter.toJsonHex(block.getHeader().getEnergyLimit())); + obj.put("nrgUsed", TypeConverter.toJsonHex(block.getHeader().getEnergyConsumed())); + obj.put("nrgLimit", TypeConverter.toJsonHex(block.getHeader().getEnergyLimit())); + // obj.put("extraData", TypeConverter.toJsonHex(block.getExtraData())); obj.put("size", new NumericalValue(block.getEncoded().length).toHexString()); @@ -182,8 +183,12 @@ private JSONObject blockToJson(AionBlock block, BigInteger totalDifficulty, bool for (AionTransaction _tx : _txs) { if (fullTransaction) { JSONObject jsonTx = new JSONObject(); - jsonTx.put("address", TypeConverter.toJsonHex(_tx.getContractAddress().toString())); + jsonTx.put("address", (_tx.getContractAddress() != null)? TypeConverter.toJsonHex(_tx.getContractAddress().toString()):null); jsonTx.put("transactionHash", TypeConverter.toJsonHex(_tx.getHash())); + jsonTx.put("transactionIndex", getTransactionReceipt(_tx.getHash()).transactionIndex); + jsonTx.put("value", TypeConverter.toJsonHex(_tx.getValue())); + jsonTx.put("nrg", _tx.getNrg()); + jsonTx.put("nrgPrice", TypeConverter.toJsonHex(_tx.getNrgPrice())); jsonTx.put("nonce", ByteUtil.byteArrayToLong(_tx.getNonce())); jsonTx.put("from", TypeConverter.toJsonHex(_tx.getFrom().toString())); jsonTx.put("to", TypeConverter.toJsonHex(_tx.getTo().toString())); diff --git a/modApiServer/src/org/aion/api/server/http/HttpServer.java b/modApiServer/src/org/aion/api/server/http/HttpServer.java index e43e2d3007..85423c9a06 100644 --- a/modApiServer/src/org/aion/api/server/http/HttpServer.java +++ b/modApiServer/src/org/aion/api/server/http/HttpServer.java @@ -155,7 +155,7 @@ private static JSONObject process(final IRpc.Method _method, final long _id, fin case eth_getBlockByHash: { String hashString = (String) params.get(0); - boolean fullTransactions = Boolean.parseBoolean((String) params.get(1)); + boolean fullTransactions = Boolean.parseBoolean(params.get(1) + ""); if (hashString == null) { log.debug("eth_getBlockByHash: invalid input"); return processResult(_id, null); @@ -166,11 +166,13 @@ private static JSONObject process(final IRpc.Method _method, final long _id, fin case eth_getBalance: String address = params.get(0) + ""; return processResult(_id, TypeConverter.toJsonHex(api.getBalance(address))); - + /* + // rationale for not supporting this: does not make sense in the context of aion's getWork for minig. + // see functions under 'stratum pool' descriptor in IRpc.java for currenly-supported stratum interactions case eth_getWork: // Header without nonce and solution , pool needs add new nonce - return processResult(_id, api.getBestBlock().getHeader().getHeaderBytes(true)); - + return processResult(_id, toHexString(HashUtil.h256(api.getBestBlock().getHeader().getHeaderBytes(true)))); + */ case eth_syncing: SyncInfo syncInfo = api.getSync(); if (!syncInfo.done) { @@ -279,6 +281,9 @@ private static JSONObject process(final IRpc.Method _method, final long _id, fin JSONObject obj = new JSONObject(); obj.put("address", txR.logs[i].address); obj.put("data", txR.txData); + obj.put("blockNumber", new NumericalValue(txR.blockNumber).toHexString()); + obj.put("transactionIndex", new NumericalValue(txR.transactionIndex).toHexString()); + obj.put("logIndex", new NumericalValue(i).toHexString()); String[] topics = txR.logs[i].topics; JSONArray topicArray = new JSONArray(); diff --git a/modApiServer/src/org/aion/api/server/pb/ApiAion0.java b/modApiServer/src/org/aion/api/server/pb/ApiAion0.java index c4013c281c..335e3d3694 100644 --- a/modApiServer/src/org/aion/api/server/pb/ApiAion0.java +++ b/modApiServer/src/org/aion/api/server/pb/ApiAion0.java @@ -49,6 +49,7 @@ import org.aion.zero.impl.blockchain.IAionChain; import org.aion.zero.impl.types.AionBlock; import org.aion.zero.impl.types.AionBlockSummary; +import org.aion.zero.impl.types.AionTxInfo; import org.aion.zero.types.AionTransaction; import org.aion.zero.types.AionTxReceipt; import org.json.JSONArray; @@ -1235,17 +1236,15 @@ public byte[] process(byte[] request, byte[] socketId) { try { req = Message.req_getBlockDetailsByNumber.parseFrom(data); - List num = req.getBlkNumbersList().parallelStream() + List blkNum = req.getBlkNumbersList().parallelStream() .collect(Collectors.toSet()).parallelStream() .sorted().collect(Collectors.toList()); - if (num.size() > 1000) { - num = num.subList(0, 1000); + if (blkNum.size() > 1000) { + blkNum = blkNum.subList(0, 1000); } - List> blks = - num.parallelStream().filter(n -> this.getBlock(n)!= null).map(n -> Map.entry(this.getBlock(n), this.ac.getBlockchain().getTotalDifficultyByHash( - Hash256.wrap(this.getBlock(n).getHash())))).collect(Collectors.toList()); + List> blks = getBlkAndDifficultyForBlkNumList(blkNum); if (blks == null) { return ApiUtil.toReturnHeader(getApiVersion(), Message.Retcode.r_fail_function_arguments_VALUE); @@ -1286,16 +1285,10 @@ public byte[] process(byte[] request, byte[] socketId) { Long endBlock = this.getBestBlock().getNumber(); Long startBlock = (endBlock - count + 1) >= 0 ? (endBlock - count + 1) : 0; - List numbers = LongStream.rangeClosed(startBlock, endBlock) + List blkNum = LongStream.rangeClosed(startBlock, endBlock) .boxed().collect(Collectors.toList()); - List> blks = - numbers.parallelStream() - .filter(n -> this.getBlock(n)!= null) - .map(n -> Map.entry(this.getBlock(n), - this.ac.getBlockchain().getTotalDifficultyByHash( - Hash256.wrap(this.getBlock(n).getHash())))) - .collect(Collectors.toList()); + List> blks = getBlkAndDifficultyForBlkNumList(blkNum); if (blks == null) { return ApiUtil.toReturnHeader(getApiVersion(), Message.Retcode.r_fail_function_arguments_VALUE); @@ -1334,16 +1327,10 @@ public byte[] process(byte[] request, byte[] socketId) { Long endBlock = this.getBestBlock().getNumber(); Long startBlock = (endBlock - count + 1) >= 0 ? (endBlock - count + 1) : 0; - List numbers = LongStream.rangeClosed(startBlock, endBlock) + List blkNum = LongStream.rangeClosed(startBlock, endBlock) .boxed().collect(Collectors.toList()); - List> blks = - numbers.parallelStream() - .filter(n -> this.getBlock(n)!= null) - .map(n -> Map.entry(this.getBlock(n), - this.ac.getBlockchain().getTotalDifficultyByHash( - Hash256.wrap(this.getBlock(n).getHash())))) - .collect(Collectors.toList()); + List> blks = getBlkAndDifficultyForBlkNumList(blkNum); if (blks == null) { return ApiUtil.toReturnHeader(getApiVersion(), Message.Retcode.r_fail_function_arguments_VALUE); @@ -1476,23 +1463,25 @@ private List getRsp_getBlocks(List bs = blks.parallelStream() .filter(Objects::nonNull) .map(blk -> { + AionBlock b = blk.getKey(); + return Message.t_Block.newBuilder() - .setBlockNumber(blk.getKey().getNumber()) - .setDifficulty(ByteString.copyFrom(blk.getKey().getDifficulty())) - .setExtraData(ByteString.copyFrom(blk.getKey().getExtraData())) - .setHash(ByteString.copyFrom(blk.getKey().getHash())) - .setLogsBloom(ByteString.copyFrom(blk.getKey().getLogBloom())) - .setMinerAddress(ByteString.copyFrom(blk.getKey().getCoinbase().toBytes())) - .setNonce(ByteString.copyFrom(blk.getKey().getNonce())) - .setNrgConsumed(blk.getKey().getNrgConsumed()) - .setNrgLimit(blk.getKey().getNrgLimit()) - .setParentHash(ByteString.copyFrom(blk.getKey().getParentHash())) - .setTimestamp(blk.getKey().getTimestamp()) - .setTxTrieRoot(ByteString.copyFrom(blk.getKey().getTxTrieRoot())) - .setReceiptTrieRoot(ByteString.copyFrom(blk.getKey().getReceiptsRoot())) - .setStateRoot(ByteString.copyFrom(blk.getKey().getStateRoot())) - .setSize(blk.getKey().getEncoded().length) - .setSolution(ByteString.copyFrom(blk.getKey().getHeader().getSolution())) + .setBlockNumber(b.getNumber()) + .setDifficulty(ByteString.copyFrom(b.getDifficulty())) + .setExtraData(ByteString.copyFrom(b.getExtraData())) + .setHash(ByteString.copyFrom(b.getHash())) + .setLogsBloom(ByteString.copyFrom(b.getLogBloom())) + .setMinerAddress(ByteString.copyFrom(b.getCoinbase().toBytes())) + .setNonce(ByteString.copyFrom(b.getNonce())) + .setNrgConsumed(b.getNrgConsumed()) + .setNrgLimit(b.getNrgLimit()) + .setParentHash(ByteString.copyFrom(b.getParentHash())) + .setTimestamp(b.getTimestamp()) + .setTxTrieRoot(ByteString.copyFrom(b.getTxTrieRoot())) + .setReceiptTrieRoot(ByteString.copyFrom(b.getReceiptsRoot())) + .setStateRoot(ByteString.copyFrom(b.getStateRoot())) + .setSize(b.getEncoded().length) + .setSolution(ByteString.copyFrom(b.getHeader().getSolution())) .setTotalDifficulty(ByteString.copyFrom(blk.getValue().toByteArray())) .build(); }).collect(Collectors.toList()); @@ -1502,36 +1491,45 @@ private List getRsp_getBlocks(List getRsp_getBlockDetails(List> blks) { List bds = blks.parallelStream().filter(Objects::nonNull).map(blk -> { - + AionBlock b = blk.getKey(); Message.t_BlockDetail.Builder builder = Message.t_BlockDetail.newBuilder() - .setBlockNumber(blk.getKey().getNumber()) - .setDifficulty(ByteString.copyFrom(blk.getKey().getDifficulty())) - .setExtraData(ByteString.copyFrom(blk.getKey().getExtraData())) - .setHash(ByteString.copyFrom(blk.getKey().getHash())) - .setLogsBloom(ByteString.copyFrom(blk.getKey().getLogBloom())) - .setMinerAddress(ByteString.copyFrom(blk.getKey().getCoinbase().toBytes())) - .setNonce(ByteString.copyFrom(blk.getKey().getNonce())) - .setNrgConsumed(blk.getKey().getNrgConsumed()) - .setNrgLimit(blk.getKey().getNrgLimit()) - .setParentHash(ByteString.copyFrom(blk.getKey().getParentHash())) - .setTimestamp(blk.getKey().getTimestamp()) - .setTxTrieRoot(ByteString.copyFrom(blk.getKey().getTxTrieRoot())) - .setReceiptTrieRoot(ByteString.copyFrom(blk.getKey().getReceiptsRoot())) - .setStateRoot(ByteString.copyFrom(blk.getKey().getStateRoot())) - .setSize(blk.getKey().getEncoded().length) - .setSolution(ByteString.copyFrom(blk.getKey().getHeader().getSolution())) + .setBlockNumber(b.getNumber()) + .setDifficulty(ByteString.copyFrom(b.getDifficulty())) + .setExtraData(ByteString.copyFrom(b.getExtraData())) + .setHash(ByteString.copyFrom(b.getHash())) + .setLogsBloom(ByteString.copyFrom(b.getLogBloom())) + .setMinerAddress(ByteString.copyFrom(b.getCoinbase().toBytes())) + .setNonce(ByteString.copyFrom(b.getNonce())) + .setNrgConsumed(b.getNrgConsumed()) + .setNrgLimit(b.getNrgLimit()) + .setParentHash(ByteString.copyFrom(b.getParentHash())) + .setTimestamp(b.getTimestamp()) + .setTxTrieRoot(ByteString.copyFrom(b.getTxTrieRoot())) + .setReceiptTrieRoot(ByteString.copyFrom(b.getReceiptsRoot())) + .setStateRoot(ByteString.copyFrom(b.getStateRoot())) + .setSize(b.getEncoded().length) + .setSolution(ByteString.copyFrom(b.getHeader().getSolution())) .setTotalDifficulty(ByteString.copyFrom(blk.getValue().toByteArray())); - List txs = blk.getKey().getTransactionsList(); + List txs = b.getTransactionsList(); - List tds = txs.parallelStream().filter(Objects::nonNull).map(tx -> { - TxRecpt rt = this.getTransactionReceipt(tx.getHash()); + List tds = new ArrayList<>(); + long cumulativeNrg = 0L; - List tles = Arrays.asList(rt.logs).parallelStream().map(log -> Message.t_LgEle.newBuilder() - .setData(ByteString.copyFrom(ByteUtil.hexStringToBytes(log.data))) - .setAddress(ByteString.copyFrom(Address.wrap(log.address).toBytes())) - .addAllTopics(Arrays.asList(log.topics)) - .build()).filter(Objects::nonNull).collect(Collectors.toList()); + // Can't use parallel streams here since we need to compute cumulativeNrg, which is done iteratively + for (AionTransaction tx : txs) { + AionTxInfo ti = this.ac.getAionHub().getBlockchain().getTransactionInfo(tx.getHash()); + cumulativeNrg += ti.getReceipt().getEnergyUsed(); + TxRecpt rt = new TxRecpt(b, ti, cumulativeNrg); + + List tles = Arrays.asList(rt.logs).parallelStream() + .map(log -> { + return Message.t_LgEle.newBuilder() + .setData(ByteString.copyFrom(ByteUtil.hexStringToBytes(log.data))) + .setAddress(ByteString.copyFrom(Address.wrap(log.address).toBytes())) + .addAllTopics(Arrays.asList(log.topics)) + .build(); + }).filter(Objects::nonNull).collect(Collectors.toList()); Message.t_TxDetail.Builder tdBuilder = Message.t_TxDetail.newBuilder() .setData(ByteString.copyFrom(tx.getData())) @@ -1549,8 +1547,8 @@ private List getRsp_getBlockDetails(List getRsp_getBlockDetails(List> getBlkAndDifficultyForBlkNumList(List blkNum) { + return blkNum.parallelStream() + .map(n -> { + AionBlock b = this.getBlock(n); + return Map.entry(b, this.ac.getAionHub().getBlockStore().getTotalDifficultyForHash(b.getHash())); + }) + .collect(Collectors.toList()); + } + @Override public byte getApiVersion() { return JAVAAPI_VAR; diff --git a/modP2p/src/org/aion/p2p/INode.java b/modP2p/src/org/aion/p2p/INode.java index fc9bcec8c1..ada20e739f 100644 --- a/modP2p/src/org/aion/p2p/INode.java +++ b/modP2p/src/org/aion/p2p/INode.java @@ -68,15 +68,15 @@ public interface INode { long getBestBlockNumber(); /** - * @return long + * @return BigInteger */ - long getTotalDifficulty(); + byte[] getTotalDifficulty(); /** * @param _bestBlockNumber long * @param _bestBlockHash byte[] * @param _totalDifficulty long */ - void updateStatus(long _bestBlockNumber, final byte[] _bestBlockHash, long _totalDifficulty); + void updateStatus(long _bestBlockNumber, final byte[] _bestBlockHash, final byte[] _totalDifficulty); } diff --git a/modP2p/src/org/aion/p2p/INodeMgr.java b/modP2p/src/org/aion/p2p/INodeMgr.java new file mode 100644 index 0000000000..fc37705bed --- /dev/null +++ b/modP2p/src/org/aion/p2p/INodeMgr.java @@ -0,0 +1,9 @@ +package org.aion.p2p; + +import org.aion.p2p.INode; + +public interface INodeMgr { + + void updateAllNodesInfo(INode _n); + +} diff --git a/modP2p/src/org/aion/p2p/IP2pMgr.java b/modP2p/src/org/aion/p2p/IP2pMgr.java index 7af286f213..7a875b06d8 100644 --- a/modP2p/src/org/aion/p2p/IP2pMgr.java +++ b/modP2p/src/org/aion/p2p/IP2pMgr.java @@ -28,20 +28,24 @@ import java.util.List; import java.util.Map; + /** * * @author chris * */ -public interface IP2pMgr{ +public interface IP2pMgr { /** * @return Map */ Map getActiveNodes(); + + INodeMgr getNodeMgr(); /** - * @param _hs List + * @param _hs + * List */ void register(final List _hs); @@ -51,15 +55,15 @@ public interface IP2pMgr{ INode getRandom(); /** - * @param _id int - * @param _msg Msg + * @param _id + * int + * @param _msg + * Msg */ void send(int _id, final Msg _msg); /** - * Used to hook up with kernel - * to shutdown threads in network - * module + * Used to hook up with kernel to shutdown threads in network module */ void shutdown(); diff --git a/modP2p/src/org/aion/p2p/NodeRandPolicy.java b/modP2p/src/org/aion/p2p/NodeRandPolicy.java new file mode 100644 index 0000000000..507eb98abd --- /dev/null +++ b/modP2p/src/org/aion/p2p/NodeRandPolicy.java @@ -0,0 +1,5 @@ +package org.aion.p2p; + +public enum NodeRandPolicy { + RND, SYNC, REALTIME; +} diff --git a/modP2pImpl/build.xml b/modP2pImpl/build.xml index ddeb7430f6..a1a3d2242f 100644 --- a/modP2pImpl/build.xml +++ b/modP2pImpl/build.xml @@ -16,6 +16,7 @@ + diff --git a/modP2pImpl/module-info.java b/modP2pImpl/module-info.java index 83be492ae3..b35397be18 100644 --- a/modP2pImpl/module-info.java +++ b/modP2pImpl/module-info.java @@ -1,4 +1,5 @@ module aion.p2p.impl { requires aion.p2p; + requires miniupnpc.linux; exports org.aion.p2p.impl; } \ No newline at end of file diff --git a/modP2pImpl/src/org/aion/p2p/impl/ChannelBuffer.java b/modP2pImpl/src/org/aion/p2p/impl/ChannelBuffer.java index 28f2dc7f30..5922e43a2d 100644 --- a/modP2pImpl/src/org/aion/p2p/impl/ChannelBuffer.java +++ b/modP2pImpl/src/org/aion/p2p/impl/ChannelBuffer.java @@ -26,8 +26,11 @@ package org.aion.p2p.impl; import org.aion.p2p.Header; +import org.aion.p2p.Msg; + import java.nio.ByteBuffer; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; import java.util.concurrent.atomic.AtomicBoolean; /** @@ -47,6 +50,11 @@ class ChannelBuffer { byte[] body = null; + /** + * write flag + */ + public AtomicBoolean onWrite = new AtomicBoolean(false); + void refreshHeader(){ headerBuf.clear(); header = null; @@ -71,6 +79,7 @@ boolean isBodyCompleted() { return header != null && body != null && body.length == header.getLen(); } - public AtomicBoolean onWrite = new AtomicBoolean(false); + + public BlockingQueue msgs = new ArrayBlockingQueue<>(10); } diff --git a/modP2pImpl/src/org/aion/p2p/impl/Node.java b/modP2pImpl/src/org/aion/p2p/impl/Node.java index 33c1217d50..dea83d6bb9 100644 --- a/modP2pImpl/src/org/aion/p2p/impl/Node.java +++ b/modP2pImpl/src/org/aion/p2p/impl/Node.java @@ -39,17 +39,20 @@ * node-id could be any non-empty string update to 36 bytes * */ -public final class Node implements INode{ +public final class Node implements INode { private boolean fromBootList; /** - * id != "" && version != "" && node on pending nodes => move to active nodes + * id != "" && version != "" && node on pending nodes => move to active + * nodes */ private byte[] id; // 36 bytes private int idHash; + private int fullHash = -1; + /** * for display only */ @@ -61,7 +64,8 @@ public final class Node implements INode{ private String ipStr; - private int port; + private int port = -1; + private int portConnected = -1; private long timestamp; @@ -69,20 +73,31 @@ public final class Node implements INode{ private byte[] bestBlockHash; - private long totalDifficulty; + private byte[] totalDifficulty; private SocketChannel channel; - private static final Pattern IPV4 = Pattern.compile( - "^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$"); + private String type = ""; + + private static final String REGEX_PROTOCOL = "^p2p://"; // Protocol eg. p2p:// + private static final String REGEX_NODE_ID = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}"; // Node-Id eg. 3e2cab6a-09dd-4771-b28d-6aa674009796 + private static final String REGEX_IPV4 = "(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])"; // Ip eg. 127.0.0.1 + private static final String REGEX_PORT = "[0-9]+$"; // Port eg. 30303 + + private static final Pattern PATTERN_P2P = Pattern.compile(REGEX_PROTOCOL + REGEX_NODE_ID + "@" + REGEX_IPV4 + ":" + REGEX_PORT); + + private static final int SIZE_BYTES_IPV4 = 8; + PeerMetric peerMetric = new PeerMetric(); /** - * constructor for initial stage of connections from network + * constructor for initial stage of connections from network */ Node(boolean fromBootList, String _ipStr) { this.fromBootList = fromBootList; - this.id = new byte[36]; + + // if id is not gathered, leave it empty + // this.id = new byte[36]; this.idHash = 0; this.version = 0; this.ip = ipStrToBytes(_ipStr); @@ -92,13 +107,27 @@ public final class Node implements INode{ this.bestBlockNumber = 0L; } + Node(String _ipStr, int port, int portConnected) { + this.fromBootList = false; + // if id is not gathered, leave it empty + // this.id = new byte[36]; + this.idHash = 0; + this.version = 0; + this.ip = ipStrToBytes(_ipStr); + this.ipStr = _ipStr; + this.port = port; + this.portConnected = portConnected; + this.timestamp = System.currentTimeMillis(); + this.bestBlockNumber = 0L; + } + /** - * constructor for initial stage of boot nodes from config + * constructor for initial stage of boot nodes from config */ public Node(boolean fromBootList, final byte[] _id, final byte[] _ip, final int _port) { this.fromBootList = fromBootList; this.id = _id; - if(_id != null && _id.length == 36) { + if (_id != null && _id.length == 36) { this.idHash = Arrays.hashCode(_id); this.idShort = new String(Arrays.copyOfRange(_id, 0, 6)); } @@ -117,7 +146,7 @@ public Node(boolean fromBootList, final byte[] _id, final byte[] _ip, final int public static byte[] ipStrToBytes(final String _ip) { ByteBuffer bb8 = ByteBuffer.allocate(8); String[] frags = _ip.split("\\."); - for(String frag : frags) { + for (String frag : frags) { short ipFrag; try { ipFrag = Short.parseShort(frag); @@ -134,33 +163,17 @@ public static byte[] ipStrToBytes(final String _ip) { * @return String */ static String ipBytesToStr(final byte[] _ip) { - ByteBuffer bb2 = ByteBuffer.allocate(2); - if(_ip == null || _ip.length != 8) + if(_ip == null || _ip.length != SIZE_BYTES_IPV4) return ""; else { + short[] shorts = new short[_ip.length/2]; + ByteBuffer.wrap(_ip).asShortBuffer().get(shorts); + String ip = ""; - bb2.put(_ip[0]); - bb2.put(_ip[1]); - bb2.flip(); - ip += bb2.getShort() + "."; - - bb2.clear(); - bb2.put(_ip[2]); - bb2.put(_ip[3]); - bb2.flip(); - ip += bb2.getShort() + "."; - - bb2.clear(); - bb2.put(_ip[4]); - bb2.put(_ip[5]); - bb2.flip(); - ip += bb2.getShort() + "."; - - bb2.clear(); - bb2.put(_ip[6]); - bb2.put(_ip[7]); - bb2.flip(); - ip += bb2.getShort(); + for (int i = 0; i < shorts.length; i++) { + ip += shorts[i] + (i < shorts.length - 1 ? "." : ""); + } + return ip; } } @@ -170,28 +183,32 @@ static String ipBytesToStr(final byte[] _ip) { * @return Node * TODO: ugly */ - static Node parseP2p(String _p2p) { + public static Node parseP2p(String _p2p) { + if (!PATTERN_P2P.matcher(_p2p).matches()) + return null; + String[] arrs = _p2p.split("@"); byte[] _tempBytes = arrs[0].getBytes(); - if(_tempBytes.length != 42) - return null; + byte[] _id = Arrays.copyOfRange(_tempBytes, 6, 42); String[] subArrs = arrs[1].split(":"); - if(!IPV4.matcher(subArrs[0]).matches()) - return null; - byte[] _ip = ipStrToBytes(subArrs[0]); - int _port = Integer.parseInt(subArrs[1]); + int _port = Integer.parseInt(subArrs[1]); + return new Node(true, _id, _ip, _port); } + void setFromBootList(boolean _ifBoot) { + this.fromBootList = _ifBoot; + } + /** * @param _id byte[] */ void setId(final byte[] _id) { this.id = _id; - if(_id != null && _id.length == 36) { + if (_id != null && _id.length == 36) { this.idHash = Arrays.hashCode(_id); this.idShort = new String(Arrays.copyOfRange(_id, 0, 6)); } @@ -211,9 +228,13 @@ void setPort(final int _port) { this.port = _port; } + void setPortConnected(final int _port) { + this.portConnected = _port; + } + /** - * this method used to keep current node stage - * on either pending list or active list + * this method used to keep current node stage on either pending list or + * active list */ void refreshTimestamp() { this.timestamp = System.currentTimeMillis(); @@ -226,6 +247,13 @@ void setChannel(final SocketChannel _channel) { this.channel = _channel; } + /** + * @param _type String + */ + void setType(String _type) { + this.type = _type; + } + /** * @return boolean */ @@ -246,13 +274,19 @@ public byte[] getIp() { } @Override - public String getIpStr(){ return this.ipStr; } + public String getIpStr() { + return this.ipStr; + } @Override public int getPort() { return this.port; } + public int getConnectedPort() { + return portConnected; + } + /** * @return long */ @@ -277,29 +311,71 @@ public int getIdHash() { return this.idHash; } + String getType() { + return this.type; + } + + boolean hasFullInfo() { + return (id != null) && (ip != null) && (port > 0); + } + + int getFullHash() { + if (fullHash > 0) + return fullHash; + else { + if (hasFullInfo()) { + ByteBuffer bb = ByteBuffer.allocate(id.length + ip.length + 4); + bb.putInt(port); + bb.put(id); + bb.put(ip); + return Arrays.hashCode(bb.array()); + } + } + return -1; + } + @Override - public String getIdShort() {return this.idShort == null ? "" : this.idShort; } + public String getIdShort() { + return this.idShort == null ? "" : this.idShort; + } @Override public long getBestBlockNumber() { return this.bestBlockNumber; } -// byte[] getBestBlockHash() { -// return this.bestBlockHash; -// } + byte[] getBestBlockHash() { + return this.bestBlockHash; + } @Override - public long getTotalDifficulty() { + public byte[] getTotalDifficulty() { return this.totalDifficulty; } @Override - public void updateStatus(long _bestBlockNumber, final byte[] _bestBlockHash, long _totalDifficulty) { - if(_bestBlockNumber > this.bestBlockNumber){ + public void updateStatus(long _bestBlockNumber, final byte[] _bestBlockHash, final byte[] _totalDifficulty) { + if (_bestBlockNumber > this.bestBlockNumber) { this.bestBlockNumber = _bestBlockNumber; this.bestBlockHash = _bestBlockHash; this.totalDifficulty = _totalDifficulty; } } + + void copyNodeStatus(Node _n) { + if (_n.bestBlockNumber > this.bestBlockNumber) { + this.bestBlockNumber = _n.getBestBlockNumber(); + this.bestBlockHash = _n.bestBlockHash; + this.totalDifficulty = _n.getTotalDifficulty(); + } + } + + @Override + public boolean equals(Object o) { + if (o instanceof Node) { + Node other = (Node) o; + return this.getFullHash() == other.getFullHash(); + } + return false; + } } diff --git a/modP2pImpl/src/org/aion/p2p/impl/NodeMgr.java b/modP2pImpl/src/org/aion/p2p/impl/NodeMgr.java new file mode 100644 index 0000000000..38521a4423 --- /dev/null +++ b/modP2pImpl/src/org/aion/p2p/impl/NodeMgr.java @@ -0,0 +1,342 @@ +/* + * Copyright (c) 2017-2018 Aion foundation. + * + * This file is part of the aion network project. + * + * The aion network project is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or any later version. + * + * The aion network project is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the aion network project source files. + * If not, see . + * + * Contributors to the aion source files in decreasing order of code volume: + * + * Aion foundation. + * + */ + +package org.aion.p2p.impl; + +import java.math.BigInteger; +import java.util.*; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedBlockingQueue; + +import org.aion.p2p.INode; +import org.aion.p2p.INodeMgr; + +public class NodeMgr implements INodeMgr { + + private final static int TIMEOUT_ACTIVE_NODES = 30000; + private final static int TIMEOUT_INBOUND_NODES = 10000; + + private final Set seedIps = new HashSet<>(); + private final Map allNodes = new ConcurrentHashMap<>(); + private final BlockingQueue tempNodes = new LinkedBlockingQueue<>(); + private final Map outboundNodes = new ConcurrentHashMap<>(); + private final Map inboundNodes = new ConcurrentHashMap<>(); + private final Map activeNodes = new ConcurrentHashMap<>(); + + Map getOutboundNodes() { + return outboundNodes; + } + + public void dumpAllNodeInfo() { + StringBuilder sb = new StringBuilder(); + sb.append(" ==================== ALL PEERS METRIC ===========================\n"); + List all = new ArrayList<>(allNodes.values()); + all.sort((a, b) -> (int) (b.getBestBlockNumber() - a.getBestBlockNumber())); + int cnt = 0; + for (Node n : all) { + char isSeed = n.getIfFromBootList() ? 'Y' : 'N'; + sb.append(String.format(" %3d ID:%6s SEED:%c IP:%15s PORT:%5d PORT_CONN:%5d FC:%1d BB:%8d \n", cnt, + n.getIdShort(), isSeed, n.getIpStr(), n.getPort(), n.getConnectedPort(), + n.peerMetric.metricFailedConn, n.getBestBlockNumber())); + cnt++; + } + System.out.println(sb.toString()); + } + + /** + * + * @param selfShortId String + */ + void dumpNodeInfo(String selfShortId) { + StringBuilder sb = new StringBuilder(); + sb.append("\n"); + sb.append(String.format(" ================== p2p-status-%6s ==================\n", selfShortId)); + sb.append(String.format(" temp[%d] inbound[%d] outbound[%d]\n", + tempNodesSize(), + inboundNodes.size(), + outboundNodes.size() + )); + List sorted = new ArrayList<>(activeNodes.values()); + if(sorted.size() > 0){ + sb.append(" -------------------------------------------------------\n"); + sb.append(" seed blk td id ip port type\n"); + sorted.sort((n1, n2) -> Long.compare(n2.getBestBlockNumber(), n1.getBestBlockNumber())); + for (Node n : sorted) { + sb.append( + String.format(" %c%10d %16s %6s %15s %5d %8s\n", + n.getIfFromBootList() ? 0x221A : ' ', + n.getBestBlockNumber(), + n.getTotalDifficulty() == null ? "0" : new BigInteger(1, n.getTotalDifficulty()).toString(10), + n.getIdShort(), + n.getIpStr(), + n.getPort(), + n.getType() + ) + ); + } + } + sb.append("\n"); + System.out.println(sb.toString()); + } + + private void updateMetric(final Node _n) { + if (_n.hasFullInfo()) { + int fullHash = _n.getFullHash(); + if (allNodes.containsKey(fullHash)) { + Node orig = allNodes.get(fullHash); + + // pull out metric. + _n.peerMetric = orig.peerMetric; + _n.copyNodeStatus(orig); + } + allNodes.put(fullHash, _n); + } + } + + public void updateAllNodesInfo(INode _n) { + Node n = (Node) _n; + + if (n.hasFullInfo()) { + int fullHash = n.getFullHash(); + if (allNodes.containsKey(fullHash)) { + Node orig = allNodes.get(fullHash); + // pull out metric. + orig.copyNodeStatus(n); + } + } + } + + /** + * @param _n Node + */ + void tempNodesAdd(final Node _n) { + if (!tempNodes.contains(_n)) { + updateMetric(_n); + tempNodes.add(_n); + } + } + + /** + * @param _ip String + */ + void seedIpAdd(String _ip){ + this.seedIps.add(_ip); + } + + void inboundNodeAdd(final Node _n) { + updateMetric(_n); + inboundNodes.put(_n.getChannel().hashCode(), _n); + } + + synchronized Node tempNodesTake() throws InterruptedException { + return tempNodes.take(); + } + + int tempNodesSize() { + return tempNodes.size(); + } + + /** + * for test + */ + void clearTempNodes(){ + this.tempNodes.clear(); + } + + int activeNodesSize() { + return activeNodes.size(); + } + + boolean hasActiveNode(int k) { + return activeNodes.containsKey(k); + } + + Node getActiveNode(int k) { + return activeNodes.get(k); + } + + Node getInboundNode(int k) { + return inboundNodes.get(k); + } + + Map getNodes() { + return allNodes; + } + + Node allocNode(String ip, int p0, int p1) { + return new Node(ip, p0, p1); + } + + List getActiveNodesList() { + return new ArrayList(activeNodes.values()); + } + + Map getActiveNodesMap() { + return new HashMap(activeNodes); + } + + INode getRandom() { + int nodesCount = activeNodes.size(); + if (nodesCount > 0) { + Random r = new Random(System.currentTimeMillis()); + List keysArr = new ArrayList<>(activeNodes.keySet()); + try { + int randomNodeKeyIndex = r.nextInt(keysArr.size()); + int randomNodeKey = keysArr.get(randomNodeKeyIndex); + return this.getActiveNode(randomNodeKey); + } catch (IllegalArgumentException e) { + System.out.println(""); + return null; + } + } else + return null; + } + + public INode getRandomRealtime(long bbn) { + + List keysArr = new ArrayList<>(); + + for (Node n : activeNodes.values()) { + if ((n.getBestBlockNumber() == 0) || (n.getBestBlockNumber() > bbn)) { + keysArr.add(n.getIdHash()); + } + } + + int nodesCount = keysArr.size(); + if (nodesCount > 0) { + Random r = new Random(System.currentTimeMillis()); + + try { + int randomNodeKeyIndex = r.nextInt(keysArr.size()); + int randomNodeKey = keysArr.get(randomNodeKeyIndex); + return this.getActiveNode(randomNodeKey); + } catch (IllegalArgumentException e) { + return null; + } + } else + return null; + } + + /** + * @param _nodeIdHash int + * @param _shortId String + * @param _p2pMgr P2pMgr + */ + void moveOutboundToActive(int _nodeIdHash, String _shortId, final P2pMgr _p2pMgr) { + Node node = outboundNodes.remove(_nodeIdHash); + if (node != null) { + node.setType("outbound"); + INode previous = activeNodes.putIfAbsent(_nodeIdHash, node); + if (previous != null) + _p2pMgr.closeSocket(node.getChannel()); + else { + if (_p2pMgr.showLog) + System.out.println(""); + } + } + } + + /** + * @param _channelHashCode int + * @param _p2pMgr P2pMgr + */ + void moveInboundToActive(int _channelHashCode, final P2pMgr _p2pMgr) { + Node node = inboundNodes.remove(_channelHashCode); + if (node != null) { + node.setType("inbound"); + node.setFromBootList(seedIps.contains(node.getIpStr())); + INode previous = activeNodes.putIfAbsent(node.getIdHash(), node); + if (previous != null) + _p2pMgr.closeSocket(node.getChannel()); + else { + if (_p2pMgr.showLog) + System.out.println(""); + } + } + } + + void rmMetricFailedNodes() { + { + Iterator nodesIt = tempNodes.iterator(); + while (nodesIt.hasNext()) { + Node n = (Node) nodesIt.next(); + if (n.peerMetric.shouldNotConn()) + tempNodes.remove(n); + } + } + } + + void rmTimeOutInbound(P2pMgr pmgr) { + { + Iterator inboundIt = inboundNodes.keySet().iterator(); + while (inboundIt.hasNext()) { + int key = (int) inboundIt.next(); + Node node = inboundNodes.get(key); + if (System.currentTimeMillis() - node.getTimestamp() > TIMEOUT_INBOUND_NODES) { + + pmgr.closeSocket(node.getChannel()); + + inboundIt.remove(); + + if (pmgr.showLog) + System.out.println(""); + } + } + } + } + + void rmTimeOutActives(P2pMgr pmgr) { + Iterator activeIt = activeNodes.keySet().iterator(); + while (activeIt.hasNext()) { + int key = (int) activeIt.next(); + Node node = getActiveNode(key); + if (System.currentTimeMillis() - node.getTimestamp() > TIMEOUT_ACTIVE_NODES) { + + pmgr.closeSocket(node.getChannel()); + activeIt.remove(); + if (pmgr.showLog) + System.out.println(""); + } + } + } + + /** + * @param _p2pMgr P2pMgr + */ + void shutdown(final P2pMgr _p2pMgr) { + try { + activeNodes.forEach((k, n) -> _p2pMgr.closeSocket(n.getChannel())); + activeNodes.clear(); + outboundNodes.forEach((k, n) -> _p2pMgr.closeSocket(n.getChannel())); + outboundNodes.clear(); + inboundNodes.forEach((k, n) -> _p2pMgr.closeSocket(n.getChannel())); + inboundNodes.clear(); + } catch (Exception e) { + + } + } + +} diff --git a/modP2pImpl/src/org/aion/p2p/impl/P2pMgr.java b/modP2pImpl/src/org/aion/p2p/impl/P2pMgr.java index 342481c0e7..beddbfb3d5 100644 --- a/modP2pImpl/src/org/aion/p2p/impl/P2pMgr.java +++ b/modP2pImpl/src/org/aion/p2p/impl/P2pMgr.java @@ -27,7 +27,6 @@ import java.io.IOException; import java.net.InetSocketAddress; -import java.net.Socket; import java.net.StandardSocketOptions; import java.nio.ByteBuffer; import java.nio.channels.SelectionKey; @@ -39,7 +38,6 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; -import java.util.stream.Collectors; import org.aion.p2p.*; import org.aion.p2p.impl.msg.ReqHandshake; @@ -47,42 +45,36 @@ import org.aion.p2p.impl.msg.ResHandshake; /** - * @author Chris - * aion0 p2p implementation p2p://{uuid}@{ip}:{port} eg: - * p2p://3e2cab6a-09dd-4771-b28d-6aa674009796@127.0.0.1:30303 TODO: 1) - * simplify id bytest to int, ip bytest to str 2) upnp protocal 3) - * framing + * @author Chris p2p://{uuid}@{ip}:{port} TODO: 1) simplify id bytest to int, ip + * bytest to str 2) upnp protocal 3) framing */ public final class P2pMgr implements IP2pMgr { private final static int PERIOD_SHOW_STATUS = 10000; private final static int PERIOD_REQUEST_ACTIVE_NODES = 1000; - private final static int PERIOD_CONNECT_OUTBOUND = 2000; + private final static int PERIOD_CONNECT_OUTBOUND = 1000; private final static int PERIOD_CLEAR = 20000; private final static int TIMEOUT_OUTBOUND_CONNECT = 10000; private final static int TIMEOUT_OUTBOUND_NODES = 10000; - private final static int TIMEOUT_INBOUND_NODES = 10000; - private final static int TIMEOUT_ACTIVE_NODES = 30000; + private final static int PERIOD_UPNP_PORT_MAPPING = 3600000; + private final static int TIMEOUT_MSG_READ = 10000; private final int maxTempNodes; private final int maxActiveNodes; private final boolean showStatus; - private final boolean showLog; + final boolean showLog; private final int selfNodeIdHash; private String selfShortId; private final byte[] selfIp; private final int selfPort; private final boolean upnpEnable; - private final BlockingQueue tempNodes = new LinkedBlockingQueue<>(); - private final Map outboundNodes = new ConcurrentHashMap<>(); - private final Map inboundNodes = new ConcurrentHashMap<>(); - private final Map activeNodes = new ConcurrentHashMap<>(); private final Map> handlers = new ConcurrentHashMap<>(); + private NodeMgr nodeMgr = new NodeMgr(); private ServerSocketChannel tcpServer; private Selector selector; private Lock selectorLock = new ReentrantLock(); @@ -130,7 +122,6 @@ public void run() { } catch (IOException | NullPointerException e) { if (showLog) { System.out.println(""); - //e.printStackTrace(); } closeSocket((SocketChannel) sk.channel()); } @@ -146,17 +137,8 @@ private final class TaskStatus implements Runnable { @Override public void run() { Thread.currentThread().setName("p2p-ts"); - System.out.println("[p2p-status " + selfShortId + "]"); - System.out.println("[temp-nodes-size=" + tempNodes.size() + "]"); - //System.out.println("[inbound-nodes-size=" + inboundNodes.size() + "]"); - //System.out.println("[outbound-nodes-size=" + outboundNodes.size() + "]"); - - List list = new ArrayList<>(activeNodes.values()); - list.sort((e1, e2) -> Long.compare(e2.getBestBlockNumber(), e1.getBestBlockNumber())); - System.out.println("[active-nodes(nodeIdHash)=[" + list.stream() - .map((entry) -> "\n" + entry.getBestBlockNumber() + "-" + entry.getIdShort() - + "-" + entry.getIpStr() + (entry.getIfFromBootList() ? "-seed" : "")) - .collect(Collectors.joining(",")) + "]]"); + nodeMgr.dumpNodeInfo(selfShortId); + nodeMgr.dumpAllNodeInfo(); } } @@ -172,7 +154,7 @@ public void run() { System.out.println(""); } - if(P2pMgr.this.activeNodes.size() >= P2pMgr.this.maxActiveNodes){ + if (nodeMgr.activeNodesSize() >= maxActiveNodes) { if (showLog) System.out.println(""); return; @@ -180,23 +162,28 @@ public void run() { Node node; try { - node = tempNodes.take(); + node = nodeMgr.tempNodesTake(); if (node.getIfFromBootList()) - tempNodes.add(node); + nodeMgr.tempNodesAdd(node); + if (node.peerMetric.shouldNotConn()) { + continue; + } } catch (InterruptedException e) { if (showLog) System.out.println(""); return; } int nodeIdHash = node.getIdHash(); - if (!outboundNodes.containsKey(nodeIdHash) && !activeNodes.containsKey(nodeIdHash)) { - + if (!nodeMgr.getOutboundNodes().containsKey(nodeIdHash) && !nodeMgr.hasActiveNode(nodeIdHash)) { int _port = node.getPort(); try { SocketChannel channel = SocketChannel.open(); if (showLog) System.out.println(""); - channel.socket().connect(new InetSocketAddress(node.getIpStr(), _port), TIMEOUT_OUTBOUND_CONNECT); + channel.socket().connect( + new InetSocketAddress(node.getIpStr(), _port), + TIMEOUT_OUTBOUND_CONNECT + ); configChannel(channel); if (channel.finishConnect() && channel.isConnected()) { @@ -205,19 +192,29 @@ public void run() { ChannelBuffer rb = new ChannelBuffer(); rb.nodeIdHash = nodeIdHash; sk.attach(rb); + node.setChannel(channel); + node.setPortConnected(channel.socket().getLocalPort()); + addOutboundNode(node); selectorLock.unlock(); workers.submit(new TaskWrite(node.getIdShort(), channel, cachedReqHandshake, rb)); if (showLog) - System.out.println(""); + System.out.println(""); + + node.peerMetric.decFailedCount(); + } else { channel.close(); + node.peerMetric.incFailedCount(); } } catch (IOException e) { if (showLog) - System.out.println(""); + System.out.println(""); + node.peerMetric.incFailedCount(); } } } @@ -232,22 +229,14 @@ public void run() { try { Thread.sleep(PERIOD_CLEAR); - Iterator inboundIt = P2pMgr.this.inboundNodes.keySet().iterator(); - while (inboundIt.hasNext()) { - int key = (int) inboundIt.next(); - Node node = P2pMgr.this.inboundNodes.get(key); - if (System.currentTimeMillis() - node.getTimestamp() > TIMEOUT_INBOUND_NODES) { - selectorLock.lock(); - closeSocket(node.getChannel()); - selectorLock.unlock(); - inboundIt.remove(); + selectorLock.lock(); + nodeMgr.rmTimeOutInbound(P2pMgr.this); + selectorLock.unlock(); - if (showLog) - System.out.println(""); - } - } + // clean up temp nodes list if metric failed. + nodeMgr.rmMetricFailedNodes(); - Iterator outboundIt = P2pMgr.this.outboundNodes.keySet().iterator(); + Iterator outboundIt = nodeMgr.getOutboundNodes().keySet().iterator(); while (outboundIt.hasNext()) { Object obj = outboundIt.next(); @@ -255,8 +244,8 @@ public void run() { if (obj == null) continue; - int nodeIdHash = (int)obj; - Node node = P2pMgr.this.outboundNodes.get(nodeIdHash); + int nodeIdHash = (int) obj; + Node node = nodeMgr.getOutboundNodes().get(nodeIdHash); if (node == null) continue; @@ -272,36 +261,24 @@ public void run() { } } - Iterator activeIt = P2pMgr.this.activeNodes.keySet().iterator(); - while (activeIt.hasNext()) { - int key = (int) activeIt.next(); - Node node = P2pMgr.this.activeNodes.get(key); - if (System.currentTimeMillis() - node.getTimestamp() > TIMEOUT_ACTIVE_NODES) { - selectorLock.lock(); - closeSocket(node.getChannel()); - selectorLock.unlock(); - activeIt.remove(); + selectorLock.lock(); + nodeMgr.rmTimeOutActives(P2pMgr.this); + selectorLock.unlock(); - if (showLog) - System.out.println(""); - } - } } catch (Exception e) { -// if(showLog) -// e.printStackTrace(); } } } } - final class TaskWrite implements Runnable { + private final class TaskWrite implements Runnable { private String nodeShortId; private SocketChannel sc; private Msg msg; private ChannelBuffer channelBuffer; - public TaskWrite(String _nodeShortId, final SocketChannel _sc, final Msg _msg, final ChannelBuffer _cb){ + TaskWrite(String _nodeShortId, final SocketChannel _sc, final Msg _msg, final ChannelBuffer _cb) { this.nodeShortId = _nodeShortId; this.sc = _sc; this.msg = _msg; @@ -313,7 +290,7 @@ public void run() { Thread.currentThread().setName("p2p-write"); // NOTE: the following logic may cause message loss - if(this.channelBuffer != null && this.channelBuffer.onWrite.compareAndSet(false, true)) { + if (this.channelBuffer.onWrite.compareAndSet(false, true)) { /* * @warning header set len (body len) before header encode */ @@ -323,7 +300,7 @@ public void run() { h.setLen(bodyLen); byte[] headerBytes = h.encode(); - //System.out.println("out " + h.getVer() + "-" + h.getCtrl() + "-" + h.getAction()); + //System.out.println("write " + h.getCtrl() + "-" + h.getAction()); ByteBuffer buf = ByteBuffer.allocate(headerBytes.length + bodyLen); buf.put(headerBytes); if (bodyBytes != null) @@ -337,41 +314,45 @@ public void run() { } catch (IOException e) { if (showLog) { System.out.println(""); - // e.printStackTrace(); } - } - finally { + } finally { this.channelBuffer.onWrite.set(false); -// if (buf.hasRemaining()) -// dropActive(_nodeIdHash, _nodeShortId, "timeout-write-msg"); + try { + + Msg msg = this.channelBuffer.msgs.poll(1, TimeUnit.MILLISECONDS); + + if (msg != null) { + //System.out.println("write " + h.getCtrl() + "-" + h.getAction()); + workers.submit(new TaskWrite(nodeShortId, sc, msg, channelBuffer)); + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } else { + try { + this.channelBuffer.msgs.put(msg); + } catch (InterruptedException e) { + e.printStackTrace(); } } + } } /** - * @param _nodeId byte[36] - * @param _ip String - * @param _port int - * @param _bootNodes String[] - * @param _upnpEnable boolean - * @param _maxTempNodes int + * @param _nodeId byte[36] + * @param _ip String + * @param _port int + * @param _bootNodes String[] + * @param _upnpEnable boolean + * @param _maxTempNodes int * @param _maxActiveNodes int - * @param _showStatus boolean - * @param _showLog boolean - * + * @param _showStatus boolean + * @param _showLog boolean */ - public P2pMgr( - String _nodeId, - String _ip, - int _port, - final String[] _bootNodes, - boolean _upnpEnable, - int _maxTempNodes, - int _maxActiveNodes, - boolean _showStatus, - boolean _showLog - ) { + public P2pMgr(String _nodeId, String _ip, int _port, final String[] _bootNodes, boolean _upnpEnable, + int _maxTempNodes, int _maxActiveNodes, boolean _showStatus, boolean _showLog) { byte[] selfNodeId = _nodeId.getBytes(); this.selfNodeIdHash = Arrays.hashCode(selfNodeId); this.selfShortId = new String(Arrays.copyOfRange(selfNodeId, 0, 6)); @@ -386,8 +367,9 @@ public P2pMgr( for (String _bootNode : _bootNodes) { Node node = Node.parseP2p(_bootNode); - if (validateNode(node)) { - tempNodes.add(node); + if (node != null && validateNode(node)) { + nodeMgr.tempNodesAdd(node); + nodeMgr.seedIpAdd(node.getIpStr()); } } @@ -399,9 +381,12 @@ public P2pMgr( * @return boolean */ private boolean validateNode(final Node _node) { - return _node != null && _node.getIdHash() != this.selfNodeIdHash - && !(Arrays.equals(selfIp, _node.getIp()) && selfPort == _node.getPort()) - && !activeNodes.containsKey(_node.getIdHash()) && !outboundNodes.containsKey(_node.getIdHash()); + boolean notNull = _node != null; + boolean notSelfId = _node.getIdHash() != this.selfNodeIdHash; + boolean notSameIpOrPort = !(Arrays.equals(selfIp, _node.getIp()) && selfPort == _node.getPort()); + boolean notActive = !nodeMgr.hasActiveNode(_node.getIdHash()); + boolean notOutbound = !nodeMgr.getOutboundNodes().containsKey(_node.getIdHash()); + return notNull && notSelfId && notSameIpOrPort && notActive && notOutbound; } /** @@ -418,7 +403,7 @@ private void configChannel(final SocketChannel _channel) throws IOException { /** * @param _sc SocketChannel */ - private void closeSocket(final SocketChannel _sc) { + void closeSocket(final SocketChannel _sc) { try { SelectionKey sk = _sc.keyFor(selector); _sc.close(); @@ -431,73 +416,16 @@ private void closeSocket(final SocketChannel _sc) { } /** - * @param _node Node self-check inbound timestamp and close if expired - */ - private void addInboundNode(final Node _node) { - SocketChannel sc = _node.getChannel(); - Node previous = inboundNodes.putIfAbsent(sc.hashCode(), _node); - if (previous != null) - closeSocket(_node.getChannel()); - } - - /** - * @param _node Node - * 1) leave outbound timestamp check to outbound connections process - * 2) add if no such connection or drop new if connection to target exists + * @param _node Node 1) leave outbound timestamp check to outbound connections + * process 2) add if no such connection or drop new if connection + * to target exists */ private void addOutboundNode(final Node _node) { - Node previous = outboundNodes.putIfAbsent(_node.getIdHash(), _node); + Node previous = nodeMgr.getOutboundNodes().putIfAbsent(_node.getIdHash(), _node); if (previous != null) closeSocket(_node.getChannel()); } - /** - * @param _channelHashCode int - */ - private void moveInboundToActive(int _channelHashCode) { - Node node = this.inboundNodes.remove(_channelHashCode); - if (node != null) { - INode previous = this.activeNodes.putIfAbsent(node.getIdHash(), node); - if (previous != null) - closeSocket(node.getChannel()); - else { - if (showLog) - System.out.println(""); - } - } - } - - /** - * @param _nodeIdHash int - */ - private void moveOutboundToActive(int _nodeIdHash, String _shortId) { - Node node = this.outboundNodes.remove(_nodeIdHash); - if (node != null) { - INode previous = this.activeNodes.putIfAbsent(_nodeIdHash, node); - if (previous != null) - closeSocket(node.getChannel()); - else { - if (showLog) - System.out.println(""); - } - } - } - -// /** -// * @param _nodeIdHash int -// * @param _reason String -// */ -// private void dropActive(int _nodeIdHash, String _reason, String _shortId) { -// Node node = activeNodes.remove(_nodeIdHash); -// if (node != null) { -// selectorLock.lock(); -// closeSocket(node.getChannel()); -// selectorLock.unlock(); -// if (showLog) -// System.out.println(""); -// } -// } - private void accept() { SocketChannel channel; try { @@ -508,9 +436,13 @@ private void accept() { sk.attach(new ChannelBuffer()); String ip = channel.socket().getInetAddress().getHostAddress(); - Node node = new Node(false, ip); + int port = channel.socket().getPort(); + + // Node node = new Node(false, ip); + Node node = nodeMgr.allocNode(ip, 0, port); + node.setChannel(channel); - addInboundNode(node); + nodeMgr.inboundNodeAdd(node); } catch (IOException e) { if (showLog) System.out.println(""); @@ -534,18 +466,19 @@ private void read(final SelectionKey _sk) throws IOException { // read header if (!rb.isHeaderCompleted()) { - readHeader((SocketChannel)_sk.channel(), rb); + readHeader((SocketChannel) _sk.channel(), rb); } // read body if (rb.isHeaderCompleted() && !rb.isBodyCompleted()) { - readBody((SocketChannel)_sk.channel(), rb); + readBody((SocketChannel) _sk.channel(), rb); } if (!rb.isBodyCompleted()) return; Header h = rb.header; + byte[] bodyBytes = Arrays.copyOf(rb.body, rb.body.length); rb.refreshHeader(); @@ -553,6 +486,9 @@ private void read(final SelectionKey _sk) throws IOException { byte ctrl = h.getCtrl(); byte act = h.getAction(); + + //System.out.println("read " + ctrl + "-" + act); + switch (ctrl) { case Ctrl.NET: handleP2pMsg(_sk, act, bodyBytes); @@ -572,13 +508,14 @@ private void read(final SelectionKey _sk) throws IOException { private void readHeader(final SocketChannel _sc, final ChannelBuffer _cb) throws IOException { int ret; - while ((ret = _sc.read(_cb.headerBuf)) > 0) {} + while ((ret = _sc.read(_cb.headerBuf)) > 0) { + } if (!_cb.headerBuf.hasRemaining()) { _cb.header = Header.decode(_cb.headerBuf.array()); } else { if (ret == -1) { - throw new IOException("read-header-eof"); + throw new IOException("read-header-eof"); } } } @@ -593,7 +530,8 @@ private void readBody(final SocketChannel _sc, final ChannelBuffer _cb) throws I _cb.bodyBuf = ByteBuffer.allocate(_cb.header.getLen()); int ret; - while ((ret = _sc.read(_cb.bodyBuf)) > 0) {} + while ((ret = _sc.read(_cb.bodyBuf)) > 0) { + } if (!_cb.bodyBuf.hasRemaining()) { _cb.body = _cb.bodyBuf.array(); @@ -605,31 +543,29 @@ private void readBody(final SocketChannel _sc, final ChannelBuffer _cb) throws I } /** - * @param _sk SelectionKey - * @param _act ACT + * @param _sk SelectionKey + * @param _act ACT * @param _msgBytes byte[] */ private void handleP2pMsg(final SelectionKey _sk, byte _act, final byte[] _msgBytes) { ChannelBuffer rb = (ChannelBuffer) _sk.attachment(); + //System.out.println("I am handle p2p msg !!!!!"); switch (_act) { case Act.REQ_HANDSHAKE: ReqHandshake reqHandshake = ReqHandshake.decode(_msgBytes); if (reqHandshake != null) { - Node node = inboundNodes.get(_sk.channel().hashCode()); + Node node = nodeMgr.getInboundNode(_sk.channel().hashCode()); if (node != null) { rb.nodeIdHash = Arrays.hashCode(reqHandshake.getNodeId()); node.setId(reqHandshake.getNodeId()); node.setVersion(reqHandshake.getVersion()); node.setPort(reqHandshake.getPort()); - moveInboundToActive(node.getChannel().hashCode()); - workers.submit(new TaskWrite( - node.getIdShort(), - node.getChannel(), - new ResHandshake(true), - rb - )); + + nodeMgr.moveInboundToActive(node.getChannel().hashCode(), this); + + workers.submit(new TaskWrite(node.getIdShort(), node.getChannel(), new ResHandshake(true), rb)); } } break; @@ -637,47 +573,43 @@ private void handleP2pMsg(final SelectionKey _sk, byte _act, final byte[] _msgBy case Act.RES_HANDSHAKE: ResHandshake resHandshake = ResHandshake.decode(_msgBytes); if (resHandshake != null && rb.nodeIdHash != 0 && resHandshake.getSuccess()) { - Node node = outboundNodes.get(rb.nodeIdHash); + Node node = nodeMgr.getOutboundNodes().get(rb.nodeIdHash); if (node != null) { node.refreshTimestamp(); - moveOutboundToActive(node.getIdHash(), node.getIdShort()); + nodeMgr.moveOutboundToActive(node.getIdHash(), node.getIdShort(), this); } } break; case Act.REQ_ACTIVE_NODES: if (rb.nodeIdHash != 0) { - Node node = activeNodes.get(rb.nodeIdHash); + Node node = nodeMgr.getActiveNode(rb.nodeIdHash); if (node != null) - workers.submit(new TaskWrite( - node.getIdShort(), - node.getChannel(), - new ResActiveNodes(new ArrayList(activeNodes.values())), - rb - )); + workers.submit(new TaskWrite(node.getIdShort(), node.getChannel(), + new ResActiveNodes(nodeMgr.getActiveNodesList()), rb)); } break; case Act.RES_ACTIVE_NODES: if (rb.nodeIdHash != 0) { - Node node = activeNodes.get(rb.nodeIdHash); + Node node = nodeMgr.getActiveNode(rb.nodeIdHash); if (node != null) { node.refreshTimestamp(); ResActiveNodes resActiveNodes = ResActiveNodes.decode(_msgBytes); if (resActiveNodes != null) { List incomingNodes = resActiveNodes.getNodes(); for (Node incomingNode : incomingNodes) { - if (tempNodes.size() >= this.maxTempNodes) + if (nodeMgr.tempNodesSize() >= this.maxTempNodes) return; if (validateNode(incomingNode)) - tempNodes.add(incomingNode); + nodeMgr.tempNodesAdd(incomingNode); } } } } break; default: - if(showLog) + if (showLog) System.out.println(""); break; } @@ -685,37 +617,37 @@ private void handleP2pMsg(final SelectionKey _sk, byte _act, final byte[] _msgBy /** * @param _nodeIdHash int - * @param _route int - * @param _msgBytes byte[] + * @param _route int + * @param _msgBytes byte[] */ private void handleKernelMsg(int _nodeIdHash, int _route, final byte[] _msgBytes) { - Node node = activeNodes.get(_nodeIdHash); + Node node = nodeMgr.getActiveNode(_nodeIdHash); if (node != null) { List hs = handlers.get(_route); if (hs == null) return; - for (Handler h : hs) { - if (h == null) + for (Handler hlr : hs) { + if (hlr == null) continue; node.refreshTimestamp(); - //System.out.println("in1 " + h.getHeader().getVer() + "-" + h.getHeader().getCtrl() + "-" + h.getHeader().getAction()); - workers.submit(() -> h.receive(node.getIdHash(), node.getIdShort(), _msgBytes)); + //System.out.println("I am handle kernel msg !!!!! " + hlr.getHeader().getCtrl() + "-" + hlr.getHeader().getAction() + "-" + hlr.getHeader().getLen()); + workers.submit(() -> hlr.receive(node.getIdHash(), node.getIdShort(), _msgBytes)); } } } - private void runUpnp() { - // TODO: implement + + public NodeMgr getNodeMgr() { + return this.nodeMgr; } @Override public void run() { try { - this.selector = Selector.open(); + selector = Selector.open(); scheduledWorkers = new ScheduledThreadPoolExecutor(1); - - workers = Executors.newFixedThreadPool(Math.max(Runtime.getRuntime().availableProcessors() * 2, 8)); + workers = Executors.newFixedThreadPool(Math.min(Runtime.getRuntime().availableProcessors() * 2, 16)); tcpServer = ServerSocketChannel.open(); tcpServer.configureBlocking(false); @@ -723,16 +655,18 @@ public void run() { tcpServer.socket().bind(new InetSocketAddress(Node.ipBytesToStr(selfIp), selfPort)); tcpServer.register(selector, SelectionKey.OP_ACCEPT); - if (this.upnpEnable) - runUpnp(); - Thread boss = new Thread(new TaskInbound(), "p2p-pi"); boss.setPriority(Thread.MAX_PRIORITY); boss.start(); + if (upnpEnable) + scheduledWorkers.scheduleWithFixedDelay(new TaskUPnPManager(selfPort), 1, PERIOD_UPNP_PORT_MAPPING, + TimeUnit.MILLISECONDS); + if (showStatus) scheduledWorkers.scheduleWithFixedDelay(new TaskStatus(), 2, PERIOD_SHOW_STATUS, TimeUnit.MILLISECONDS); - scheduledWorkers.scheduleWithFixedDelay(new TaskRequestActiveNodes(this), 5, PERIOD_REQUEST_ACTIVE_NODES, TimeUnit.MILLISECONDS); + scheduledWorkers.scheduleWithFixedDelay(new TaskRequestActiveNodes(this), 5000, PERIOD_REQUEST_ACTIVE_NODES, + TimeUnit.MILLISECONDS); workers.submit(new TaskClear()); workers.submit(new TaskConnectPeers()); @@ -744,27 +678,40 @@ public void run() { } @Override - public INode getRandom() { - int nodesCount = this.activeNodes.size(); - if (nodesCount > 0) { - Random r = new Random(System.currentTimeMillis()); - List keysArr = new ArrayList<>(this.activeNodes.keySet()); - try { - int randomNodeKeyIndex = r.nextInt(keysArr.size()); - int randomNodeKey = keysArr.get(randomNodeKeyIndex); - return this.activeNodes.get(randomNodeKey); - } catch (IllegalArgumentException e) { - if (showLog) - System.out.println(""); - return null; - } - } else - return null; + public INode getRandom(){ + return nodeMgr.getRandom(); + } + + public INode getRandom(NodeRandPolicy nrp, long bbn) { + switch (nrp) { + case RND: + break; + case REALTIME: + + // only fetch node with blocknumber > ( highest -128 ) + return nodeMgr.getRandomRealtime(bbn); + + case SYNC: + break; + } + + return nodeMgr.getRandom(); } @Override - public Map getActiveNodes() { - return this.activeNodes; + public Map getActiveNodes() { + return this.nodeMgr.getActiveNodesMap(); + } + + /** + * for test + */ + void clearTempNodes() { + this.nodeMgr.clearTempNodes(); + } + + int getTempNodesCount() { + return nodeMgr.tempNodesSize(); } @Override @@ -773,7 +720,7 @@ public void register(final List _cbs) { Header h = _cb.getHeader(); short ver = h.getVer(); byte ctrl = h.getCtrl(); - if(Ver.filter(ver) != Ver.UNKNOWN && Ctrl.filter(ctrl) != Ctrl.UNKNOWN){ + if (Ver.filter(ver) != Ver.UNKNOWN && Ctrl.filter(ctrl) != Ctrl.UNKNOWN) { int route = h.getRoute(); List routeHandlers = handlers.get(route); if (routeHandlers == null) { @@ -789,19 +736,15 @@ public void register(final List _cbs) { @Override public void send(int _nodeIdHashcode, final Msg _msg) { - Node node = this.activeNodes.get(_nodeIdHashcode); + Node node = this.nodeMgr.getActiveNode(_nodeIdHashcode); if (node != null) { SelectionKey sk = node.getChannel().keyFor(selector); if (sk != null) { Object attachment = sk.attachment(); if (attachment != null) - workers.submit(new TaskWrite( - node.getIdShort(), - node.getChannel(), - _msg, - (ChannelBuffer) attachment - )); + workers.submit( + new TaskWrite(node.getIdShort(), node.getChannel(), _msg, (ChannelBuffer) attachment)); } } } @@ -810,12 +753,7 @@ public void send(int _nodeIdHashcode, final Msg _msg) { public void shutdown() { start.set(false); scheduledWorkers.shutdownNow(); - activeNodes.forEach((k,n) -> closeSocket(n.getChannel())); - activeNodes.clear(); - outboundNodes.forEach((k,n) -> closeSocket(n.getChannel())); - outboundNodes.clear(); - inboundNodes.forEach((k,n) -> closeSocket(n.getChannel())); - inboundNodes.clear(); + nodeMgr.shutdown(this); workers.shutdownNow(); } diff --git a/modP2pImpl/src/org/aion/p2p/impl/PeerMetric.java b/modP2pImpl/src/org/aion/p2p/impl/PeerMetric.java new file mode 100644 index 0000000000..392fe21f17 --- /dev/null +++ b/modP2pImpl/src/org/aion/p2p/impl/PeerMetric.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017-2018 Aion foundation. + * + * This file is part of the aion network project. + * + * The aion network project is free software: you can redistribute it + * and/or modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or any later version. + * + * The aion network project is distributed in the hope that it will + * be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with the aion network project source files. + * If not, see . + * + * Contributors to the aion source files in decreasing order of code volume: + * + * Aion foundation. + * + */ + +package org.aion.p2p.impl; + +final class PeerMetric { + + public static final int STOP_CONN_AFTER_FAILED_CONN = 2; + + int metricFailedConn; + + boolean shouldNotConn() { + return metricFailedConn > STOP_CONN_AFTER_FAILED_CONN; + } + + void incFailedCount() { + metricFailedConn++; + } + + void decFailedCount() { + if (metricFailedConn > 0) + metricFailedConn--; + } + +} diff --git a/modP2pImpl/src/org/aion/p2p/impl/TaskRequestActiveNodes.java b/modP2pImpl/src/org/aion/p2p/impl/TaskRequestActiveNodes.java index 5917478639..0803c0ad49 100644 --- a/modP2pImpl/src/org/aion/p2p/impl/TaskRequestActiveNodes.java +++ b/modP2pImpl/src/org/aion/p2p/impl/TaskRequestActiveNodes.java @@ -28,6 +28,7 @@ import java.util.Map; import org.aion.p2p.INode; +import org.aion.p2p.NodeRandPolicy; import org.aion.p2p.impl.msg.ReqActiveNodes; /** @@ -39,13 +40,13 @@ public final class TaskRequestActiveNodes implements Runnable { private P2pMgr mgr; - TaskRequestActiveNodes(final P2pMgr _mgr){ + TaskRequestActiveNodes(final P2pMgr _mgr) { this.mgr = _mgr; } @Override public void run() { - INode node = mgr.getRandom(); + INode node = mgr.getRandom(NodeRandPolicy.RND, 0); if (node != null) this.mgr.send(node.getIdHash(), new ReqActiveNodes()); } diff --git a/modP2pImpl/src/org/aion/p2p/impl/TaskUPnPManager.java b/modP2pImpl/src/org/aion/p2p/impl/TaskUPnPManager.java new file mode 100644 index 0000000000..284411037f --- /dev/null +++ b/modP2pImpl/src/org/aion/p2p/impl/TaskUPnPManager.java @@ -0,0 +1,103 @@ +package org.aion.p2p.impl; + +import fr.free.miniupnp.IGDdatas; +import fr.free.miniupnp.MiniupnpcLibrary; +import fr.free.miniupnp.UPNPDev; +import fr.free.miniupnp.UPNPUrls; +import java.nio.ByteBuffer; +import java.nio.IntBuffer; + +public class TaskUPnPManager implements Runnable { + + private final static String UPNP_PROTOCOL_TCP = "TCP"; + private final static String UPNP_PORT_MAPPING_DESCRIPTION = "aion-UPnP"; + private final static int DEFAULT_UPNP_PORT_MAPPING_LIFETIME_IN_SECONDS = 3600; + private final static int UPNP_DELAY = 2000; + + private int port; + MiniupnpcLibrary miniupnpc; + + TaskUPnPManager(int port){ + this.port = port; + miniupnpc = MiniupnpcLibrary.INSTANCE; + } + + @Override + public void run() { + Thread.currentThread().setName("p2p-UPnP"); + + UPNPUrls urls = new UPNPUrls(); + IGDdatas data = new IGDdatas(); + + ByteBuffer lanaddr = ByteBuffer.allocate(16); + + UPNPDev devlist = miniupnpc.upnpDiscover(UPNP_DELAY, null, null, 0, 0, (byte) 2, IntBuffer.allocate(1)); + if (devlist != null) { + if (miniupnpc.UPNP_GetValidIGD(devlist, urls, data, lanaddr, 16) != 0) { + System.out.println(""); + System.out.println(""); + + getExternalIpAddress(urls, data); + addPortMapping(urls, data, lanaddr); + getMappedPortInfo(urls, data); + + miniupnpc.FreeUPNPUrls(urls); + } else { + System.out.println(""); + } + } else { + System.out.println(""); + } + } + + private void addPortMapping(UPNPUrls urls, IGDdatas data, ByteBuffer lanaddr) { + int ret = miniupnpc.UPNP_AddPortMapping( + urls.controlURL.getString(0), + new String(data.first.servicetype), + String.valueOf(port), + String.valueOf(port), + new String(lanaddr.array()), + UPNP_PORT_MAPPING_DESCRIPTION, + UPNP_PROTOCOL_TCP, + null, + String.valueOf(DEFAULT_UPNP_PORT_MAPPING_LIFETIME_IN_SECONDS)); + + if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) + System.out.println(""); + } + + private void getMappedPortInfo(UPNPUrls urls, IGDdatas data) { + ByteBuffer intClient = ByteBuffer.allocate(16); + ByteBuffer intPort = ByteBuffer.allocate(6); + ByteBuffer desc = ByteBuffer.allocate(80); + ByteBuffer enabled = ByteBuffer.allocate(4); + ByteBuffer leaseDuration = ByteBuffer.allocate(16); + + int ret = miniupnpc.UPNP_GetSpecificPortMappingEntry( + urls.controlURL.getString(0), new String(data.first.servicetype), + String.valueOf(port), UPNP_PROTOCOL_TCP, null, intClient, intPort, + desc, enabled, leaseDuration); + + if (ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) { + System.out.println(""); + return; + } + + System.out.println(""); + } + + private void getExternalIpAddress(UPNPUrls urls, IGDdatas data) { + ByteBuffer externalAddress = ByteBuffer.allocate(16); + int ret = miniupnpc.UPNP_GetExternalIPAddress(urls.controlURL.getString(0), + new String(data.first.servicetype), externalAddress); + + if(ret != MiniupnpcLibrary.UPNPCOMMAND_SUCCESS) { + System.out.println(""); + return; + } + + System.out.println(""); + } +} \ No newline at end of file diff --git a/modP2pImpl/test/org/aion/p2p/impl/NodeTest.java b/modP2pImpl/test/org/aion/p2p/impl/NodeTest.java index 226023b75c..cecd6d599c 100644 --- a/modP2pImpl/test/org/aion/p2p/impl/NodeTest.java +++ b/modP2pImpl/test/org/aion/p2p/impl/NodeTest.java @@ -47,4 +47,33 @@ public void testParseFromEnode() { } + @Test + public void testIpByteStrConversion() { + String ipSource, ipVerify; + byte[] ipBytes; + + ipSource = "253.253.253.253"; + ipBytes = Node.ipStrToBytes(ipSource); + assertNotNull(ipBytes); + assertEquals(ipBytes.length, 8); + ipVerify = Node.ipBytesToStr(ipBytes); + assertTrue(ipSource.equals(ipVerify)); + + ipSource = "000.000.000.000"; + ipBytes = Node.ipStrToBytes(ipSource); + assertNotNull(ipBytes); + assertEquals(ipBytes.length, 8); + ipVerify = Node.ipBytesToStr(ipBytes); + assertFalse(ipSource.equals(ipVerify)); + assertTrue("0.0.0.0".equals(ipVerify)); + + ipSource = "256.256.256.256"; + ipBytes = Node.ipStrToBytes(ipSource); + assertNotNull(ipBytes); + assertEquals(ipBytes.length, 8); + ipVerify = Node.ipBytesToStr(ipBytes); + System.out.println(ipVerify); + assertTrue("256.256.256.256".equals(ipVerify)); + } + } \ No newline at end of file diff --git a/modP2pImpl/test/org/aion/p2p/impl/P2pMgrTest.java b/modP2pImpl/test/org/aion/p2p/impl/P2pMgrTest.java index 37c1ccaae4..bed0532a55 100644 --- a/modP2pImpl/test/org/aion/p2p/impl/P2pMgrTest.java +++ b/modP2pImpl/test/org/aion/p2p/impl/P2pMgrTest.java @@ -25,8 +25,13 @@ package org.aion.p2p.impl; +import org.aion.p2p.INode; import org.junit.Test; +import java.util.Map; import java.util.UUID; + +import static junit.framework.TestCase.assertNotNull; +import static junit.framework.TestCase.assertTrue; import static org.junit.Assert.assertEquals; /** @@ -88,20 +93,25 @@ public void testConnect() throws InterruptedException { int port1 = 30303; int port2 = 30304; - P2pMgr node1 = new P2pMgr( + P2pMgr receiver = new P2pMgr( id1, ip, port1, - new String[0], + new String[]{ + "p2p://" + id2 + "@" + ip + ":" + port2 + }, false, 128, 128, false, false ); - node1.run(); - P2pMgr node2 = new P2pMgr( + // clear temp nodes list but keep seed ips list + receiver.clearTempNodes(); + receiver.run(); + + P2pMgr connector = new P2pMgr( id2, ip, port2, @@ -114,10 +124,18 @@ public void testConnect() throws InterruptedException { false, false ); - node2.run(); + connector.run(); Thread.sleep(5000); - assertEquals(1, node1.getActiveNodes().size()); - assertEquals(1, node2.getActiveNodes().size()); + assertEquals(1, receiver.getActiveNodes().size()); + assertEquals(1, connector.getActiveNodes().size()); + + // check seed ips contains ip as incoming node + Map ns = receiver.getActiveNodes(); + Map.Entry entry = ns.entrySet().iterator().next(); + assertNotNull(entry); + assertTrue(((Node)entry.getValue()).getIfFromBootList()); + receiver.shutdown(); + connector.shutdown(); } diff --git a/modP2pImpl/test/org/aion/p2p/impl/Test.java b/modP2pImpl/test/org/aion/p2p/impl/Test.java new file mode 100644 index 0000000000..209e44cc88 --- /dev/null +++ b/modP2pImpl/test/org/aion/p2p/impl/Test.java @@ -0,0 +1,24 @@ +package org.aion.p2p.impl; + +import java.util.HashSet; +import java.util.Set; + +import static junit.framework.TestCase.assertTrue; +import static org.junit.Assert.assertFalse; + +public class Test { + + @org.junit.Test + public void testParseFromP2p(){ + + Set ips = new HashSet<>(); + for(int i = 0; i < 3; i++) + ips.add("192.168.0." + i); + + + + assertTrue(ips.contains("192.168.0.2")); + assertFalse(ips.contains("192.168.0.3")); + + } +} diff --git a/modP2pImpl/test/org/aion/p2p/impl/msg/ResActiveNodesTest.java b/modP2pImpl/test/org/aion/p2p/impl/msg/ResActiveNodesTest.java index 269617b8db..ca4373be6a 100644 --- a/modP2pImpl/test/org/aion/p2p/impl/msg/ResActiveNodesTest.java +++ b/modP2pImpl/test/org/aion/p2p/impl/msg/ResActiveNodesTest.java @@ -10,6 +10,7 @@ import org.aion.p2p.Ver; import org.aion.p2p.impl.Node; import org.aion.p2p.impl.Act; +import org.aion.p2p.impl.P2pMgr; import org.junit.Assert; import org.junit.Test; @@ -18,6 +19,8 @@ */ public class ResActiveNodesTest { + + private Node randomNode(){ return new Node( ThreadLocalRandom.current().nextBoolean(), diff --git a/modTxPoolImpl/src/org/aion/txpool/zero/TxPoolA0.java b/modTxPoolImpl/src/org/aion/txpool/zero/TxPoolA0.java index cfa49612a6..f8d3ce9d0a 100644 --- a/modTxPoolImpl/src/org/aion/txpool/zero/TxPoolA0.java +++ b/modTxPoolImpl/src/org/aion/txpool/zero/TxPoolA0.java @@ -52,7 +52,6 @@ public TxPoolA0(Properties config) { } private void setPoolArgs(Properties config) { - if (Optional.ofNullable(config.get(PROP_TXN_TIMEOUT)).isPresent()) { txn_timeout = Integer.valueOf(config.get(PROP_TXN_TIMEOUT).toString()); if (txn_timeout < TXN_TIMEOUT_MIN) {