Skip to content

Commit

Permalink
Merge pull request #329 from Sdkyl/develop
Browse files Browse the repository at this point in the history
  • Loading branch information
LucasMLK authored Feb 27, 2025
2 parents 0d18683 + 38a5468 commit b265c8d
Show file tree
Hide file tree
Showing 46 changed files with 1,459 additions and 560 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
<dist.phase>package</dist.phase>
<dist.base>${project.basedir}/dist</dist.base>

<xdagj-native-randomx.version>0.1.9</xdagj-native-randomx.version>
<xdagj-native-randomx.version>0.2.1</xdagj-native-randomx.version>
<netty.version>4.1.116.Final</netty.version>
<tuweni.version>2.4.2</tuweni.version>
<jackson.version>2.18.2</jackson.version>
Expand Down
8 changes: 6 additions & 2 deletions src/main/java/io/xdag/Kernel.java
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,8 @@ public synchronized void testStart() throws Exception {
// Create genesis block if first startup
if (xdagStats.getOurLastBlockHash() == null) {
firstAccount = Keys.toBytesAddress(wallet.getDefKey().getPublicKey());
firstBlock = new Block(config, XdagTime.getCurrentTimestamp(), null, null, false, null, null, -1, XAmount.ZERO);
firstBlock = new Block(config, XdagTime.getCurrentTimestamp(), null, null, false,
null, null, -1, XAmount.ZERO, null);
firstBlock.signOut(wallet.getDefKey());
xdagStats.setOurLastBlockHash(firstBlock.getHashLow().toArray());
if (xdagStats.getGlobalMiner() == null) {
Expand Down Expand Up @@ -229,7 +230,10 @@ public synchronized void testStart() throws Exception {
// Initialize mining
pow = new XdagPow(this);

//getWsServer().start();
if (webSocketServer == null) {
webSocketServer = new WebSocketServer(this, config.getPoolWhiteIPList(), config.getWebsocketServerPort());
}
webSocketServer.start();

// Start RPC
api = new XdagApiImpl(this);
Expand Down
39 changes: 28 additions & 11 deletions src/main/java/io/xdag/Wallet.java
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import org.apache.commons.io.FileUtils;
import org.apache.tuweni.bytes.Bytes;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.units.bigints.UInt64;
import org.bouncycastle.crypto.generators.BCrypt;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.hyperledger.besu.crypto.KeyPair;
Expand Down Expand Up @@ -485,7 +486,7 @@ private void requireHdWalletInitialized() {
* @param remark Optional remark to include in transaction
* @return List of transaction block wrappers
*/
public List<BlockWrapper> createTransactionBlock(Map<Address, KeyPair> ourKeys, Bytes32 to, String remark) {
public List<BlockWrapper> createTransactionBlock(Map<Address, KeyPair> ourKeys, Bytes32 to, String remark, UInt64 txNonce) {
// Check if remark exists
int hasRemark = remark == null ? 0 : 1;

Expand All @@ -501,8 +502,14 @@ public List<BlockWrapper> createTransactionBlock(Map<Address, KeyPair> ourKeys,
// Add default key
keysPerBlock.add(getDefKey());

// Base count for block (header + send address + default key signature)
int base = 1 + 1 + 2 + hasRemark;
int base;
if (txNonce != null) {
// base count a block <header + transaction nonce + send address + defKey signature>
base = 1 + 1 + 1 + 2 + hasRemark;
} else {
// base count a block <header + send address + defKey signature>
base = 1 + 1 + 2 + hasRemark;
}
XAmount amount = XAmount.ZERO;

while (!stack.isEmpty()) {
Expand All @@ -522,17 +529,21 @@ public List<BlockWrapper> createTransactionBlock(Map<Address, KeyPair> ourKeys,
stack.poll();
} else {
// Create block with current keys
res.add(createTransaction(to, amount, keys, remark));
res.add(createTransaction(to, amount, keys, remark, txNonce));
// Reset for next block
keys = new HashMap<>();
keysPerBlock = new HashSet<>();
keysPerBlock.add(getDefKey());
base = 1 + 1 + 2 + hasRemark;
if (txNonce != null) {
base = 1 + 1 + 1 + 2 + hasRemark;
} else {
base = 1 + 1 + 2 + hasRemark;
}
amount = XAmount.ZERO;
}
}
if (!keys.isEmpty()) {
res.add(createTransaction(to, amount, keys, remark));
res.add(createTransaction(to, amount, keys, remark, txNonce));
}

return res;
Expand All @@ -547,11 +558,11 @@ public List<BlockWrapper> createTransactionBlock(Map<Address, KeyPair> ourKeys,
* @param remark Optional remark
* @return Transaction block wrapper
*/
private BlockWrapper createTransaction(Bytes32 to, XAmount amount, Map<Address, KeyPair> keys, String remark) {
private BlockWrapper createTransaction(Bytes32 to, XAmount amount, Map<Address, KeyPair> keys, String remark, UInt64 txNonce) {

List<Address> tos = Lists.newArrayList(new Address(to, XDAG_FIELD_OUTPUT, amount,true));

Block block = createNewBlock(new HashMap<>(keys), tos, remark);
Block block = createNewBlock(new HashMap<>(keys), tos, remark, txNonce);

if (block == null) {
return null;
Expand Down Expand Up @@ -586,7 +597,7 @@ private BlockWrapper createTransaction(Bytes32 to, XAmount amount, Map<Address,
* @return New transaction block
*/
private Block createNewBlock(Map<Address, KeyPair> pairs, List<Address> to,
String remark) {
String remark, UInt64 txNonce) {
int hasRemark = remark == null ? 0 : 1;

int defKeyIndex = -1;
Expand Down Expand Up @@ -614,7 +625,12 @@ private Block createNewBlock(Map<Address, KeyPair> pairs, List<Address> to,
all.addAll(to);

// Calculate total fields needed
int res = 1 + pairs.size() + to.size() + 3 * keys.size() + (defKeyIndex == -1 ? 2 : 0) + hasRemark;
int res;
if (txNonce != null) {
res = 1 + 1 + pairs.size() + to.size() + 3 * keys.size() + (defKeyIndex == -1 ? 2 : 0) + hasRemark;
} else {
res = 1 + pairs.size() + to.size() + 3 * keys.size() + (defKeyIndex == -1 ? 2 : 0) + hasRemark;
}

// Validate block size
if (res > 16) {
Expand All @@ -623,7 +639,8 @@ private Block createNewBlock(Map<Address, KeyPair> pairs, List<Address> to,

long sendTime = XdagTime.getCurrentTimestamp();

return new Block(getConfig(), sendTime, all, null, false, keys, remark, defKeyIndex, XAmount.of(100, XUnit.MILLI_XDAG));
return new Block(getConfig(), sendTime, all, null, false, keys, remark,
defKeyIndex, XAmount.of(100, XUnit.MILLI_XDAG), txNonce);
}

}
84 changes: 71 additions & 13 deletions src/main/java/io/xdag/cli/Commands.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.tuweni.bytes.Bytes32;
import org.apache.tuweni.bytes.MutableBytes32;
import org.apache.tuweni.units.bigints.UInt64;
import org.bouncycastle.util.encoders.Hex;
import org.hyperledger.besu.crypto.KeyPair;

Expand Down Expand Up @@ -135,7 +136,7 @@ public static String getStateByFlags(int flags) {
}

/**
* List addresses and balances
* List addresses, balances and current transaction quantity
* @param num Number of addresses to display
*/
public String account(int num) {
Expand All @@ -158,10 +159,19 @@ public String account(int num) {
if (num == 0) {
break;
}

UInt64 txQuantity = kernel.getAddressStore().getTxQuantity(toBytesAddress(keyPair));
UInt64 exeTxNonceNum = kernel.getAddressStore().getExecutedNonceNum(toBytesAddress(keyPair));

str.append(toBase58(toBytesAddress(keyPair)))
.append(" ")
.append(kernel.getAddressStore().getBalanceByAddress(toBytesAddress(keyPair)).toDecimal(9, XUnit.XDAG).toPlainString())
.append(" XDAG")
.append(" [Current TX Quantity: ")
.append(txQuantity.toUInt64())
.append(", Confirmed TX Quantity: ")
.append(exeTxNonceNum.toUInt64())
.append("]")
.append("\n");
num--;
}
Expand Down Expand Up @@ -199,7 +209,29 @@ public String balance(String address) {
Block block = kernel.getBlockStore().getBlockInfoByHash(Bytes32.wrap(key));
return String.format("Block balance: %s XDAG", block.getInfo().getAmount().toDecimal(9, XUnit.XDAG).toPlainString());
}
}
}

public String txQuantity(String address) {
if (StringUtils.isEmpty(address)) {
UInt64 ourTxQuantity = UInt64.ZERO;
UInt64 exeTxQuantit = UInt64.ZERO;
List<KeyPair> list = kernel.getWallet().getAccounts();
for (KeyPair key : list) {
ourTxQuantity = ourTxQuantity.add(kernel.getAddressStore().getTxQuantity(toBytesAddress(key)));
exeTxQuantit = exeTxQuantit.add(kernel.getAddressStore().getExecutedNonceNum(toBytesAddress(key)));
}
return String.format("Current Transaction Quantity: %s, executed Transaction Quantity: %s \n", ourTxQuantity.toLong(), exeTxQuantit.toLong());
} else {
UInt64 addressTxQuantity = UInt64.ZERO;
UInt64 addressExeTxQuantity = UInt64.ZERO;
if (checkAddress(address)) {
addressTxQuantity = addressTxQuantity.add(kernel.getAddressStore().getTxQuantity(fromBase58(address)));
addressExeTxQuantity = addressExeTxQuantity.add(kernel.getAddressStore().getExecutedNonceNum(fromBase58(address)));
return String.format("Current Transaction Quantity: %s, executed Transaction Quantity: %s \n", addressTxQuantity.toLong(), addressExeTxQuantity.toLong());
} else {
return "The account address format is incorrect! \n";
}
}
}

Expand All @@ -223,9 +255,13 @@ public String xfer(double sendAmount, Bytes32 address, String remark) {
// Collect input accounts
Map<Address, KeyPair> ourAccounts = Maps.newHashMap();
List<KeyPair> accounts = kernel.getWallet().getAccounts();
UInt64 txNonce = null;

for (KeyPair account : accounts) {
byte[] addr = toBytesAddress(account);
XAmount addrBalance = kernel.getAddressStore().getBalanceByAddress(addr);
UInt64 currentTxQuantity = kernel.getAddressStore().getTxQuantity(addr);
txNonce = currentTxQuantity.add(UInt64.ONE);

if (compareAmountTo(remain.get(), addrBalance) <= 0) {
ourAccounts.put(new Address(keyPair2Hash(account), XDAG_FIELD_INPUT, remain.get(), true), account);
Expand All @@ -245,22 +281,33 @@ public String xfer(double sendAmount, Bytes32 address, String remark) {
}

// Create and broadcast transaction blocks
List<BlockWrapper> txs = createTransactionBlock(ourAccounts, to, remark);
List<BlockWrapper> txs = createTransactionBlock(ourAccounts, to, remark, txNonce);
for (BlockWrapper blockWrapper : txs) {
ImportResult result = kernel.getSyncMgr().validateAndAddNewBlock(blockWrapper);
if (result == ImportResult.IMPORTED_BEST || result == ImportResult.IMPORTED_NOT_BEST) {
kernel.getChannelMgr().sendNewBlock(blockWrapper);
Block block = new Block(new XdagBlock(blockWrapper.getBlock().getXdagBlock().getData().toArray()));
List<Address> inputs = block.getInputs();
UInt64 blockNonce = block.getTxNonceField().getTransactionNonce();
for (Address input : inputs) {
if (input.getType() == XDAG_FIELD_INPUT) {
byte[] addr = BytesUtils.byte32ToArray(input.getAddress());
kernel.getAddressStore().updateTxQuantity(addr, blockNonce);
}
}
str.append(hash2Address(blockWrapper.getBlock().getHashLow())).append("\n");
} else if (result == ImportResult.INVALID_BLOCK) {
str.append(result.getErrorInfo());
}
}

return str.append("}, it will take several minutes to complete the transaction.").toString();
return str.append("}, it will take several minutes to complete the transaction. \n").toString();
}

/**
* Create transaction blocks from inputs to recipient
*/
private List<BlockWrapper> createTransactionBlock(Map<Address, KeyPair> ourKeys, Bytes32 to, String remark) {
private List<BlockWrapper> createTransactionBlock(Map<Address, KeyPair> ourKeys, Bytes32 to, String remark, UInt64 txNonce) {
// Check if remark exists
int hasRemark = remark == null ? 0 : 1;

Expand All @@ -274,8 +321,14 @@ private List<BlockWrapper> createTransactionBlock(Map<Address, KeyPair> ourKeys,
Set<KeyPair> keysPerBlock = Sets.newHashSet();
keysPerBlock.add(kernel.getWallet().getDefKey());

// Base field count for block
int base = 1 + 1 + 2 + hasRemark;
int base;
if (txNonce != null) {
// base count a block <header + transaction nonce + send address + defKey signature>
base = 1 + 1 + 1 + 2 + hasRemark;
} else {
// base count a block <header + send address + defKey signature>
base = 1 + 1 + 2 + hasRemark;
}
XAmount amount = XAmount.ZERO;

while (!stack.isEmpty()) {
Expand All @@ -296,28 +349,33 @@ private List<BlockWrapper> createTransactionBlock(Map<Address, KeyPair> ourKeys,
stack.poll();
} else {
// Create block and reset for next
res.add(createTransaction(to, amount, keys, remark));
res.add(createTransaction(to, amount, keys, remark, txNonce));
keys = new HashMap<>();
keysPerBlock = new HashSet<>();
keysPerBlock.add(kernel.getWallet().getDefKey());
base = 1 + 1 + 2 + hasRemark;
if (txNonce != null) {
base = 1 + 1 + 1 + 2 + hasRemark;
} else {
base = 1 + 1 + 2 + hasRemark;
}
amount = XAmount.ZERO;
}
}

// Create final block if needed
if (!keys.isEmpty()) {
res.add(createTransaction(to, amount, keys, remark));
res.add(createTransaction(to, amount, keys, remark, txNonce));
}
return res;
}

/**
* Create single transaction block
*/
private BlockWrapper createTransaction(Bytes32 to, XAmount amount, Map<Address, KeyPair> keys, String remark) {
private BlockWrapper createTransaction(Bytes32 to, XAmount amount, Map<Address, KeyPair> keys, String remark, UInt64 txNonce) {
List<Address> tos = Lists.newArrayList(new Address(to, XDAG_FIELD_OUTPUT, amount, true));
Block block = kernel.getBlockchain().createNewBlock(new HashMap<>(keys), tos, false, remark, XAmount.of(100, XUnit.MILLI_XDAG));
Block block = kernel.getBlockchain().createNewBlock(new HashMap<>(keys), tos, false, remark,
XAmount.of(100, XUnit.MILLI_XDAG), txNonce);

if (block == null) {
return null;
Expand Down Expand Up @@ -737,7 +795,7 @@ public String xferToNew() {
});

// Generate multiple transaction blocks
List<BlockWrapper> txs = createTransactionBlock(ourBlocks, to, remark);
List<BlockWrapper> txs = createTransactionBlock(ourBlocks, to, remark, null);
for (BlockWrapper blockWrapper : txs) {
ImportResult result = kernel.getSyncMgr().validateAndAddNewBlock(blockWrapper);
if (result == ImportResult.IMPORTED_BEST || result == ImportResult.IMPORTED_NOT_BEST) {
Expand All @@ -761,7 +819,7 @@ public StringBuilder xferToNode(Map<Address, KeyPair> paymentsToNodesMap) {
String remark = "Pay to " + kernel.getConfig().getNodeSpec().getNodeTag();

// Generate transaction blocks to reward node
List<BlockWrapper> txs = createTransactionBlock(paymentsToNodesMap, to, remark);
List<BlockWrapper> txs = createTransactionBlock(paymentsToNodesMap, to, remark, null);
for (BlockWrapper blockWrapper : txs) {
ImportResult result = kernel.getSyncMgr().validateAndAddNewBlock(blockWrapper);
if (result == ImportResult.IMPORTED_BEST || result == ImportResult.IMPORTED_NOT_BEST) {
Expand Down
18 changes: 18 additions & 0 deletions src/main/java/io/xdag/cli/Shell.java
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ public Shell() {
commandExecute.put("terminate", new CommandMethods(this::processTerminate, this::defaultCompleter));
commandExecute.put("address", new CommandMethods(this::processAddress, this::defaultCompleter));
commandExecute.put("oldbalance", new CommandMethods(this::processOldBalance, this::defaultCompleter));
commandExecute.put("txQuantity", new CommandMethods(this::processTxQuantity, this::defaultCompleter));
registerCommands(commandExecute);
}

Expand Down Expand Up @@ -210,6 +211,23 @@ private void processBalance(CommandInput input) {
}
}

private void processTxQuantity(CommandInput input) {
final String[] usage = {
"txQuantity - print current transaction quantity of the address [ADDRESS] or current nonce of our address \n",
"Usage: txQuantity [ADDRESS](optional)",
" -? --help Show help",
};
try {
Options opt = parseOptions(usage, input.args());
if (opt.isSet("help")) {
throw new Options.HelpException(opt.usage());
}
List<String> argv = opt.args();
println(commands.txQuantity(!argv.isEmpty() ? argv.get(0) : null));
} catch (Exception error) {
saveException(error);
}
}

private void processBlock(CommandInput input) {
final String[] usage = {
Expand Down
2 changes: 2 additions & 0 deletions src/main/java/io/xdag/config/Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -152,4 +152,6 @@ public interface Config {
*/
FundSpec getFundSpec();

String getNodeTag();

}
4 changes: 2 additions & 2 deletions src/main/java/io/xdag/consensus/XdagPow.java
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ public void newBlock() {

public Block generateRandomXBlock(long sendTime) {
taskIndex.incrementAndGet();
Block block = blockchain.createNewBlock(null, null, true, null, XAmount.ZERO);
Block block = blockchain.createNewBlock(null, null, true, null, XAmount.ZERO, null);
block.signOut(wallet.getDefKey());
// The first 20 bytes of the initial nonce are the node wallet address.
minShare.set(Bytes32.wrap(BytesUtils.merge(hash2byte(keyPair2Hash(wallet.getDefKey())),
Expand All @@ -199,7 +199,7 @@ public Block generateRandomXBlock(long sendTime) {

public Block generateBlock(long sendTime) {
taskIndex.incrementAndGet();
Block block = blockchain.createNewBlock(null, null, true, null, XAmount.ZERO);
Block block = blockchain.createNewBlock(null, null, true, null, XAmount.ZERO, null);
block.signOut(wallet.getDefKey());
minShare.set(Bytes32.wrap(BytesUtils.merge(hash2byte(keyPair2Hash(wallet.getDefKey())),
XdagRandomUtils.nextNewBytes(12))));
Expand Down
Loading

0 comments on commit b265c8d

Please sign in to comment.