diff --git a/pom.xml b/pom.xml
index 494950bc..b75481cc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -337,7 +337,7 @@
io.xdag
xdagj-native-randomx
- 0.1.5
+ 0.1.6
diff --git a/src/main/java/io/xdag/Kernel.java b/src/main/java/io/xdag/Kernel.java
index e899fa39..708bcdb4 100644
--- a/src/main/java/io/xdag/Kernel.java
+++ b/src/main/java/io/xdag/Kernel.java
@@ -70,8 +70,8 @@
import io.xdag.rpc.Web3;
import io.xdag.rpc.Web3Impl;
import io.xdag.rpc.cors.CorsConfiguration;
-import io.xdag.rpc.modules.web3.Web3XdagModule;
-import io.xdag.rpc.modules.web3.Web3XdagModuleImpl;
+import io.xdag.rpc.modules.xdag.Web3XdagModule;
+import io.xdag.rpc.modules.xdag.Web3XdagModuleImpl;
import io.xdag.rpc.modules.xdag.XdagModule;
import io.xdag.rpc.modules.xdag.XdagModuleChainBase;
import io.xdag.rpc.modules.xdag.XdagModuleTransactionEnabled;
@@ -83,7 +83,7 @@
import io.xdag.rpc.netty.XdagJsonRpcHandler;
import io.xdag.rpc.serialize.JacksonBasedRpcSerializer;
import io.xdag.rpc.serialize.JsonRpcSerializer;
-import io.xdag.utils.ByteArrayToByte32;
+import io.xdag.utils.BytesUtils;
import io.xdag.utils.XdagTime;
import java.net.InetAddress;
import java.net.UnknownHostException;
@@ -232,7 +232,7 @@ public synchronized void testStart() throws Exception {
// 如果是第一次启动,则新建一个创世块
if (xdagStats.getOurLastBlockHash() == null) {
firstAccount = Keys.toBytesAddress(wallet.getDefKey().getPublicKey());
- poolMiner = new Miner(ByteArrayToByte32.arrayToByte32(firstAccount));
+ poolMiner = new Miner(BytesUtils.arrayToByte32(firstAccount));
firstBlock = new Block(config, XdagTime.getCurrentTimestamp(), null, null, false, null, null, -1);
firstBlock.signOut(wallet.getDefKey());
xdagStats.setOurLastBlockHash(firstBlock.getHashLow().toArray());
@@ -242,7 +242,7 @@ public synchronized void testStart() throws Exception {
blockchain.tryToConnect(firstBlock);
} else {
firstAccount = Keys.toBytesAddress(wallet.getDefKey().getPublicKey());
- poolMiner = new Miner(ByteArrayToByte32.arrayToByte32(firstAccount));
+ poolMiner = new Miner(BytesUtils.arrayToByte32(firstAccount));
}
log.info("Blockchain init");
diff --git a/src/main/java/io/xdag/Wallet.java b/src/main/java/io/xdag/Wallet.java
index 5cfd129b..a202ffe7 100644
--- a/src/main/java/io/xdag/Wallet.java
+++ b/src/main/java/io/xdag/Wallet.java
@@ -43,11 +43,11 @@
import io.xdag.crypto.Sign;
import io.xdag.utils.Numeric;
import io.xdag.utils.SimpleDecoder;
-import io.xdag.utils.SystemUtil;
import io.xdag.utils.WalletUtils;
import io.xdag.utils.XdagTime;
import java.io.File;
import java.io.IOException;
+import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.attribute.PosixFilePermission;
import java.security.InvalidAlgorithmParameterException;
@@ -339,7 +339,7 @@ public boolean flush() {
}
// set posix permissions
- if (SystemUtil.isPosix() && !file.exists()) {
+ if (FileSystems.getDefault().supportedFileAttributeViews().contains("posix") && !file.exists()) {
Files.createFile(file.toPath());
Files.setPosixFilePermissions(file.toPath(), POSIX_SECURED_PERMISSIONS);
}
diff --git a/src/main/java/io/xdag/cli/Commands.java b/src/main/java/io/xdag/cli/Commands.java
index 33f5128a..69f47864 100644
--- a/src/main/java/io/xdag/cli/Commands.java
+++ b/src/main/java/io/xdag/cli/Commands.java
@@ -49,9 +49,9 @@
import static io.xdag.utils.BasicUtils.pubAddress2Hash;
import static io.xdag.utils.BasicUtils.xdag2amount;
import static io.xdag.utils.BasicUtils.xdagHashRate;
-import static io.xdag.utils.PubkeyAddressUtils.checkAddress;
-import static io.xdag.utils.PubkeyAddressUtils.fromBase58;
-import static io.xdag.utils.PubkeyAddressUtils.toBase58;
+import static io.xdag.utils.WalletUtils.checkAddress;
+import static io.xdag.utils.WalletUtils.fromBase58;
+import static io.xdag.utils.WalletUtils.toBase58;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
@@ -73,8 +73,7 @@
import io.xdag.mine.miner.MinerStates;
import io.xdag.net.node.Node;
import io.xdag.utils.BasicUtils;
-import io.xdag.utils.ByteArrayToByte32;
-import io.xdag.utils.PubkeyAddressUtils;
+import io.xdag.utils.BytesUtils;
import io.xdag.utils.XdagTime;
import java.math.BigInteger;
import java.net.InetSocketAddress;
@@ -740,7 +739,7 @@ public String address(Bytes32 wrap) {
.format(XdagTime.xdagTimestampToMs(txHistory.getTimeStamp()))));
}
}else {
- tx.append(String.format(" snapshot: %s %.9f %s%n", (PubkeyAddressUtils.toBase58(ByteArrayToByte32.byte32ToArray(address.getAddress()))),
+ tx.append(String.format(" snapshot: %s %.9f %s%n", (toBase58(BytesUtils.byte32ToArray(address.getAddress()))),
amount2xdag(address.getAmount()),
FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSS")
.format(XdagTime.xdagTimestampToMs(txHistory.getTimeStamp()))));
diff --git a/src/main/java/io/xdag/cli/Shell.java b/src/main/java/io/xdag/cli/Shell.java
index df6d5ea5..df0afce9 100644
--- a/src/main/java/io/xdag/cli/Shell.java
+++ b/src/main/java/io/xdag/cli/Shell.java
@@ -30,7 +30,6 @@
import io.xdag.Kernel;
import io.xdag.Wallet;
import io.xdag.utils.BasicUtils;
-import io.xdag.utils.PubkeyAddressUtils;
import io.xdag.utils.WalletUtils;
import java.util.HashMap;
import java.util.List;
@@ -130,7 +129,7 @@ private void processAddress(CommandInput input) {
String address = argv.get(0);
try {
Bytes32 hash;
- if (PubkeyAddressUtils.checkAddress(address)) {
+ if (WalletUtils.checkAddress(address)) {
hash = pubAddress2Hash(address);
} else {
println("Incorrect address");
@@ -377,7 +376,7 @@ private void processXfer(CommandInput input) {
return;
}
- if (PubkeyAddressUtils.checkAddress(argv.get(1))) {
+ if (WalletUtils.checkAddress(argv.get(1))) {
hash = pubAddress2Hash(argv.get(1));
} else {
println("Incorrect address");
diff --git a/src/main/java/io/xdag/consensus/XdagPow.java b/src/main/java/io/xdag/consensus/XdagPow.java
index 9ab4b757..98c7f34b 100644
--- a/src/main/java/io/xdag/consensus/XdagPow.java
+++ b/src/main/java/io/xdag/consensus/XdagPow.java
@@ -83,6 +83,8 @@ public class XdagPow implements PoW, Listener, Runnable {
protected AtomicReference currentTask = new AtomicReference<>();
protected AtomicLong taskIndex = new AtomicLong(0L);
+ private boolean isWorking = false;
+
private final ExecutorService timerExecutor = Executors.newSingleThreadExecutor(new BasicThreadFactory.Builder()
.namingPattern("XdagPow-timer-thread")
@@ -267,11 +269,15 @@ public void receiveNewShare(MinerChannel channel, Message msg) {
}
public void receiveNewPretop(Bytes pretop) {
- if (!this.isRunning) {
+ // make sure the PoW is running and the main block is generating
+ if (!this.isRunning || !isWorking) {
return;
}
- if (!equalBytes(pretop.toArray(), globalPretop.toArray())) {
- globalPretop = Bytes32.wrap(blockchain.getXdagTopStatus().getPreTop());
+
+ // prevent duplicate event
+ if (globalPretop == null || !equalBytes(pretop.toArray(), globalPretop.toArray())) {
+ log.debug("update global pretop:{}", Bytes32.wrap(pretop).toHexString());
+ globalPretop = Bytes32.wrap(pretop);
events.add(new Event(Event.Type.NEW_PRETOP, pretop));
}
}
@@ -327,17 +333,20 @@ protected void onNewShare(XdagField shareInfo, MinerChannel channel) {
protected void onTimeout() {
Block b = generateBlock.get();
+ // stop generate main block
+ isWorking = false;
if (b != null) {
Block newBlock = new Block(new XdagBlock(b.toBytes()));
log.debug("Broadcast locally generated blockchain, waiting to be verified. block hash = [{}]",
newBlock.getHash().toHexString());
- // 发送区块 如果有的话 然后开始生成新区块
+ // add new block, reward miner, and broadcast the new block
kernel.getBlockchain().tryToConnect(newBlock);
awardManager.addAwardBlock(minShare.get(), newBlock.getHash(), newBlock.getTimestamp());
BlockWrapper bw = new BlockWrapper(newBlock, kernel.getConfig().getNodeSpec().getTTL());
-
broadcaster.broadcast(bw);
}
+ // start generate main block
+ isWorking = true;
newBlock();
}
@@ -405,7 +414,7 @@ public void run() {
// resetTimeout(XdagTime.getEndOfEpoch(XdagTime.getCurrentTimestamp() + 64));
timer.timeout(XdagTime.getEndOfEpoch(XdagTime.getCurrentTimestamp() + 64));
// init pretop
- globalPretop = Bytes32.wrap(blockchain.getXdagTopStatus().getPreTop());
+ globalPretop = null;
while (this.isRunning) {
try {
Event ev = events.poll(10, TimeUnit.MILLISECONDS);
diff --git a/src/main/java/io/xdag/core/Address.java b/src/main/java/io/xdag/core/Address.java
index d2768a45..04dc06c9 100644
--- a/src/main/java/io/xdag/core/Address.java
+++ b/src/main/java/io/xdag/core/Address.java
@@ -25,7 +25,7 @@
package io.xdag.core;
import io.xdag.utils.BytesUtils;
-import io.xdag.utils.PubkeyAddressUtils;
+import io.xdag.utils.WalletUtils;
import lombok.Getter;
import lombok.Setter;
import org.apache.tuweni.bytes.Bytes;
@@ -167,7 +167,7 @@ public boolean getIsAddress() {
@Override
public String toString() {
if(isAddress){
- return "Address [" + PubkeyAddressUtils.toBase58(addressHash.slice(8,20).toArray()) + "]";
+ return "Address [" + WalletUtils.toBase58(addressHash.slice(8,20).toArray()) + "]";
}else {
return "Block Hash[" + addressHash.toHexString() + "]";
}
diff --git a/src/main/java/io/xdag/core/BlockchainImpl.java b/src/main/java/io/xdag/core/BlockchainImpl.java
index 1af2d0f4..25537e76 100644
--- a/src/main/java/io/xdag/core/BlockchainImpl.java
+++ b/src/main/java/io/xdag/core/BlockchainImpl.java
@@ -73,8 +73,8 @@
import io.xdag.listener.PretopMessage;
import io.xdag.mine.randomx.RandomX;
import io.xdag.utils.BasicUtils;
-import io.xdag.utils.ByteArrayToByte32;
-import io.xdag.utils.PubkeyAddressUtils;
+import io.xdag.utils.BytesUtils;
+import io.xdag.utils.WalletUtils;
import io.xdag.utils.XdagTime;
import java.math.BigInteger;
import java.util.ArrayList;
@@ -324,7 +324,7 @@ public synchronized ImportResult tryToConnect(Block block) {
log.debug("Block have no parent for " + result.getHashlow().toHexString());
return result;
} else {
- // 链接块的时间需要小于该块时间,否则为不合法区块
+ // ensure ref block's time is earlier than block's time
if (refBlock.getTimestamp() >= block.getTimestamp()) {
result = ImportResult.INVALID_BLOCK;
result.setHashlow(refBlock.getHashLow());
@@ -337,10 +337,10 @@ public synchronized ImportResult tryToConnect(Block block) {
}
}else {
- if(ref.type == XDAG_FIELD_INPUT && !addressStore.addressIsExist(ByteArrayToByte32.byte32ToArray(ref.getAddress()))){
+ if(ref.type == XDAG_FIELD_INPUT && !addressStore.addressIsExist(BytesUtils.byte32ToArray(ref.getAddress()))){
result = ImportResult.INVALID_BLOCK;
- result.setErrorInfo("Address isn't exist " + PubkeyAddressUtils.toBase58(ByteArrayToByte32.byte32ToArray(ref.getAddress())));
- log.debug("Address isn't exist " + PubkeyAddressUtils.toBase58(ByteArrayToByte32.byte32ToArray(ref.getAddress())));
+ result.setErrorInfo("Address isn't exist " + WalletUtils.toBase58(BytesUtils.byte32ToArray(ref.getAddress())));
+ log.debug("Address isn't exist " + WalletUtils.toBase58(BytesUtils.byte32ToArray(ref.getAddress())));
return result;
}
}
@@ -408,17 +408,10 @@ public synchronized ImportResult tryToConnect(Block block) {
updateBlockFlag(block, BI_OURS, true);
}
- // 更新区块难度和maxDiffLink
+ // calculate block's self difficulty
BigInteger cuDiff = calculateCurrentBlockDiff(block);
- BigInteger diff = calculateBlockDiff(block,cuDiff);
-
- // 更新preTop
- setPreTop(block, diff);
- setPreTop(getBlockByHash(xdagTopStatus.getTop() == null ? null : Bytes32.wrap(xdagTopStatus.getTop()),
- false), xdagTopStatus.getTopDiff());
-
- // 通知XdagPoW 新pretop产生
- onNewPretop();
+ // calculate block's chain difficulty
+ calculateBlockDiff(block,cuDiff);
// TODO:extra 处理
processExtraBlock();
@@ -439,9 +432,20 @@ public synchronized ImportResult tryToConnect(Block block) {
log.info("XDAG:Before unwind, height = {}, After unwind, height = {}, unwind number = {}",
currentHeight, xdagStats.nmain, currentHeight - xdagStats.nmain);
}
+
+ Block currentTop = getBlockByHash(xdagTopStatus.getTop() == null ? null :
+ Bytes32.wrap(xdagTopStatus.getTop()), false);
+ BigInteger currentTopDiff = xdagTopStatus.getTopDiff();
log.debug("update top: {}", block.getHashLow());
+ // update Top
xdagTopStatus.setTopDiff(block.getInfo().getDifficulty());
xdagTopStatus.setTop(block.getHashLow().toArray());
+ // update preTop
+ setPreTop(currentTop,currentTopDiff);
+ // if block's epoch is earlier than current epoch, then notify the PoW thread to regenerate the main block
+ if (XdagTime.getEpoch(block.getTimestamp()) < XdagTime.getCurrentEpoch()) {
+ onNewPretop();
+ }
result = ImportResult.IMPORTED_BEST;
xdagStats.updateMaxDiff(xdagTopStatus.getTopDiff());
xdagStats.updateDiff(xdagTopStatus.getTopDiff());
@@ -450,20 +454,13 @@ public synchronized ImportResult tryToConnect(Block block) {
// 新增区块
xdagStats.nblocks++;
xdagStats.totalnblocks = Math.max(xdagStats.nblocks, xdagStats.totalnblocks);
-// if (xdagStats.getTotalnblocks() < xdagStats.getNblocks()) {
-// xdagStats.setTotalnblocks(xdagStats.getNblocks());
-// }
- //orphan (hash , block)
-// log.debug("======New block waiting to link======,{}",Hex.toHexString(block.getHashLow()));
if ((block.getInfo().flags & BI_EXTRA) != 0) {
-// log.debug("block:{} is extra, put it into memOrphanPool waiting to link.", Hex.toHexString(block.getHashLow()));
memOrphanPool.put(block.getHashLow(), block);
xdagStats.nextra++;
// TODO:设置为返回 IMPORTED_EXTRA
// result = ImportResult.IMPORTED_EXTRA;
} else {
-// log.debug("block:{} is extra, put it into orphanPool waiting to link.", Hex.toHexString(block.getHashLow()));
saveBlock(block);
orphanBlockStore.addOrphan(block);
xdagStats.nnoref++;
@@ -594,7 +591,7 @@ public void processExtraBlock() {
protected void onNewPretop() {
for (Listener listener : listeners) {
- listener.onMessage(new PretopMessage(Bytes.wrap(xdagTopStatus.getPreTop()), PRE_TOP));
+ listener.onMessage(new PretopMessage(Bytes.wrap(xdagTopStatus.getTop()), PRE_TOP));
}
}
@@ -638,9 +635,8 @@ public synchronized void checkNewMain() {
*/
public void unWindMain(Block block) {
log.debug("Unwind main to block,{}", block == null ? "null" : block.getHashLow().toHexString());
-// log.debug("xdagTopStatus.getTop(),{}",xdagTopStatus.getTop()==null?"null":Hex.toHexString(xdagTopStatus.getTop()));
if (xdagTopStatus.getTop() != null) {
- log.debug("now top : {}", Bytes32.wrap(xdagTopStatus.getPreTop()).toHexString());
+ log.debug("now pretop : {}",xdagTopStatus.getPreTop() == null?"null": Bytes32.wrap(xdagTopStatus.getPreTop()).toHexString());
for (Block tmp = getBlockByHash(Bytes32.wrap(xdagTopStatus.getTop()), true); tmp != null
&& !blockEqual(block, tmp); tmp = getMaxDiffLink(tmp, true)) {
updateBlockFlag(tmp, BI_MAIN_CHAIN, false);
@@ -1005,37 +1001,49 @@ public Bytes32 getPreTopMainBlockForLink(long sendTime) {
return null;
}
if (XdagTime.getEpoch(topInfo.getTimestamp()) == mainTime) {
+ log.debug("use pretop:{}", Bytes32.wrap(xdagTopStatus.getPreTop()).toHexString());
return Bytes32.wrap(xdagTopStatus.getPreTop());
} else {
+ log.debug("use top:{}", Bytes32.wrap(xdagTopStatus.getTop()).toHexString());
return Bytes32.wrap(xdagTopStatus.getTop());
}
}
/**
* update pretop
- * @param block block
- * @param diff difficulty of block
+ * @param target target
+ * @param targetDiff difficulty of block
*/
- public void setPreTop(Block block, BigInteger diff) {
- if (block == null) {
+ public void setPreTop(Block target, BigInteger targetDiff) {
+ if (target == null) {
return;
}
- if (XdagTime.getEpoch(block.getTimestamp()) > XdagTime.getCurrentEpoch()) {
- return;
+
+ // make sure the target's epoch is earlier than current top's epoch
+ Block block = getBlockByHash(xdagTopStatus.getTop() == null ? null :
+ Bytes32.wrap(xdagTopStatus.getTop()), false);
+ if (block != null) {
+ if (XdagTime.getEpoch(target.getTimestamp()) >= XdagTime.getEpoch(block.getTimestamp())) {
+ return;
+ }
}
+
+ // if pretop is null, then update pretop to target
if (xdagTopStatus.getPreTop() == null) {
- xdagTopStatus.setPreTop(block.getHashLow().toArray());
- xdagTopStatus.setPreTopDiff(diff);
- block.setPretopCandidate(true);
- block.setPretopCandidateDiff(diff);
+ xdagTopStatus.setPreTop(target.getHashLow().toArray());
+ xdagTopStatus.setPreTopDiff(targetDiff);
+ target.setPretopCandidate(true);
+ target.setPretopCandidateDiff(targetDiff);
return;
}
- if (diff.compareTo(xdagTopStatus.getPreTopDiff()) > 0) {
- xdagTopStatus.setPreTop(block.getHashLow().toArray());
- xdagTopStatus.setPreTopDiff(diff);
- block.setPretopCandidate(true);
- block.setPretopCandidateDiff(diff);
+ // if targetDiff greater than pretop diff, then update pretop to target
+ if (targetDiff.compareTo(xdagTopStatus.getPreTopDiff()) > 0) {
+ log.debug("update pretop:{}", Bytes32.wrap(target.getHashLow()).toHexString());
+ xdagTopStatus.setPreTop(target.getHashLow().toArray());
+ xdagTopStatus.setPreTopDiff(targetDiff);
+ target.setPretopCandidate(true);
+ target.setPretopCandidateDiff(targetDiff);
}
}
/**
diff --git a/src/main/java/io/xdag/db/rocksdb/SnapshotStoreImpl.java b/src/main/java/io/xdag/db/rocksdb/SnapshotStoreImpl.java
index ee61f8c2..dd1146f4 100644
--- a/src/main/java/io/xdag/db/rocksdb/SnapshotStoreImpl.java
+++ b/src/main/java/io/xdag/db/rocksdb/SnapshotStoreImpl.java
@@ -23,7 +23,6 @@
*/
package io.xdag.db.rocksdb;
-import static io.xdag.config.Constants.BI_MAIN;
import static io.xdag.config.Constants.BI_OURS;
import static io.xdag.db.BlockStore.HASH_BLOCK_INFO;
import static io.xdag.db.BlockStore.SUMS_BLOCK_INFO;
@@ -31,7 +30,6 @@
import static io.xdag.db.AddressStore.ADDRESS_SIZE;
import static io.xdag.db.AddressStore.AMOUNT_SUM;
import static io.xdag.utils.BasicUtils.compareAmountTo;
-import static io.xdag.utils.ByteArrayToByte32.arrayToByte32;
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
@@ -256,7 +254,7 @@ public void saveAddress(BlockStore blockStore,AddressStore addressStore, List out) {
byte[] addressHash = Arrays.copyOfRange(message,0,20);
checkProtocol(ctx,addressHash);
- if (!initMiner(ByteArrayToByte32.arrayToByte32(addressHash))) {
+ if (!initMiner(BytesUtils.arrayToByte32(addressHash))) {
log.debug("too many connect for the miner: {},ip&port:{}",
- PubkeyAddressUtils.toBase58(channel.getAccountAddressHashByte()),channel.getInetAddress().toString());
+ WalletUtils.toBase58(channel.getAccountAddressHashByte()),channel.getInetAddress().toString());
ctx.close();
return;
}
@@ -95,12 +97,12 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf in, List