diff --git a/.gitignore b/.gitignore index 191f94965..e82472b4d 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,12 @@ src/gen # ignore slf4j test config src/test/resources/log4j2-test.xml + +CMakeFiles +CMakeFiles/ +/CMakeFiles/ +CMakeLists.txt.user +CMakeCache.txt +Makefile +install_manifest.txt +cmake_install.cmake diff --git a/CHANGELOG.md b/CHANGELOG.md index b9368a2c3..227e7d4b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## [v2.2.x](https://github.com/semuxproject/semux-core/tree/develop) (2020-xx-xx) (WIP) + +This release adds support for EIP-665 precompiled contract. + +NOTE: A softfork `EIP665_PRECOMPILED_UPGRADE` is introduced. + + + ## [v2.1.x](https://github.com/semuxproject/semux-core/tree/v2.1.1) (2019-09-10) This release tries to fix several issues about the voting precompiled contracts. All nodes diff --git a/pom.xml b/pom.xml index 58a89be46..ec88e76c1 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 org.semux semux - 2.1.1 + 2.2.0 jar Semux is an experimental high-performance blockchain platform that powers decentralized application. diff --git a/src/main/java/org/semux/api/http/HttpHandler.java b/src/main/java/org/semux/api/http/HttpHandler.java index a10e8ceed..7de0fe939 100644 --- a/src/main/java/org/semux/api/http/HttpHandler.java +++ b/src/main/java/org/semux/api/http/HttpHandler.java @@ -53,7 +53,6 @@ import io.netty.handler.codec.http.HttpChunkedInput; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaders; -import io.netty.handler.codec.http.HttpMethod; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpUtil; import io.netty.handler.codec.http.QueryStringDecoder; diff --git a/src/main/java/org/semux/api/util/TransactionBuilder.java b/src/main/java/org/semux/api/util/TransactionBuilder.java index 8572b072a..f2b8776bb 100644 --- a/src/main/java/org/semux/api/util/TransactionBuilder.java +++ b/src/main/java/org/semux/api/util/TransactionBuilder.java @@ -9,6 +9,7 @@ import org.semux.Kernel; import org.semux.Network; import org.semux.core.Amount; +import org.semux.core.Fork; import org.semux.core.Transaction; import org.semux.core.TransactionType; import org.semux.crypto.CryptoException; @@ -218,7 +219,7 @@ public TransactionBuilder withGasPrice(String gasPrice) { return this; } - public Transaction buildUnsigned() { + public Transaction buildUnsigned(byte[] from) { Network network = (this.network != null) ? this.network : kernel.getConfig().network(); TransactionType type = this.type; @@ -293,7 +294,7 @@ public Transaction buildUnsigned() { } } - return new Transaction(network, type, to, value, fee, nonce, timestamp, data, gas, gasPrice); + return new Transaction(network, type, to, from, value, fee, nonce, timestamp, data, gas, gasPrice, kernel.getBlockchain().isForkActivated(Fork.ED25519_CONTRACT)); } public Transaction buildSigned() { @@ -301,6 +302,11 @@ public Transaction buildSigned() { throw new IllegalArgumentException("The sender is not specified"); } - return buildUnsigned().sign(account); + return buildUnsigned(account.toAddress()).sign(account); + } + + public byte[] To () + { + return to; } } \ No newline at end of file diff --git a/src/main/java/org/semux/api/v2/SemuxApiImpl.java b/src/main/java/org/semux/api/v2/SemuxApiImpl.java index 841511172..24a77c426 100644 --- a/src/main/java/org/semux/api/v2/SemuxApiImpl.java +++ b/src/main/java/org/semux/api/v2/SemuxApiImpl.java @@ -70,6 +70,7 @@ import org.semux.core.Block; import org.semux.core.Blockchain; import org.semux.core.BlockchainImpl; +import org.semux.core.Fork; import org.semux.core.PendingManager; import org.semux.core.SyncManager; import org.semux.core.Transaction; @@ -167,7 +168,9 @@ public Response composeRawTransaction(String network, String type, String to, St .withData(data) .withGas(gas) .withGasPrice(gasPrice); - Transaction transaction = transactionBuilder.buildUnsigned(); + + /*We can use TO address instead FROM address, only if transaction will be used for ComposeRawTransactionResponse*/ + Transaction transaction = transactionBuilder.buildUnsigned(transactionBuilder.To()); ComposeRawTransactionResponse resp = new ComposeRawTransactionResponse(); resp.setResult(Hex.encode0x(transaction.getEncoded())); @@ -662,7 +665,7 @@ public Response signRawTransaction(String raw, String address) { return badRequest("Address doesn't belong to this wallet."); } - Transaction tx = Transaction.fromEncoded(txBytes).sign(signerKey); + Transaction tx = Transaction.fromEncoded(txBytes, signerKey.toAddress(), kernel.getBlockchain().isForkActivated(Fork.ED25519_CONTRACT)).sign(signerKey); SignRawTransactionResponse resp = new SignRawTransactionResponse(); resp.setResult(Hex.encode0x(tx.toBytes())); @@ -914,7 +917,7 @@ private TransactionResultType doLocalTransaction(TransactionType type, String to SemuxBlock block = kernel.createEmptyBlock(); BlockStore blockStore = new SemuxBlockStore(chain); TransactionExecutor exec = new TransactionExecutor(config, blockStore, chain.isVMEnabled(), - chain.isVotingPrecompiledUpgraded()); + chain.isVotingPrecompiledUpgraded(), chain.isEd25519ContractEnabled()); TransactionResult result = exec.execute(tx, asTrack, dsTrack, block, 0); byte[] contractAddress = type.equals(TransactionType.CREATE) diff --git a/src/main/java/org/semux/config/AbstractConfig.java b/src/main/java/org/semux/config/AbstractConfig.java index b730f2266..94f865464 100644 --- a/src/main/java/org/semux/config/AbstractConfig.java +++ b/src/main/java/org/semux/config/AbstractConfig.java @@ -10,9 +10,7 @@ import static org.semux.Network.MAINNET; import static org.semux.Network.TESTNET; import static org.semux.core.Amount.ZERO; -import static org.semux.core.Fork.UNIFORM_DISTRIBUTION; -import static org.semux.core.Fork.VIRTUAL_MACHINE; -import static org.semux.core.Fork.VOTING_PRECOMPILED_UPGRADE; +import static org.semux.core.Fork.*; import static org.semux.core.Unit.MILLI_SEM; import static org.semux.core.Unit.SEM; @@ -156,6 +154,7 @@ public abstract class AbstractConfig implements Config, ChainSpec { protected boolean forkUniformDistributionEnabled = false; protected boolean forkVirtualMachineEnabled = false; protected boolean forkVotingPrecompiledUpgradeEnabled = false; + protected boolean forkEd25519ContractEnabled = false; @Override public ChainSpec spec() { @@ -253,7 +252,7 @@ public String getPrimaryValidator(List validators, long height, int view return validators.get(getUniformDistPrimaryValidatorNumber(validators.size(), height, view)); } else { byte[] key = Bytes.merge(Bytes.of(height), Bytes.of(view)); - return validators.get((Hash.h256(key)[0] & 0xff) % validators.size()); + return validators.get((Hash.h256_s(key, null)[0] & 0xff) % validators.size()); } } @@ -295,15 +294,18 @@ public Spec vmSpec() { periods[MAINNET.id()][UNIFORM_DISTRIBUTION.id()] = new long[] { 200_001L, 400_000L }; periods[MAINNET.id()][VIRTUAL_MACHINE.id()] = new long[] { 1_500_001L, 1_700_000L }; periods[MAINNET.id()][VOTING_PRECOMPILED_UPGRADE.id()] = new long[] { 1_600_001L, 1_800_000L }; + periods[MAINNET.id()][ED25519_CONTRACT.id()] = new long[] { 2_800_804L, 3_000_000L }; periods[TESTNET.id()][UNIFORM_DISTRIBUTION.id()] = new long[] { 1L, 200_000L }; periods[TESTNET.id()][VIRTUAL_MACHINE.id()] = new long[] { 1L, 200_000L }; periods[TESTNET.id()][VOTING_PRECOMPILED_UPGRADE.id()] = new long[] { 150_001L, 350_000L }; + periods[MAINNET.id()][ED25519_CONTRACT.id()] = new long[] { 1_000_000L, 1_500_000L }; // as soon as possible periods[DEVNET.id()][UNIFORM_DISTRIBUTION.id()] = new long[] { 1L, 200_000L }; periods[DEVNET.id()][VIRTUAL_MACHINE.id()] = new long[] { 1L, 200_000L }; periods[DEVNET.id()][VOTING_PRECOMPILED_UPGRADE.id()] = new long[] { 1, 200_000L }; + periods[DEVNET.id()][ED25519_CONTRACT.id()] = new long[] { 1, 200_000L }; } @Override @@ -590,6 +592,11 @@ public boolean forkVotingPrecompiledUpgradeEnabled() { return forkVotingPrecompiledUpgradeEnabled; } + @Override + public boolean forkEd25519ContractEnabled() { + return forkEd25519ContractEnabled; + } + protected void init() { File f = getFile(); if (!f.exists()) { diff --git a/src/main/java/org/semux/config/Config.java b/src/main/java/org/semux/config/Config.java index f072595fa..b57037b11 100644 --- a/src/main/java/org/semux/config/Config.java +++ b/src/main/java/org/semux/config/Config.java @@ -444,6 +444,13 @@ public interface Config { */ boolean forkVotingPrecompiledUpgradeEnabled(); + /** + * Returns whether ED25519_CONTRACT fork is enabled. + * + * @return + */ + boolean forkEd25519ContractEnabled(); + // ========================= // Checkpoints // ========================= @@ -462,4 +469,5 @@ public interface Config { * [block height] */ Map manuallyActivatedForks(); + } diff --git a/src/main/java/org/semux/config/Constants.java b/src/main/java/org/semux/config/Constants.java index a1f2d8ea8..68a66b57d 100644 --- a/src/main/java/org/semux/config/Constants.java +++ b/src/main/java/org/semux/config/Constants.java @@ -34,7 +34,7 @@ public class Constants { /** * Version of this client. */ - public static final String CLIENT_VERSION = "2.1.1"; + public static final String CLIENT_VERSION = "2.2.0"; /** * Algorithm name for the 256-bit hash. diff --git a/src/main/java/org/semux/config/DevnetConfig.java b/src/main/java/org/semux/config/DevnetConfig.java index aa8d867f9..4cfaeb5b5 100644 --- a/src/main/java/org/semux/config/DevnetConfig.java +++ b/src/main/java/org/semux/config/DevnetConfig.java @@ -23,6 +23,7 @@ public DevnetConfig(String dataDir) { this.forkUniformDistributionEnabled = true; this.forkVirtualMachineEnabled = true; this.forkVotingPrecompiledUpgradeEnabled = true; + this.forkEd25519ContractEnabled = true; // set fast blocks bftNewHeightTimeout = 1000L; @@ -48,6 +49,7 @@ public Map manuallyActivatedForks() { forks.put(Fork.UNIFORM_DISTRIBUTION, 1l); forks.put(Fork.VIRTUAL_MACHINE, 1l); forks.put(Fork.VOTING_PRECOMPILED_UPGRADE, 1l); + forks.put(Fork.ED25519_CONTRACT, 1l); return forks; } diff --git a/src/main/java/org/semux/config/MainnetConfig.java b/src/main/java/org/semux/config/MainnetConfig.java index 7c3125d9b..8f8486cd7 100644 --- a/src/main/java/org/semux/config/MainnetConfig.java +++ b/src/main/java/org/semux/config/MainnetConfig.java @@ -45,6 +45,7 @@ public MainnetConfig(String dataDir) { this.forkUniformDistributionEnabled = true; this.forkVirtualMachineEnabled = true; this.forkVotingPrecompiledUpgradeEnabled = true; + this.forkEd25519ContractEnabled = false; // enable this when we are ready to go } @Override diff --git a/src/main/java/org/semux/config/TestnetConfig.java b/src/main/java/org/semux/config/TestnetConfig.java index 5e1cb9cf1..d3c504140 100644 --- a/src/main/java/org/semux/config/TestnetConfig.java +++ b/src/main/java/org/semux/config/TestnetConfig.java @@ -20,6 +20,7 @@ public TestnetConfig(String dataDir) { this.forkUniformDistributionEnabled = true; this.forkVirtualMachineEnabled = true; this.forkVotingPrecompiledUpgradeEnabled = true; + this.forkEd25519ContractEnabled = true; } @Override diff --git a/src/main/java/org/semux/consensus/SemuxBft.java b/src/main/java/org/semux/consensus/SemuxBft.java index 82f308c46..cfafb0f4f 100644 --- a/src/main/java/org/semux/consensus/SemuxBft.java +++ b/src/main/java/org/semux/consensus/SemuxBft.java @@ -27,6 +27,7 @@ import org.semux.core.Block; import org.semux.core.BlockHeader; import org.semux.core.Blockchain; +import org.semux.core.Fork; import org.semux.core.PendingManager; import org.semux.core.SyncManager; import org.semux.core.Transaction; @@ -766,7 +767,7 @@ protected Block proposeBlock() { final List includedResults = new ArrayList<>(); TransactionExecutor exec = new TransactionExecutor(config, blockStore, chain.isVMEnabled(), - chain.isVotingPrecompiledUpgraded()); + chain.isVotingPrecompiledUpgraded(), chain.isEd25519ContractEnabled()); SemuxBlock semuxBlock = new SemuxBlock(tempHeader, config.spec().maxBlockGasLimit()); // only propose gas used up to configured block gas limit @@ -841,7 +842,7 @@ protected boolean validateBlockProposal(BlockHeader header, List tr // [2] check transactions List unvalidatedTransactions = getUnvalidatedTransactions(transactions); - if (!block.validateTransactions(header, unvalidatedTransactions, transactions, config.network())) { + if (!block.validateTransactions(header, unvalidatedTransactions, transactions, config.network(), kernel.getBlockchain().isForkActivated(Fork.ED25519_CONTRACT))) { logger.warn("Invalid transactions"); return false; } @@ -852,7 +853,7 @@ protected boolean validateBlockProposal(BlockHeader header, List tr // [3] evaluate transactions TransactionExecutor transactionExecutor = new TransactionExecutor(config, blockStore, chain.isVMEnabled(), - chain.isVotingPrecompiledUpgraded()); + chain.isVotingPrecompiledUpgraded(), chain.isEd25519ContractEnabled()); List results = transactionExecutor.execute(transactions, asTrack, dsTrack, new SemuxBlock(header, config.spec().maxBlockGasLimit()), 0); if (!block.validateResults(header, results)) { diff --git a/src/main/java/org/semux/core/Block.java b/src/main/java/org/semux/core/Block.java index 7698b573a..c3d13fa17 100644 --- a/src/main/java/org/semux/core/Block.java +++ b/src/main/java/org/semux/core/Block.java @@ -151,10 +151,11 @@ public boolean validateHeader(BlockHeader header, BlockHeader parentHeader) { * @param header * @param transactions * @param network + * @param isFixTxHash * @return */ - public boolean validateTransactions(BlockHeader header, List transactions, Network network) { - return validateTransactions(header, transactions, transactions, network); + public boolean validateTransactions(BlockHeader header, List transactions, Network network, boolean isFixTxHash) { + return validateTransactions(header, transactions, transactions, network, isFixTxHash); } /** @@ -169,18 +170,19 @@ public boolean validateTransactions(BlockHeader header, List transa * all transactions within the block * @param network * network + * @param isFixTxHash * @return */ public boolean validateTransactions(BlockHeader header, Collection unvalidatedTransactions, - List allTransactions, Network network) { + List allTransactions, Network network, boolean isFixTxHash) { // validate transactions if (!Key.isVerifyBatchSupported() || unvalidatedTransactions.size() < 3) { - if (!unvalidatedTransactions.parallelStream().allMatch(tx -> tx.validate(network))) { + if (!unvalidatedTransactions.parallelStream().allMatch(tx -> tx.validate_verify_sign(network, isFixTxHash))) { return false; } } else { - if (!unvalidatedTransactions.parallelStream().allMatch(tx -> tx.validate(network, false))) { + if (!unvalidatedTransactions.parallelStream().allMatch(tx -> tx.validate_no_verify_sign(network, isFixTxHash))) { return false; } @@ -460,6 +462,7 @@ public byte[] getEncodedVotes() { * Serialized transaction results * @param v * Serialized votes + * @param isFixTxHash * @return */ public static Block fromComponents(byte[] h, byte[] t, byte[] r, byte[] v) { diff --git a/src/main/java/org/semux/core/BlockHeader.java b/src/main/java/org/semux/core/BlockHeader.java index 3653e7318..2bc8c562a 100644 --- a/src/main/java/org/semux/core/BlockHeader.java +++ b/src/main/java/org/semux/core/BlockHeader.java @@ -71,7 +71,7 @@ public BlockHeader(long number, byte[] coinbase, byte[] prevHash, long timestamp enc.writeBytes(stateRoot); enc.writeBytes(data); this.encoded = enc.toBytes(); - this.hash = Hash.h256(encoded); + this.hash = Hash.h256_s(encoded, null); } /** @@ -112,7 +112,7 @@ public boolean validate() { && stateRoot != null && Arrays.equals(Bytes.EMPTY_HASH, stateRoot) // RESERVED FOR VM && data != null && data.length <= BlockHeaderData.MAX_SIZE && encoded != null - && Arrays.equals(Hash.h256(encoded), hash); + && Arrays.equals(Hash.h256_s(encoded, null), hash); } public byte[] getHash() { diff --git a/src/main/java/org/semux/core/Blockchain.java b/src/main/java/org/semux/core/Blockchain.java index db732b08f..0c7b08236 100644 --- a/src/main/java/org/semux/core/Blockchain.java +++ b/src/main/java/org/semux/core/Blockchain.java @@ -270,4 +270,6 @@ public interface Blockchain { boolean isVMEnabled(); boolean isVotingPrecompiledUpgraded(); + + boolean isEd25519ContractEnabled(); } diff --git a/src/main/java/org/semux/core/BlockchainImpl.java b/src/main/java/org/semux/core/BlockchainImpl.java index a499e0340..93b5cce5b 100644 --- a/src/main/java/org/semux/core/BlockchainImpl.java +++ b/src/main/java/org/semux/core/BlockchainImpl.java @@ -6,9 +6,7 @@ */ package org.semux.core; -import static org.semux.core.Fork.UNIFORM_DISTRIBUTION; -import static org.semux.core.Fork.VIRTUAL_MACHINE; -import static org.semux.core.Fork.VOTING_PRECOMPILED_UPGRADE; +import static org.semux.core.Fork.*; import java.io.IOException; import java.nio.file.FileVisitResult; @@ -394,11 +392,13 @@ public synchronized void addBlock(Block block) { Transaction tx = new Transaction(config.network(), TransactionType.COINBASE, block.getCoinbase(), + Constants.COINBASE_KEY.toAddress(), reward, Amount.ZERO, block.getNumber(), block.getTimestamp(), - Bytes.EMPTY_BYTES); + Bytes.EMPTY_BYTES, + isForkActivated(Fork.ED25519_CONTRACT)); tx.sign(Constants.COINBASE_KEY); indexDB.put(Bytes.merge(TYPE_TRANSACTION_INDEX_BY_HASH, tx.getHash()), tx.toBytes()); indexDB.put(Bytes.merge(TYPE_BLOCK_COINBASE_BY_NUMBER, Bytes.of(block.getNumber())), tx.getHash()); @@ -714,6 +714,11 @@ public boolean isVotingPrecompiledUpgraded() { return isForkActivated(VOTING_PRECOMPILED_UPGRADE); } + @Override + public boolean isEd25519ContractEnabled() { + return isForkActivated(ED25519_CONTRACT); + } + @Override public byte[] constructBlockHeaderDataField() { Set set = new HashSet<>(); @@ -729,6 +734,9 @@ public byte[] constructBlockHeaderDataField() { if (config.forkVotingPrecompiledUpgradeEnabled()) { addFork(set, VOTING_PRECOMPILED_UPGRADE); } + if (config.forkEd25519ContractEnabled()) { + addFork(set, ED25519_CONTRACT); + } return set.isEmpty() ? new BlockHeaderData().toBytes() : new BlockHeaderData(ForkSignalSet.of(set)).toBytes(); } @@ -786,7 +794,7 @@ protected boolean validateBlock(Block block, AccountState asTrack, DelegateState } // [2] check transactions - if (!block.validateTransactions(header, transactions, config.network())) { + if (!block.validateTransactions(header, transactions, config.network(), isForkActivated(Fork.ED25519_CONTRACT))) { logger.error("Invalid transactions"); return false; } @@ -797,7 +805,7 @@ protected boolean validateBlock(Block block, AccountState asTrack, DelegateState // [3] evaluate transactions TransactionExecutor transactionExecutor = new TransactionExecutor(config, blockStore, isVMEnabled(), - isVotingPrecompiledUpgraded()); + isVotingPrecompiledUpgraded(), isEd25519ContractEnabled()); List results = transactionExecutor.execute(transactions, asTrack, dsTrack, new SemuxBlock(block.getHeader(), config.spec().maxBlockGasLimit()), 0); @@ -910,6 +918,10 @@ protected void activateForks() { && forks.activateFork(VOTING_PRECOMPILED_UPGRADE)) { setActivatedForks(forks.getActivatedForks()); } + if (config.forkEd25519ContractEnabled() + && forks.activateFork(ED25519_CONTRACT)) { + setActivatedForks(forks.getActivatedForks()); + } } /** diff --git a/src/main/java/org/semux/core/Fork.java b/src/main/java/org/semux/core/Fork.java index a35c6ae8b..099306845 100644 --- a/src/main/java/org/semux/core/Fork.java +++ b/src/main/java/org/semux/core/Fork.java @@ -29,7 +29,14 @@ public enum Fork implements Comparable { /** * This soft fork introduces an upgrade to the voting pre-compiled contracts. */ - VOTING_PRECOMPILED_UPGRADE((short) 3, 1500, 2000); + VOTING_PRECOMPILED_UPGRADE((short) 3, 1500, 2000), + + /** + * This soft fork adds: + * - new pre-compiled contracts for ED25519 as well as will + * - new TX hash + */ + ED25519_CONTRACT((short) 4, 1500, 2000); /** * An unique number of this fork. diff --git a/src/main/java/org/semux/core/PendingManager.java b/src/main/java/org/semux/core/PendingManager.java index 29318dc44..e306a136b 100644 --- a/src/main/java/org/semux/core/PendingManager.java +++ b/src/main/java/org/semux/core/PendingManager.java @@ -167,7 +167,7 @@ public synchronized void addTransaction(Transaction tx) { if (queue.size() < QUEUE_SIZE_LIMIT && processedTxs.getIfPresent(hash) == null - && tx.validate(kernel.getConfig().network())) { + && tx.validate_verify_sign(kernel.getConfig().network(), kernel.getBlockchain().isForkActivated(Fork.ED25519_CONTRACT))) { // NOTE: re-insertion doesn't affect item order queue.put(ByteArray.of(tx.getHash()), tx); } @@ -186,7 +186,7 @@ public synchronized ProcessingResult addTransactionSync(Transaction tx) { return new ProcessingResult(0, TransactionResult.Code.INVALID_NONCE); } - if (tx.validate(kernel.getConfig().network())) { + if (tx.validate_verify_sign(kernel.getConfig().network(), kernel.getBlockchain().isForkActivated(Fork.ED25519_CONTRACT))) { // proceed with the tx, ignoring transaction queue size limit return processTransaction(tx, false, true); } else { @@ -352,7 +352,8 @@ protected ProcessingResult processTransaction(Transaction tx, boolean isIncluded AccountState as = pendingAS.track(); DelegateState ds = pendingDS.track(); TransactionResult result = new TransactionExecutor(kernel.getConfig(), blockStore, - kernel.getBlockchain().isVMEnabled(), kernel.getBlockchain().isVotingPrecompiledUpgraded()) + kernel.getBlockchain().isVMEnabled(), kernel.getBlockchain().isVotingPrecompiledUpgraded(), + kernel.getBlockchain().isEd25519ContractEnabled()) .execute(tx, as, ds, dummyBlock, 0); if (result.getCode().isAcceptable()) { diff --git a/src/main/java/org/semux/core/Transaction.java b/src/main/java/org/semux/core/Transaction.java index 529f10ff0..0926fcaef 100644 --- a/src/main/java/org/semux/core/Transaction.java +++ b/src/main/java/org/semux/core/Transaction.java @@ -20,8 +20,11 @@ import org.semux.crypto.Key.Signature; import org.semux.util.SimpleDecoder; import org.semux.util.SimpleEncoder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class Transaction { + private static final Logger logger = LoggerFactory.getLogger(Transaction.class); private final byte networkId; @@ -54,6 +57,7 @@ public class Transaction { * @param network * @param type * @param to + * @param from * @param value * @param fee * @param nonce @@ -61,9 +65,10 @@ public class Transaction { * @param data * @param gas * @param gasPrice + * @param isFixTxHash */ - public Transaction(Network network, TransactionType type, byte[] to, Amount value, Amount fee, long nonce, - long timestamp, byte[] data, long gas, Amount gasPrice) { + public Transaction(Network network, TransactionType type, byte[] to, byte[] from, Amount value, Amount fee, long nonce, + long timestamp, byte[] data, long gas, Amount gasPrice, boolean isFixTxHash) { this.networkId = network.id(); this.type = type; this.to = to; @@ -90,7 +95,9 @@ public Transaction(Network network, TransactionType type, byte[] to, Amount valu enc.writeAmount(gasPrice); } this.encoded = enc.toBytes(); - this.hash = Hash.h256(encoded); + this.hash = Hash.h256_s(encoded, isFixTxHash ? from : null); + + logger.info("!!! isFixTxHash = " + isFixTxHash); } /** @@ -99,11 +106,14 @@ public Transaction(Network network, TransactionType type, byte[] to, Amount valu * @param hash * @param encoded * @param signature + * @param isFixTxHash */ - private Transaction(byte[] hash, byte[] encoded, byte[] signature) { + private Transaction(byte[] hash, byte[] encoded, byte[] signature, boolean isFixTxHash) { this.hash = hash; + + this.signature = Signature.fromBytes(signature); - Transaction decodedTx = fromEncoded(encoded); + Transaction decodedTx = fromEncoded(encoded, this.signature.getAddress(), isFixTxHash); this.networkId = decodedTx.networkId; this.type = decodedTx.type; this.to = decodedTx.to; @@ -117,12 +127,13 @@ private Transaction(byte[] hash, byte[] encoded, byte[] signature) { this.gasPrice = decodedTx.gasPrice; this.encoded = encoded; - this.signature = Signature.fromBytes(signature); + + logger.info("isFixTxHash = " + isFixTxHash); } - public Transaction(Network network, TransactionType type, byte[] toAddress, Amount value, Amount fee, long nonce, - long timestamp, byte[] data) { - this(network, type, toAddress, value, fee, nonce, timestamp, data, 0, Amount.ZERO); + public Transaction(Network network, TransactionType type, byte[] toAddress, byte[] fromAddress, Amount value, Amount fee, long nonce, + long timestamp, byte[] data, boolean isFixTxHash) { + this(network, type, toAddress, fromAddress, value, fee, nonce, timestamp, data, 0, Amount.ZERO, isFixTxHash); } public boolean isVMTransaction() { @@ -154,9 +165,13 @@ public Transaction sign(Key key) { * Whether to verify the transaction signature or not. This is useful * when there are multiple transaction signatures that can be * verified in batch for performance reason. + * @param isFixTxHash * @return true if success, otherwise false */ - public boolean validate(Network network, boolean verifySignature) { + private boolean validate(Network network, boolean verifySignature, boolean isFixTxHash) { + + logger.info("isFixTxHash = " + isFixTxHash); + return hash != null && hash.length == Hash.HASH_LEN && networkId == network.id() && type != null @@ -171,7 +186,7 @@ public boolean validate(Network network, boolean verifySignature) { && encoded != null && signature != null && !Arrays.equals(signature.getAddress(), EMPTY_ADDRESS) - && Arrays.equals(Hash.h256(encoded), hash) + && Arrays.equals(Hash.h256_s(encoded, isFixTxHash ? signature.getAddress() : null), hash) && (!verifySignature || Key.verify(hash, signature)) // The coinbase key is publicly available. People can use it for transactions. @@ -182,8 +197,12 @@ public boolean validate(Network network, boolean verifySignature) { && !Arrays.equals(to, Constants.COINBASE_ADDRESS))); } - public boolean validate(Network network) { - return validate(network, true); + public boolean validate_verify_sign(Network network, boolean isFixTxHash) { + return validate(network, true, isFixTxHash); + } + + public boolean validate_no_verify_sign(Network network, boolean isFixTxHash) { + return validate(network, false, isFixTxHash); } /** @@ -293,9 +312,14 @@ public Amount getGasPrice() { * * @param encoded * the bytes of encoded transaction + * @param from + * @param isFixTxHash * @return the decoded transaction */ - public static Transaction fromEncoded(byte[] encoded) { + public static Transaction fromEncoded(byte[] encoded, byte[] from, boolean isFixTxHash) { + + System.out.println("isFixTxHash = " + isFixTxHash); + SimpleDecoder decoder = new SimpleDecoder(encoded); byte networkId = decoder.readByte(); @@ -316,8 +340,8 @@ public static Transaction fromEncoded(byte[] encoded) { gasPrice = decoder.readAmount(); } - return new Transaction(Network.of(networkId), transactionType, to, value, fee, nonce, timestamp, data, - gas, gasPrice); + return new Transaction(Network.of(networkId), transactionType, to, from, value, fee, nonce, timestamp, data, + gas, gasPrice, isFixTxHash); } /** @@ -347,6 +371,7 @@ public byte[] toBytes() { * Parses from a byte array. * * @param bytes + * @param isFixTxHash * @return */ public static Transaction fromBytes(byte[] bytes) { @@ -355,7 +380,7 @@ public static Transaction fromBytes(byte[] bytes) { byte[] encoded = dec.readBytes(); byte[] signature = dec.readBytes(); - return new Transaction(hash, encoded, signature); + return new Transaction(hash, encoded, signature, false); } /** diff --git a/src/main/java/org/semux/core/TransactionExecutor.java b/src/main/java/org/semux/core/TransactionExecutor.java index f5c9fa3d3..cdd9404d5 100644 --- a/src/main/java/org/semux/core/TransactionExecutor.java +++ b/src/main/java/org/semux/core/TransactionExecutor.java @@ -88,6 +88,7 @@ public static boolean validateDelegateName(byte[] data) { private BlockStore blockStore; private boolean isVMEnabled; private boolean isVotingPrecompiledUpgraded; + private boolean isEd25519ContractEnabled; /** * Creates a new transaction executor. @@ -95,11 +96,12 @@ public static boolean validateDelegateName(byte[] data) { * @param config */ public TransactionExecutor(Config config, BlockStore blockStore, boolean isVMEnabled, - boolean isVotingPrecompiledUpgraded) { + boolean isVotingPrecompiledUpgraded, boolean isEd25519ContractEnabled) { this.spec = config.spec(); this.blockStore = blockStore; this.isVMEnabled = isVMEnabled; this.isVotingPrecompiledUpgraded = isVotingPrecompiledUpgraded; + this.isEd25519ContractEnabled = isEd25519ContractEnabled; } /** @@ -319,6 +321,15 @@ private void executeVmTransaction(Transaction tx, AccountState as, DelegateState byte[] returnData = receipt.getReturnData(); // NOTE: the following code is to simulate the behaviour of old clients + if (!isEd25519ContractEnabled) { + // Calling to a non existant precompiled contract just returns success/empty + // + if (DataWord.of(tx.getTo()).equals(DataWord.of(0x9))) { + code = Code.SUCCESS; + returnData = Bytes.EMPTY_BYTES; + gasUsed = tx.getGas(); + } + } if (!isVotingPrecompiledUpgraded) { // the old GetVote and GetVotes precompiled contracts always fail if (DataWord.of(tx.getTo()).equals(DataWord.of(102)) diff --git a/src/main/java/org/semux/core/Wallet.java b/src/main/java/org/semux/core/Wallet.java index 6d84fbb91..d9f434822 100644 --- a/src/main/java/org/semux/core/Wallet.java +++ b/src/main/java/org/semux/core/Wallet.java @@ -141,11 +141,11 @@ public boolean unlock(String password) { switch (version) { case 1: - key = Hash.h256(Bytes.of(password)); + key = Hash.h256_s(Bytes.of(password), null); newAccounts = readAccounts(key, dec, false, version); break; case 2: - key = Hash.h256(Bytes.of(password)); + key = Hash.h256_s(Bytes.of(password), null); newAccounts = readAccounts(key, dec, true, version); newAliases = readAddressAliases(key, dec); break; diff --git a/src/main/java/org/semux/crypto/Hash.java b/src/main/java/org/semux/crypto/Hash.java index b17f722c7..2c0b05cd3 100644 --- a/src/main/java/org/semux/crypto/Hash.java +++ b/src/main/java/org/semux/crypto/Hash.java @@ -28,16 +28,19 @@ public class Hash { * Generate the 256-bit hash. * * @param input + * @param salt * @return */ - public static byte[] h256(byte[] input) { + public static byte[] h256_s(byte[] input, byte[] salt) { if (Native.isEnabled()) { - return Native.h256(input); + return Native.h256(input, salt); } else { try { MessageDigest digest = MessageDigest.getInstance(Constants.HASH_ALGORITHM); - return digest.digest(input); + digest.update(input); + digest.update(salt); + return digest.digest(); } catch (Exception e) { throw new CryptoException(e); } @@ -49,14 +52,15 @@ public static byte[] h256(byte[] input) { * * @param one * @param two + * @param salt * @return */ - public static byte[] h256(byte[] one, byte[] two) { + public static byte[] h256_s(byte[] one, byte[] two, byte[] salt) { byte[] all = new byte[one.length + two.length]; System.arraycopy(one, 0, all, 0, one.length); System.arraycopy(two, 0, all, one.length, two.length); - return Hash.h256(all); + return Hash.h256_s(all, null); } /** @@ -70,7 +74,7 @@ public static byte[] h160(byte[] input) { return Native.h160(input); } else { try { - byte[] h256 = h256(input); + byte[] h256 = h256_s(input, null); RIPEMD160Digest digest = new RIPEMD160Digest(); digest.update(h256, 0, h256.length); diff --git a/src/main/java/org/semux/crypto/Native.java b/src/main/java/org/semux/crypto/Native.java index b7bfe7fc1..4baf64a8a 100644 --- a/src/main/java/org/semux/crypto/Native.java +++ b/src/main/java/org/semux/crypto/Native.java @@ -122,9 +122,10 @@ public static void enable() { * Computes the 256-bit hash. See {@link Hash#h256(byte[])} * * @param data + * @param salt (blake2b) * @return */ - public static native byte[] h256(byte[] data); + public static native byte[] h256(byte[] data, byte[] salt); /** * Computes the 160-bit hash. See {@link Hash#h160(byte[])} diff --git a/src/main/java/org/semux/gui/TransactionSender.java b/src/main/java/org/semux/gui/TransactionSender.java index e4aa2b864..b0fab681f 100644 --- a/src/main/java/org/semux/gui/TransactionSender.java +++ b/src/main/java/org/semux/gui/TransactionSender.java @@ -9,6 +9,7 @@ import org.semux.Kernel; import org.semux.Network; import org.semux.core.Amount; +import org.semux.core.Fork; import org.semux.core.PendingManager; import org.semux.core.Transaction; import org.semux.core.TransactionType; @@ -30,7 +31,7 @@ public static PendingManager.ProcessingResult send(Kernel kernel, WalletAccount byte[] from = account.getKey().toAddress(); long nonce = pendingMgr.getNonce(from); long timestamp = TimeUtil.currentTimeMillis(); - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data, gas, gasPrice); + Transaction tx = new Transaction(network, type, to, from, value, fee, nonce, timestamp, data, gas, gasPrice, kernel.getBlockchain().isForkActivated(Fork.ED25519_CONTRACT)); tx.sign(account.getKey()); return pendingMgr.addTransactionSync(tx); diff --git a/src/main/java/org/semux/util/MerkleTree.java b/src/main/java/org/semux/util/MerkleTree.java index eb1629b36..a68fce75d 100644 --- a/src/main/java/org/semux/util/MerkleTree.java +++ b/src/main/java/org/semux/util/MerkleTree.java @@ -93,7 +93,7 @@ private Node build(List nodes) { Node left = nodes.get(i); if (i + 1 < nodes.size()) { Node right = nodes.get(i + 1); - list.add(new Node(Hash.h256(left.value, right.value), left, right)); + list.add(new Node(Hash.h256_s(left.value, right.value, null), left, right)); } else { list.add(new Node(left.value, left, null)); } diff --git a/src/main/java/org/semux/util/MerkleUtil.java b/src/main/java/org/semux/util/MerkleUtil.java index d8427fbd1..b57f4ee55 100644 --- a/src/main/java/org/semux/util/MerkleUtil.java +++ b/src/main/java/org/semux/util/MerkleUtil.java @@ -40,7 +40,7 @@ public static byte[] computeTransactionsRoot(List txs) { public static byte[] computeResultsRoot(List results) { List hashes = new ArrayList<>(); for (TransactionResult tx : results) { - hashes.add(Hash.h256(tx.toBytesForMerkle())); + hashes.add(Hash.h256_s(tx.toBytesForMerkle(), null)); } return new MerkleTree(hashes).getRootHash(); } diff --git a/src/main/java/org/semux/vm/client/Ed25519Vfy.java b/src/main/java/org/semux/vm/client/Ed25519Vfy.java new file mode 100644 index 000000000..61a681159 --- /dev/null +++ b/src/main/java/org/semux/vm/client/Ed25519Vfy.java @@ -0,0 +1,70 @@ +/** + * Copyright (c) 2017-2018 The Semux Developers + * + * Distributed under the MIT software license, see the accompanying file + * LICENSE or https://opensource.org/licenses/mit-license.php + */ +package org.semux.vm.client; + +import java.util.Arrays; + +import org.ethereum.vm.chainspec.PrecompiledContract; +import org.ethereum.vm.chainspec.PrecompiledContractContext; +import org.ethereum.vm.util.Pair; +import org.semux.crypto.Key; +import org.semux.util.Bytes; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Implementation of + * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-665.md + */ +public class Ed25519Vfy implements PrecompiledContract { + private static final Logger logger = LoggerFactory.getLogger(Ed25519Vfy.class); + + // any non-zero value indicates a signature verification failure + public static final Pair signatureVerificationFailure = new Pair<>(true, new byte[] { 1 }); + + @Override + public long getGasForData(byte[] bytes) { + return 2000; + } + + @Override + public Pair execute(PrecompiledContractContext context) { + + byte[] data = context.getInternalTransaction().getData(); + + if (data == null || data.length != 128) { + return SemuxPrecompiledContracts.failure; + } + + /** + * ED25519VFY takes as input 128 octets: + * + * message: the 32-octet message that was signed public key: the 32-octet + * Ed25519 public key of the signer signature: the 64-octet Ed25519 signature + */ + byte[] message = Arrays.copyOfRange(data, 0, 32); + byte[] publicKey = Arrays.copyOfRange(data, 32, 64); + byte[] signature = Arrays.copyOfRange(data, 64, 128); + + byte[] semSignature = Bytes.merge(signature, publicKey); + + boolean isValidSignature = false; + try { + Key.Signature sig = Key.Signature.fromBytes(semSignature); + if (sig != null) { + if (Key.verify(message, sig)) { + isValidSignature = true; + } + } + } catch (Exception e) { + logger.info("Exception while verifying signature", e); + return SemuxPrecompiledContracts.failure; + } + + return isValidSignature ? SemuxPrecompiledContracts.success : signatureVerificationFailure; + } +} diff --git a/src/main/java/org/semux/vm/client/SemuxPrecompiledContracts.java b/src/main/java/org/semux/vm/client/SemuxPrecompiledContracts.java index 51cf7b2b0..ae30d03b5 100644 --- a/src/main/java/org/semux/vm/client/SemuxPrecompiledContracts.java +++ b/src/main/java/org/semux/vm/client/SemuxPrecompiledContracts.java @@ -33,14 +33,18 @@ public class SemuxPrecompiledContracts extends ConstantinoplePrecompiledContract private static final Unvote unvote = new Unvote(); private static final GetVotes getVotes = new GetVotes(); private static final GetVote getVote = new GetVote(); + private static final Ed25519Vfy ed25519vfy = new Ed25519Vfy(); private static final DataWord voteAddr = DataWord.of(100); private static final DataWord unvoteAddr = DataWord.of(101); private static final DataWord getVotesAddr = DataWord.of(102); private static final DataWord getVoteAddr = DataWord.of(103); - private static final Pair success = new Pair<>(true, ArrayUtils.EMPTY_BYTE_ARRAY); - private static final Pair failure = new Pair<>(false, ArrayUtils.EMPTY_BYTE_ARRAY); + // match the ethereum code, eip-665 + private static final DataWord ed25519vfyAddr = DataWord.of(0x9); + + public static final Pair success = new Pair<>(true, ArrayUtils.EMPTY_BYTE_ARRAY); + public static final Pair failure = new Pair<>(false, ArrayUtils.EMPTY_BYTE_ARRAY); @Override public PrecompiledContract getContractForAddress(DataWord address) { @@ -53,6 +57,8 @@ public PrecompiledContract getContractForAddress(DataWord address) { return getVotes; } else if (address.equals(getVoteAddr)) { return getVote; + } else if (address.equals(ed25519vfyAddr)) { + return ed25519vfy; } return super.getContractForAddress(address); } diff --git a/src/main/native/README.md b/src/main/native/README.md index 7e6413e7e..da5abd320 100644 --- a/src/main/native/README.md +++ b/src/main/native/README.md @@ -25,6 +25,16 @@ Steps to build on Debian/Ubuntu based distributions with a x86_64 machine: ``` sudo apt install cmake automake autoconf gcc gcc-aarch64-linux-gnu gcc-mingw-w64 binutils binutils-aarch64-linux-gnu binutils-mingw-w64 +clone ed25519-donna: +cd ../../native/crypto +git clone https://github.com/floodyberry/ed25519-donna + +clone libsodium: +cd ../../native/crypto +git clone https://github.com/jedisct1/libsodium +cd ./libsodium +git checkout b732443c442239c2e0184820e9b23cca0de0828c + mkdir build && cd build cmake -vvv -DCMAKE_TOOLCHAIN_FILE=../cmake/toolchain-Linux-x86_64.cmake ../ make -j$(nproc) diff --git a/src/main/native/crypto/ed25519-donna b/src/main/native/crypto/ed25519-donna index 68049dfa1..8757bd4cd 160000 --- a/src/main/native/crypto/ed25519-donna +++ b/src/main/native/crypto/ed25519-donna @@ -1 +1 @@ -Subproject commit 68049dfa1e44cb9a1113d216d1179a3d7cd087e5 +Subproject commit 8757bd4cd209cb032853ece0ce413f122eef212c diff --git a/src/main/native/crypto/libsodium b/src/main/native/crypto/libsodium index b732443c4..4f5e89fa8 160000 --- a/src/main/native/crypto/libsodium +++ b/src/main/native/crypto/libsodium @@ -1 +1 @@ -Subproject commit b732443c442239c2e0184820e9b23cca0de0828c +Subproject commit 4f5e89fa84ce1d178a6765b8b46f2b6f91216677 diff --git a/src/main/native/crypto/org_semux_crypto_Native.cpp b/src/main/native/crypto/org_semux_crypto_Native.cpp index 5fdfa3619..84daa2a76 100644 --- a/src/main/native/crypto/org_semux_crypto_Native.cpp +++ b/src/main/native/crypto/org_semux_crypto_Native.cpp @@ -8,7 +8,7 @@ #define ed25519_SIGNATUREBYTES 64U JNIEXPORT jbyteArray JNICALL Java_org_semux_crypto_Native_h256 -(JNIEnv *env, jclass cls, jbyteArray msg) +(JNIEnv *env, jclass cls, jbyteArray msg, jbyteArray salt) { // check inputs if (msg == NULL) { @@ -16,18 +16,34 @@ JNIEXPORT jbyteArray JNICALL Java_org_semux_crypto_Native_h256 return NULL; } - // read byte arrays + // read message bytes jsize msg_size = env->GetArrayLength(msg); jbyte *msg_buf = (jbyte *)malloc(msg_size); env->GetByteArrayRegion(msg, 0, msg_size, msg_buf); + // read salt bytes + jsize salt_size = 0; + jbyte *salt_buf = NULL; + + if (salt != NULL) + { + salt_size = env->GetArrayLength(salt); + salt_buf = (jbyte *)malloc(salt_size); + env->GetByteArrayRegion(salt, 0, salt_size, salt_buf); + } + // compute blake2b hash unsigned char hash[crypto_generichash_blake2b_BYTES]; - crypto_generichash_blake2b(hash, sizeof(hash), (const unsigned char *)msg_buf, msg_size, NULL, 0); + crypto_generichash_blake2b(hash, sizeof(hash), (const unsigned char *)msg_buf, msg_size, (const unsigned char *)salt_buf, salt_size); // release buffer free(msg_buf); + if (salt_buf != NULL) + { + free(salt_buf); + } + jbyteArray result = env->NewByteArray(sizeof(hash)); env->SetByteArrayRegion(result, 0, sizeof(hash), (const jbyte*)hash); return result; @@ -42,14 +58,14 @@ JNIEXPORT jbyteArray JNICALL Java_org_semux_crypto_Native_h160 return NULL; } - // read byte arrays + // read message bytes jsize msg_size = env->GetArrayLength(msg); jbyte *msg_buf = (jbyte *)malloc(msg_size); env->GetByteArrayRegion(msg, 0, msg_size, msg_buf); // compute blake2b hash unsigned char hash[crypto_generichash_blake2b_BYTES]; - crypto_generichash_blake2b(hash, sizeof(hash), (const unsigned char *)msg_buf, msg_size, NULL, 0); + crypto_generichash_blake2b(hash, sizeof(hash), (const unsigned char *)msg_buf, msg_size, NULL, 0); // compute ripemd160 digest unsigned char digest[20]; @@ -186,4 +202,4 @@ JNIEXPORT jboolean JNICALL Java_org_semux_crypto_Native_verifyBatch delete[] valid; return result; -} \ No newline at end of file +} diff --git a/src/main/native/crypto/org_semux_crypto_Native.h b/src/main/native/crypto/org_semux_crypto_Native.h index 97a278db8..e0d506d52 100644 --- a/src/main/native/crypto/org_semux_crypto_Native.h +++ b/src/main/native/crypto/org_semux_crypto_Native.h @@ -10,10 +10,10 @@ extern "C" { /* * Class: org_semux_crypto_Native * Method: h256 - * Signature: ([B)[B + * Signature: ([B[B)[B */ JNIEXPORT jbyteArray JNICALL Java_org_semux_crypto_Native_h256 - (JNIEnv *, jclass, jbyteArray); + (JNIEnv *, jclass, jbyteArray, jbyteArray); /* * Class: org_semux_crypto_Native diff --git a/src/main/resources/native/Darwin-x86_64/libsemuxcrypto.dylib b/src/main/resources/native/Darwin-x86_64/libsemuxcrypto.dylib deleted file mode 100755 index 691b10c04..000000000 Binary files a/src/main/resources/native/Darwin-x86_64/libsemuxcrypto.dylib and /dev/null differ diff --git a/src/main/resources/native/Linux-aarch64/libsemuxcrypto.so b/src/main/resources/native/Linux-aarch64/libsemuxcrypto.so index 8d5f417eb..d823c3645 100755 Binary files a/src/main/resources/native/Linux-aarch64/libsemuxcrypto.so and b/src/main/resources/native/Linux-aarch64/libsemuxcrypto.so differ diff --git a/src/main/resources/native/Linux-x86_64/libsemuxcrypto.so b/src/main/resources/native/Linux-x86_64/libsemuxcrypto.so index 3f844d2d6..2b0c67b7e 100755 Binary files a/src/main/resources/native/Linux-x86_64/libsemuxcrypto.so and b/src/main/resources/native/Linux-x86_64/libsemuxcrypto.so differ diff --git a/src/main/resources/native/Windows-x86_64/libsemuxcrypto.dll b/src/main/resources/native/Windows-x86_64/libsemuxcrypto.dll deleted file mode 100755 index e67c41d40..000000000 Binary files a/src/main/resources/native/Windows-x86_64/libsemuxcrypto.dll and /dev/null differ diff --git a/src/test/java/org/semux/TestUtils.java b/src/test/java/org/semux/TestUtils.java index 7c56ad692..98aba80b7 100644 --- a/src/test/java/org/semux/TestUtils.java +++ b/src/test/java/org/semux/TestUtils.java @@ -69,7 +69,7 @@ public static Transaction createTransaction(Config config, TransactionType type, long timestamp = TimeUtil.currentTimeMillis(); byte[] data = {}; - return new Transaction(network, type, to.toAddress(), value, fee, nonce, timestamp, data).sign(from); + return new Transaction(network, type, to.toAddress(), from.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()).sign(from); } // Source: diff --git a/src/test/java/org/semux/api/http/HttpHandlerTest.java b/src/test/java/org/semux/api/http/HttpHandlerTest.java index 45cf6b8a6..4280dbba8 100644 --- a/src/test/java/org/semux/api/http/HttpHandlerTest.java +++ b/src/test/java/org/semux/api/http/HttpHandlerTest.java @@ -32,6 +32,7 @@ import org.semux.api.SemuxApiService; import org.semux.config.Config; import org.semux.core.Amount; +import org.semux.core.Fork; import org.semux.core.Transaction; import org.semux.core.TransactionType; import org.semux.crypto.Hex; @@ -151,14 +152,19 @@ public void testGET() throws IOException { @Test public void testGETBigData() throws IOException { Config config = kernelRule.getKernel().getConfig(); + + Key key = new Key(); + + final boolean isFixTxHashActivated = kernelRule.getKernel().getBlockchain().isForkActivated(Fork.ED25519_CONTRACT); + Transaction tx = new Transaction(config.network(), - TransactionType.CALL, Bytes.random(20), + TransactionType.CALL, Bytes.random(20)/*to*/, key.toAddress()/*from*/, Amount.ZERO, Amount.ZERO, 0, TimeUtil.currentTimeMillis(), new byte[config.spec().maxTransactionDataSize(TransactionType.CALL)], - 5_000_000L, Amount.of(100)); - tx.sign(new Key()); - assertTrue(tx.validate(config.network())); + 5_000_000L, Amount.of(100), isFixTxHashActivated); + tx.sign(key); + assertTrue(tx.validate_verify_sign(config.network(), isFixTxHashActivated)); URL url = new URL( "http://" + ip + ":" + port + "/broadcast-raw-transactions?raw=" + Hex.encode0x(tx.toBytes())); diff --git a/src/test/java/org/semux/api/util/TransactionBuilderTest.java b/src/test/java/org/semux/api/util/TransactionBuilderTest.java index d50eefd43..f48ecb566 100644 --- a/src/test/java/org/semux/api/util/TransactionBuilderTest.java +++ b/src/test/java/org/semux/api/util/TransactionBuilderTest.java @@ -19,6 +19,7 @@ import org.semux.core.Amount; import org.semux.core.Transaction; import org.semux.core.TransactionType; +import org.semux.util.Bytes; public class TransactionBuilderTest { @@ -41,7 +42,7 @@ public void testDelegateWithWrongValue() { .withValue("6") .withNonce("7") .withFee("8") - .buildUnsigned(); + .buildUnsigned(Bytes.random(20)); assertEquals(Amount.of(6), tx.getValue()); assertEquals(7L, tx.getNonce()); } diff --git a/src/test/java/org/semux/bench/BlockchainPerformance.java b/src/test/java/org/semux/bench/BlockchainPerformance.java index 47c8b5d18..6c14002dc 100644 --- a/src/test/java/org/semux/bench/BlockchainPerformance.java +++ b/src/test/java/org/semux/bench/BlockchainPerformance.java @@ -54,7 +54,7 @@ public static Block testBlockCreation() { long nonce = 1 + i; long timestamp = TimeUtil.currentTimeMillis(); byte[] data = Bytes.EMPTY_BYTES; - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data).sign(key); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()).sign(key); txs.add(tx); res.add(new TransactionResult()); @@ -97,7 +97,7 @@ public static void testBlockValidation(Block block) { long t1 = System.nanoTime(); block.validateHeader(block.getHeader(), genesis.getHeader()); - block.validateTransactions(block.getHeader(), block.getTransactions(), config.network()); + block.validateTransactions(block.getHeader(), block.getTransactions(), config.network(), config.forkEd25519ContractEnabled()); block.validateResults(block.getHeader(), block.getResults()); // block votes validation skipped long t2 = System.nanoTime(); @@ -116,13 +116,13 @@ public static void testTransactionValidation() { long nonce = 1; long timestamp = TimeUtil.currentTimeMillis(); byte[] data = {}; - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()); tx.sign(key); int repeat = 1000; long t1 = System.nanoTime(); for (int i = 0; i < repeat; i++) { - tx.validate(network); + tx.validate_verify_sign(network, config.forkEd25519ContractEnabled()); } long t2 = System.nanoTime(); logger.info("Perf_transaction_size: {} B", tx.toBytes().length); diff --git a/src/test/java/org/semux/bench/CryptoPerformance.java b/src/test/java/org/semux/bench/CryptoPerformance.java index e0dbe1dfc..2088be767 100644 --- a/src/test/java/org/semux/bench/CryptoPerformance.java +++ b/src/test/java/org/semux/bench/CryptoPerformance.java @@ -23,7 +23,7 @@ public static void testH256() { long t1 = System.nanoTime(); for (int i = 0; i < REPEAT; i++) { - Hash.h256(data); + Hash.h256_s(data, null); } long t2 = System.nanoTime(); @@ -49,7 +49,7 @@ public static void testSign() { for (int size : DATA_SIZES) { Key eckey = new Key(); byte[] data = new byte[size]; - byte[] hash = Hash.h256(data); + byte[] hash = Hash.h256_s(data, null); long t1 = System.nanoTime(); for (int i = 0; i < REPEAT; i++) { @@ -65,7 +65,7 @@ public static void testVerify() { for (int size : DATA_SIZES) { Key eckey = new Key(); byte[] data = new byte[size]; - byte[] hash = Hash.h256(data); + byte[] hash = Hash.h256_s(data, null); byte[] sig = eckey.sign(hash).toBytes(); long t1 = System.nanoTime(); diff --git a/src/test/java/org/semux/bench/VMPerformance.java b/src/test/java/org/semux/bench/VMPerformance.java index 136e2f49c..2c15154c1 100644 --- a/src/test/java/org/semux/bench/VMPerformance.java +++ b/src/test/java/org/semux/bench/VMPerformance.java @@ -78,7 +78,7 @@ public static void main(String[] args) throws Throwable { byte[] data = Bytes.merge(Hex.decode0x("9c438a3d"), Bytes.of(j)); // sha1() long gas = 100_000L; Amount gasPrice = Amount.of(10); - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data, gas, gasPrice) + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()) .sign(key); txs.add(tx); res.add(new TransactionResult()); diff --git a/src/test/java/org/semux/consensus/ProposalTest.java b/src/test/java/org/semux/consensus/ProposalTest.java index 3b72cdbc2..d8e75f545 100644 --- a/src/test/java/org/semux/consensus/ProposalTest.java +++ b/src/test/java/org/semux/consensus/ProposalTest.java @@ -41,8 +41,9 @@ public void testBasics() { long timestamp = TimeUtil.currentTimeMillis(); byte[] data = Bytes.of("data"); - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data); - tx.sign(new Key()); + Key key1 = new Key(); + Transaction tx = new Transaction(network, type, to, key1.toAddress(), value, fee, nonce, timestamp, data, true); + tx.sign(key1); TransactionResult res = new TransactionResult(); long height = Long.MAX_VALUE; diff --git a/src/test/java/org/semux/consensus/SemuxBftTest.java b/src/test/java/org/semux/consensus/SemuxBftTest.java index 2d47e74c1..ff23d1c3c 100644 --- a/src/test/java/org/semux/consensus/SemuxBftTest.java +++ b/src/test/java/org/semux/consensus/SemuxBftTest.java @@ -265,10 +265,12 @@ private Transaction createTransaction(Key to, Key from, long time, long nonce) { kernelRule.getKernel().getConfig().network(), TransactionType.TRANSFER, to.toAddress(), + from.toAddress(), Amount.of(10, SEM), kernelRule.getKernel().getConfig().spec().minTransactionFee(), nonce, time, - Bytes.EMPTY_BYTES).sign(from); + Bytes.EMPTY_BYTES, + kernelRule.getKernel().getConfig().forkEd25519ContractEnabled()).sign(from); } } diff --git a/src/test/java/org/semux/core/BlockTest.java b/src/test/java/org/semux/core/BlockTest.java index 41a71fa2a..f9c497b6f 100644 --- a/src/test/java/org/semux/core/BlockTest.java +++ b/src/test/java/org/semux/core/BlockTest.java @@ -38,11 +38,18 @@ public class BlockTest { private long timestamp = TimeUtil.currentTimeMillis(); private byte[] data = Bytes.of("data"); - private Transaction tx = new Transaction(Network.DEVNET, TransactionType.TRANSFER, Bytes.random(20), ZERO, - config.spec().minTransactionFee(), - 1, TimeUtil.currentTimeMillis(), Bytes.EMPTY_BYTES).sign(new Key()); + private Transaction NewTx () + { + Key key = new Key(); + + return new Transaction(Network.DEVNET, TransactionType.TRANSFER, Bytes.random(20), key.toAddress(), ZERO, + config.spec().minTransactionFee(), + 1, TimeUtil.currentTimeMillis(), Bytes.EMPTY_BYTES, + config.forkEd25519ContractEnabled()).sign(key); + } + private TransactionResult res = new TransactionResult(); - private List transactions = Collections.singletonList(tx); + private List transactions = Collections.singletonList(NewTx()); private List results = Collections.singletonList(res); private int view = 1; private List votes = new ArrayList<>(); @@ -107,7 +114,7 @@ public void testTransactionIndexes() { Integer index = indexes.getRight().get(0); SimpleDecoder dec = new SimpleDecoder(block.getEncodedTransactions(), index); Transaction tx2 = Transaction.fromBytes(dec.readBytes()); - assertArrayEquals(tx.getHash(), tx2.getHash()); + assertArrayEquals(NewTx().getHash(), tx2.getHash()); } @Test @@ -119,7 +126,7 @@ public void testValidateTransactions() { Block block = new Block(header, transactions); assertTrue(block.validateHeader(header, previousHeader)); - assertTrue(block.validateTransactions(previousHeader, transactions, Network.DEVNET)); + assertTrue(block.validateTransactions(previousHeader, transactions, Network.DEVNET, config.forkEd25519ContractEnabled())); assertTrue(block.validateResults(previousHeader, results)); } @@ -133,7 +140,7 @@ public void testValidateTransactionsSparse() { assertTrue(block.validateHeader(header, previousHeader)); assertTrue(block.validateTransactions(previousHeader, Collections.singleton(transactions.get(0)), transactions, - Network.DEVNET)); + Network.DEVNET, config.forkEd25519ContractEnabled())); assertTrue(block.validateResults(previousHeader, results)); } } diff --git a/src/test/java/org/semux/core/BlockchainImplTest.java b/src/test/java/org/semux/core/BlockchainImplTest.java index 35e5eded2..aaf0717be 100644 --- a/src/test/java/org/semux/core/BlockchainImplTest.java +++ b/src/test/java/org/semux/core/BlockchainImplTest.java @@ -55,8 +55,12 @@ public class BlockchainImplTest { private long nonce = 12345; private byte[] data = Bytes.of("test"); private long timestamp = TimeUtil.currentTimeMillis() - 60 * 1000; - private Transaction tx = new Transaction(network, TransactionType.TRANSFER, to, value, fee, nonce, timestamp, - data).sign(key); + + private Transaction NewTx() + { + return new Transaction(network, TransactionType.TRANSFER, to, key.toAddress(), value, fee, nonce, timestamp, + data, chain.isForkActivated(Fork.ED25519_CONTRACT)).sign(key); + } @Before public void setUp() { @@ -135,6 +139,8 @@ public void testGetBlockHeader() { @Test public void testGetTransaction() { + Transaction tx = NewTx(); + assertNull(chain.getTransaction(tx.getHash())); Block newBlock = createBlock(1); @@ -152,6 +158,8 @@ public void testGetTransaction() { @Test public void testHasTransaction() { + Transaction tx = NewTx(); + assertFalse(chain.hasTransaction(tx.getHash())); Block newBlock = createBlock(1); @@ -162,6 +170,8 @@ public void testHasTransaction() { @Test public void testGetTransactionResult() { + Transaction tx = NewTx(); + assertNull(chain.getTransaction(tx.getHash())); Block newBlock = createBlock(1); @@ -173,6 +183,8 @@ public void testGetTransactionResult() { @Test public void testGetInternalTransaction() { + Transaction tx = NewTx(); + assertNull(chain.getTransaction(tx.getHash())); byte[] rootTxHash = Bytes.random(32); @@ -218,6 +230,8 @@ public void testGetInternalTransaction() { @Test public void testGetTransactionBlockNumber() { + Transaction tx = NewTx(); + Block newBlock = createBlock(1); chain.addBlock(newBlock); @@ -241,6 +255,8 @@ public void testGetCoinbaseTransactionBlockNumber() { @Test public void testGetTransactionCount() { + Transaction tx = NewTx(); + assertNull(chain.getTransaction(tx.getHash())); Block newBlock = createBlock(1); @@ -251,6 +267,8 @@ public void testGetTransactionCount() { @Test public void testGetAccountTransactions() { + Transaction tx = NewTx(); + assertNull(chain.getTransaction(tx.getHash())); Block newBlock = createBlock(1); @@ -264,7 +282,7 @@ public void testGetAccountTransactions() { @Test public void testSerialization() { Block block1 = createBlock(1); - + Block block2 = Block.fromComponents(block1.getEncodedHeader(), block1.getEncodedTransactions(), block1.getEncodedResults(), block1.getEncodedVotes()); @@ -278,6 +296,8 @@ public void testSerialization() { @Test public void testGetTransactions() { + Transaction tx = NewTx(); + Block block = createBlock(1); chain.addBlock(block); @@ -292,8 +312,8 @@ public void testGetTransactions() { @Test public void testGetTransactionsSelfTx() { - Transaction selfTx = new Transaction(network, TransactionType.TRANSFER, key.toAddress(), value, fee, nonce, - timestamp, data).sign(key); + Transaction selfTx = new Transaction(network, TransactionType.TRANSFER, key.toAddress(), key.toAddress(), value, fee, nonce, + timestamp, data, chain.isForkActivated(Fork.ED25519_CONTRACT)).sign(key); Block block = createBlock( 1, Collections.singletonList(selfTx), @@ -329,6 +349,8 @@ public void testValidatorStates() { @Test public void testForkActivated() { + Transaction tx = NewTx(); + final Fork fork = Fork.UNIFORM_DISTRIBUTION; for (long i = 1; i <= fork.blocksToCheck(); i++) { chain.addBlock( @@ -346,6 +368,8 @@ public void testForkActivated() { @Test public void testForkCompatibility() { + Transaction tx = NewTx(); + Fork fork = Fork.UNIFORM_DISTRIBUTION; Block block = createBlock(1, coinbase, new BlockHeaderData(ForkSignalSet.of(fork)).toBytes(), Collections.singletonList(tx), Collections.singletonList(res)); @@ -355,6 +379,8 @@ public void testForkCompatibility() { } private Block createBlock(long number) { + Transaction tx = NewTx(); + return createBlock(number, Collections.singletonList(tx), Collections.singletonList(res)); } diff --git a/src/test/java/org/semux/core/BlockchainImportTest.java b/src/test/java/org/semux/core/BlockchainImportTest.java index d505a9369..ebb5b6ca2 100644 --- a/src/test/java/org/semux/core/BlockchainImportTest.java +++ b/src/test/java/org/semux/core/BlockchainImportTest.java @@ -53,11 +53,13 @@ public void testDuplicatedTransaction() { kernelRule.getKernel().getConfig().network(), TransactionType.TRANSFER, to.toAddress(), + from1.toAddress(), Amount.of(10, SEM), kernelRule.getKernel().getConfig().spec().minTransactionFee(), 0, time, - Bytes.EMPTY_BYTES).sign(from1); + Bytes.EMPTY_BYTES, + kernelRule.getKernel().getConfig().forkEd25519ContractEnabled()).sign(from1); kernelRule.getKernel().setBlockchain(new BlockchainImpl(kernelRule.getKernel().getConfig(), temporaryDBRule)); kernelRule.getKernel().getBlockchain().getAccountState().adjustAvailable(from1.toAddress(), Amount.of( 1000, SEM)); @@ -72,11 +74,13 @@ public void testDuplicatedTransaction() { kernelRule.getKernel().getConfig().network(), TransactionType.TRANSFER, to.toAddress(), + from2.toAddress(), Amount.of(10, SEM), kernelRule.getKernel().getConfig().spec().minTransactionFee(), 0, time, - Bytes.EMPTY_BYTES).sign(from2); + Bytes.EMPTY_BYTES, + kernelRule.getKernel().getConfig().forkEd25519ContractEnabled()).sign(from2); Block block2 = kernelRule.createBlock(Collections.singletonList(tx2)); // this test case is valid if and only if tx1 and tx2 have the same tx hash diff --git a/src/test/java/org/semux/core/CorePerformanceTest.java b/src/test/java/org/semux/core/CorePerformanceTest.java index 9a6bfdcc6..4b06747f3 100644 --- a/src/test/java/org/semux/core/CorePerformanceTest.java +++ b/src/test/java/org/semux/core/CorePerformanceTest.java @@ -72,21 +72,21 @@ public void testTransactionProcessing() { long timestamp = TimeUtil.currentTimeMillis(); byte[] data = Bytes.random(16); - Transaction tx = new Transaction(Network.DEVNET, type, to, value, fee, nonce, timestamp, data); + Transaction tx = new Transaction(Network.DEVNET, type, to, key.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()); tx.sign(key); txs.add(tx); } long t1 = System.nanoTime(); for (Transaction tx : txs) { - assertTrue(tx.validate(Network.DEVNET)); + assertTrue(tx.validate_verify_sign(Network.DEVNET, config.forkEd25519ContractEnabled())); } long t2 = System.nanoTime(); logger.info("Perf_transaction_1: {} μs/tx", (t2 - t1) / 1_000 / repeat); Blockchain chain = new BlockchainImpl(config, temporaryDBFactory); TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), chain.isVMEnabled(), - chain.isVotingPrecompiledUpgraded()); + chain.isVotingPrecompiledUpgraded(), chain.isEd25519ContractEnabled()); t1 = System.nanoTime(); exec.execute(txs, chain.getAccountState().track(), chain.getDelegateState().track(), diff --git a/src/test/java/org/semux/core/PendingManagerTest.java b/src/test/java/org/semux/core/PendingManagerTest.java index e44619bad..4c73b604a 100644 --- a/src/test/java/org/semux/core/PendingManagerTest.java +++ b/src/test/java/org/semux/core/PendingManagerTest.java @@ -82,8 +82,9 @@ public void start() { public void testGetTransaction() throws InterruptedException { long now = TimeUtil.currentTimeMillis(); long nonce = accountState.getAccount(from).getNonce(); + boolean isFixTxHash = kernel.getConfig().forkEd25519ContractEnabled(); - Transaction tx = new Transaction(network, type, to, value, fee, nonce, now, Bytes.EMPTY_BYTES).sign(key); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, now, Bytes.EMPTY_BYTES, isFixTxHash).sign(key); pendingMgr.addTransaction(tx); Thread.sleep(100); @@ -94,10 +95,11 @@ public void testGetTransaction() throws InterruptedException { public void testAddTransaction() throws InterruptedException { long now = TimeUtil.currentTimeMillis(); long nonce = accountState.getAccount(from).getNonce(); + boolean isFixTxHash = kernel.getConfig().forkEd25519ContractEnabled(); - Transaction tx = new Transaction(network, type, to, value, fee, nonce, now, Bytes.EMPTY_BYTES).sign(key); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, now, Bytes.EMPTY_BYTES, isFixTxHash).sign(key); pendingMgr.addTransaction(tx); - Transaction tx2 = new Transaction(network, type, to, value, fee, nonce + 128, now, Bytes.EMPTY_BYTES) + Transaction tx2 = new Transaction(network, type, to, key.toAddress(), value, fee, nonce + 128, now, Bytes.EMPTY_BYTES, isFixTxHash) .sign(key); pendingMgr.addTransaction(tx2); @@ -107,7 +109,8 @@ public void testAddTransaction() throws InterruptedException { @Test public void testAddTransactionSyncErrorInvalidFormat() { - Transaction tx = new Transaction(network, type, to, value, fee, 0, 0, Bytes.EMPTY_BYTES).sign(key); + boolean isFixTxHash = kernel.getConfig().forkEd25519ContractEnabled(); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, 0, 0, Bytes.EMPTY_BYTES, isFixTxHash).sign(key); PendingManager.ProcessingResult result = pendingMgr.addTransactionSync(tx); assertEquals(0, pendingMgr.getPendingTransactions().size()); assertNotNull(result.error); @@ -116,8 +119,9 @@ public void testAddTransactionSyncErrorInvalidFormat() { @Test public void testAddTransactionSyncErrorDuplicatedHash() { - Transaction tx = new Transaction(network, type, to, value, fee, 0, TimeUtil.currentTimeMillis(), - Bytes.EMPTY_BYTES) + boolean isFixTxHash = kernel.getConfig().forkEd25519ContractEnabled(); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, 0, TimeUtil.currentTimeMillis(), + Bytes.EMPTY_BYTES, isFixTxHash) .sign(key); kernel.setBlockchain(spy(kernel.getBlockchain())); @@ -133,8 +137,9 @@ public void testAddTransactionSyncErrorDuplicatedHash() { @Test public void testAddTransactionSyncInvalidRecipient() { - Transaction tx = new Transaction(network, type, Constants.COINBASE_KEY.toAddress(), value, fee, 0, - TimeUtil.currentTimeMillis(), Bytes.EMPTY_BYTES) + boolean isFixTxHash = kernel.getConfig().forkEd25519ContractEnabled(); + Transaction tx = new Transaction(network, type, Constants.COINBASE_KEY.toAddress(), key.toAddress(), value, fee, 0, + TimeUtil.currentTimeMillis(), Bytes.EMPTY_BYTES, isFixTxHash) .sign(key); PendingManager.ProcessingResult result = pendingMgr.addTransactionSync(tx); @@ -145,18 +150,19 @@ public void testAddTransactionSyncInvalidRecipient() { @Test public void testNonceJump() throws InterruptedException { - long now = TimeUtil.currentTimeMillis(); + long now = TimeUtil.currentTimeMillis(); long nonce = accountState.getAccount(from).getNonce(); + boolean isFixTxHash = kernel.getConfig().forkEd25519ContractEnabled(); - Transaction tx3 = new Transaction(network, type, to, value, fee, nonce + 2, now, Bytes.EMPTY_BYTES).sign(key); + Transaction tx3 = new Transaction(network, type, to, key.toAddress(), value, fee, nonce + 2, now, Bytes.EMPTY_BYTES, isFixTxHash).sign(key); pendingMgr.addTransaction(tx3); - Transaction tx2 = new Transaction(network, type, to, value, fee, nonce + 1, now, Bytes.EMPTY_BYTES).sign(key); + Transaction tx2 = new Transaction(network, type, to, key.toAddress(), value, fee, nonce + 1, now, Bytes.EMPTY_BYTES, isFixTxHash).sign(key); pendingMgr.addTransaction(tx2); Thread.sleep(100); assertEquals(0, pendingMgr.getPendingTransactions().size()); - Transaction tx = new Transaction(network, type, to, value, fee, nonce, now, Bytes.EMPTY_BYTES).sign(key); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, now, Bytes.EMPTY_BYTES, isFixTxHash).sign(key); pendingMgr.addTransaction(tx); Thread.sleep(100); @@ -167,18 +173,19 @@ public void testNonceJump() throws InterruptedException { public void testNonceJumpTimestampError() throws InterruptedException { long now = TimeUtil.currentTimeMillis(); long nonce = accountState.getAccount(from).getNonce(); + boolean isFixTxHash = kernel.getConfig().forkEd25519ContractEnabled(); - Transaction tx3 = new Transaction(network, type, to, value, fee, nonce + 2, + Transaction tx3 = new Transaction(network, type, to, key.toAddress(), value, fee, nonce + 2, now - TimeUnit.HOURS.toMillis(2) + TimeUnit.SECONDS.toMillis(1), - Bytes.EMPTY_BYTES).sign(key); + Bytes.EMPTY_BYTES, isFixTxHash).sign(key); pendingMgr.addTransaction(tx3); - Transaction tx2 = new Transaction(network, type, to, value, fee, nonce + 1, now, Bytes.EMPTY_BYTES).sign(key); + Transaction tx2 = new Transaction(network, type, to, key.toAddress(), value, fee, nonce + 1, now, Bytes.EMPTY_BYTES, isFixTxHash).sign(key); pendingMgr.addTransaction(tx2); TimeUnit.SECONDS.sleep(1); assertEquals(0, pendingMgr.getPendingTransactions().size()); - Transaction tx = new Transaction(network, type, to, value, fee, nonce, now, Bytes.EMPTY_BYTES).sign(key); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, now, Bytes.EMPTY_BYTES, isFixTxHash).sign(key); pendingMgr.addTransaction(tx); TimeUnit.SECONDS.sleep(1); @@ -190,9 +197,10 @@ public void testNonceJumpTimestampError() throws InterruptedException { public void testTimestampError() { long now = TimeUtil.currentTimeMillis(); long nonce = accountState.getAccount(from).getNonce(); + boolean isFixTxHash = kernel.getConfig().forkEd25519ContractEnabled(); - Transaction tx3 = new Transaction(network, type, to, value, fee, nonce, now - ALLOWED_TIME_DRIFT - 1, - Bytes.EMPTY_BYTES).sign(key); + Transaction tx3 = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, now - ALLOWED_TIME_DRIFT - 1, + Bytes.EMPTY_BYTES, isFixTxHash).sign(key); PendingManager.ProcessingResult result = pendingMgr.addTransactionSync(tx3); assertEquals(INVALID_TIMESTAMP, result.error); } @@ -201,10 +209,11 @@ public void testTimestampError() { public void testHighVolumeTransaction() throws InterruptedException { long now = TimeUtil.currentTimeMillis(); long nonce = accountState.getAccount(from).getNonce(); + boolean isFixTxHash = kernel.getConfig().forkEd25519ContractEnabled(); int[] perm = ArrayUtil.permutation(5000); for (int p : perm) { - Transaction tx = new Transaction(network, type, to, value, fee, nonce + p, now, Bytes.EMPTY_BYTES) + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce + p, now, Bytes.EMPTY_BYTES, isFixTxHash) .sign(key); pendingMgr.addTransaction(tx); } @@ -216,10 +225,11 @@ public void testHighVolumeTransaction() throws InterruptedException { public void testNewBlock() throws InterruptedException { long now = TimeUtil.currentTimeMillis(); long nonce = accountState.getAccount(from).getNonce(); + boolean isFixTxHash = kernel.getConfig().forkEd25519ContractEnabled(); - Transaction tx = new Transaction(network, type, to, value, fee, nonce, now, Bytes.EMPTY_BYTES).sign(key); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, now, Bytes.EMPTY_BYTES, isFixTxHash).sign(key); pendingMgr.addTransaction(tx); - Transaction tx2 = new Transaction(network, type, to, value, fee, nonce + 1, now, Bytes.EMPTY_BYTES).sign(key); + Transaction tx2 = new Transaction(network, type, to, key.toAddress(), value, fee, nonce + 1, now, Bytes.EMPTY_BYTES, isFixTxHash).sign(key); // pendingMgr.addTransaction(tx3); Thread.sleep(100); @@ -242,7 +252,7 @@ public void testNewBlock() throws InterruptedException { kernel.getBlockchain().getAccountState().increaseNonce(from); pendingMgr.onBlockAdded(block); - Transaction tx3 = new Transaction(network, type, to, value, fee, nonce + 2, now, Bytes.EMPTY_BYTES).sign(key); + Transaction tx3 = new Transaction(network, type, to, key.toAddress(), value, fee, nonce + 2, now, Bytes.EMPTY_BYTES, isFixTxHash).sign(key); pendingMgr.addTransaction(tx3); Thread.sleep(100); diff --git a/src/test/java/org/semux/core/TransactionExecutorTest.java b/src/test/java/org/semux/core/TransactionExecutorTest.java index 33b0943b3..4d6afe313 100644 --- a/src/test/java/org/semux/core/TransactionExecutorTest.java +++ b/src/test/java/org/semux/core/TransactionExecutorTest.java @@ -52,7 +52,7 @@ public void prepare() { as = chain.getAccountState(); ds = chain.getDelegateState(); exec = new TransactionExecutor(config, new SemuxBlockStore(chain), chain.isVMEnabled(), - chain.isVotingPrecompiledUpgraded()); + chain.isVotingPrecompiledUpgraded(), chain.isEd25519ContractEnabled()); network = config.network(); block = new SemuxBlock(mock(BlockHeader.class), config.spec().maxBlockGasLimit()); } @@ -69,7 +69,7 @@ private TransactionResult executeAndCommit(TransactionExecutor exec, Transaction @Test public void testTransfer() { Key key = new Key(); - + TransactionType type = TransactionType.TRANSFER; byte[] from = key.toAddress(); byte[] to = Bytes.random(20); @@ -79,9 +79,9 @@ public void testTransfer() { long timestamp = TimeUtil.currentTimeMillis(); byte[] data = Bytes.random(16); - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()); tx.sign(key); - assertTrue(tx.validate(network)); + assertTrue(tx.validate_verify_sign(network, config.forkEd25519ContractEnabled())); // insufficient available TransactionResult result = exec.execute(tx, as.track(), ds.track(), block, 0); @@ -120,18 +120,21 @@ public void testDelegate() { byte[] data = Bytes.random(16); // register delegate (to != EMPTY_ADDRESS, random name) - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data).sign(delegate); + Transaction tx = new Transaction(network, type, to, delegate.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()) + .sign(delegate); TransactionResult result = exec.execute(tx, as.track(), ds.track(), block, 0); assertFalse(result.getCode().isSuccess()); // register delegate (to == EMPTY_ADDRESS, random name) - tx = new Transaction(network, type, Bytes.EMPTY_ADDRESS, value, fee, nonce, timestamp, data).sign(delegate); + tx = new Transaction(network, type, Bytes.EMPTY_ADDRESS, delegate.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()) + .sign(delegate); result = exec.execute(tx, as.track(), ds.track(), block, 0); assertFalse(result.getCode().isSuccess()); // register delegate (to == EMPTY_ADDRESS, normal name) and commit data = Bytes.of("test"); - tx = new Transaction(network, type, Bytes.EMPTY_ADDRESS, value, fee, nonce, timestamp, data).sign(delegate); + tx = new Transaction(network, type, Bytes.EMPTY_ADDRESS, delegate.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()) + .sign(delegate); result = executeAndCommit(exec, tx, as.track(), ds.track(), block); assertTrue(result.getCode().isSuccess()); @@ -159,7 +162,8 @@ public void testVote() { byte[] data = {}; // vote for non-existing delegate - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data).sign(voter); + Transaction tx = new Transaction(network, type, to, voter.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()) + .sign(voter); TransactionResult result = exec.execute(tx, as.track(), ds.track(), block, 0); assertFalse(result.getCode().isSuccess()); @@ -193,7 +197,8 @@ public void testUnvote() { byte[] data = {}; // unvote (never voted before) - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data).sign(voter); + Transaction tx = new Transaction(network, type, to, voter.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()) + .sign(voter); TransactionResult result = exec.execute(tx, as.track(), ds.track(), block, 0); assertFalse(result.getCode().isSuccess()); assertEquals(INSUFFICIENT_LOCKED, result.code); @@ -232,7 +237,8 @@ public void testUnvoteInsufficientFee() { byte[] data = {}; // unvote (never voted before) - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data).sign(voter); + Transaction tx = new Transaction(network, type, to, voter.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()) + .sign(voter); TransactionResult result = exec.execute(tx, as.track(), ds.track(), block, 0); assertFalse(result.getCode().isSuccess()); diff --git a/src/test/java/org/semux/core/TransactionTest.java b/src/test/java/org/semux/core/TransactionTest.java index cbb452266..24f340077 100644 --- a/src/test/java/org/semux/core/TransactionTest.java +++ b/src/test/java/org/semux/core/TransactionTest.java @@ -44,11 +44,11 @@ public class TransactionTest { @Test public void testNew() { - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()); assertNotNull(tx.getHash()); assertNull(tx.getSignature()); tx.sign(key); - assertTrue(tx.validate(network)); + assertTrue(tx.validate_verify_sign(network, config.forkEd25519ContractEnabled())); testFields(tx); } @@ -58,7 +58,7 @@ public void testNew() { */ @Test public void testSerialization() { - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, timestamp, data, config.forkEd25519ContractEnabled()); tx.sign(key); testFields(Transaction.fromBytes(tx.toBytes())); @@ -66,7 +66,7 @@ public void testSerialization() { @Test public void testTransactionSize() { - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, Bytes.random(128)) + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, timestamp, Bytes.random(128), config.forkEd25519ContractEnabled()) .sign(key); byte[] bytes = tx.toBytes(); @@ -86,9 +86,9 @@ private void testFields(Transaction tx) { @Test public void testEquality() { - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, Bytes.random(128)) + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, timestamp, Bytes.random(128), config.forkEd25519ContractEnabled()) .sign(key); - Transaction tx2 = new Transaction(network, type, to, value, fee, nonce, timestamp, tx.getData()) + Transaction tx2 = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, timestamp, tx.getData(), config.forkEd25519ContractEnabled()) .sign(key); assertEquals(tx, tx2); @@ -104,11 +104,13 @@ public void testEncoding() { network, type, to, + key.toAddress(), value, fee, nonce, timestamp, - data); + data, + config.forkEd25519ContractEnabled()); assertArrayEquals(encodedBytes, tx.getEncoded()); } @@ -118,7 +120,7 @@ public void testEncoding() { */ @Test public void testDecoding() { - Transaction tx = Transaction.fromEncoded(encodedBytes); + Transaction tx = Transaction.fromEncoded(encodedBytes, Bytes.random(20), config.forkEd25519ContractEnabled()); assertEquals(network.id(), tx.getNetworkId()); assertEquals(type, tx.getType()); diff --git a/src/test/java/org/semux/core/WalletVersionTest.java b/src/test/java/org/semux/core/WalletVersionTest.java index 8d13edb5d..edd08e4bf 100644 --- a/src/test/java/org/semux/core/WalletVersionTest.java +++ b/src/test/java/org/semux/core/WalletVersionTest.java @@ -49,7 +49,7 @@ public void testVersion1Wallet() throws IOException { } private void writeVersion1Wallet(List accounts, File file, String password) throws IOException { - byte[] key = Hash.h256(Bytes.of(password)); + byte[] key = Hash.h256_s(Bytes.of(password), null); // write a version 1 wallet SimpleEncoder enc = new SimpleEncoder(); diff --git a/src/test/java/org/semux/crypto/HashTest.java b/src/test/java/org/semux/crypto/HashTest.java index e5188bcba..86838e7df 100644 --- a/src/test/java/org/semux/crypto/HashTest.java +++ b/src/test/java/org/semux/crypto/HashTest.java @@ -24,7 +24,7 @@ public class HashTest { @Test public void testEmptyHash() { byte[] x = new byte[0]; - byte[] hash = Hash.h256(x); + byte[] hash = Hash.h256_s(x, null); logger.info("Hash of empty byte array = {}", Hex.encode(hash)); } @@ -32,7 +32,7 @@ public void testEmptyHash() { @Test public void testH256() { byte[] raw = Bytes.of(msg); - byte[] hash = Hash.h256(raw); + byte[] hash = Hash.h256_s(raw, null); assertEquals(msgBlake2b, Hex.encode(hash)); } @@ -41,7 +41,7 @@ public void testH256() { public void testH256Merge() { byte[] raw1 = Bytes.of(msg.substring(0, 1)); byte[] raw2 = Bytes.of(msg.substring(1)); - byte[] hash = Hash.h256(raw1, raw2); + byte[] hash = Hash.h256_s(raw1, raw2, null); assertEquals(msgBlake2b, Hex.encode(hash)); } diff --git a/src/test/java/org/semux/crypto/KeyTest.java b/src/test/java/org/semux/crypto/KeyTest.java index f8398565d..727ba5f80 100644 --- a/src/test/java/org/semux/crypto/KeyTest.java +++ b/src/test/java/org/semux/crypto/KeyTest.java @@ -51,7 +51,7 @@ public void testKeyStorage() { public void testMalleability() { Key key = new Key(); byte[] data = Bytes.of("test"); - byte[] hash = Hash.h256(data); + byte[] hash = Hash.h256_s(data, null); Signature sig = key.sign(hash); assertTrue(Key.verify(hash, sig)); @@ -93,7 +93,7 @@ public void testSignAndVerify() throws SignatureException { Key key = new Key(); byte[] data = Bytes.of("test"); - byte[] hash = Hash.h256(data); + byte[] hash = Hash.h256_s(data, null); byte[] sig = key.sign(hash).toBytes(); assertEquals(Signature.LENGTH, sig.length); @@ -116,7 +116,7 @@ public void testSignLargeData() throws SignatureException { @Test public void testInvalidSignature() throws SignatureException { byte[] data = Bytes.of("test"); - byte[] hash = Hash.h256(data); + byte[] hash = Hash.h256_s(data, null); assertFalse(Key.verify(hash, Bytes.random(20))); assertFalse(Key.verify(hash, Bytes.random(Signature.LENGTH))); @@ -128,7 +128,7 @@ public void testSignatureSize() { Key key = new Key(); byte[] data = Bytes.of("test"); - byte[] hash = Hash.h256(data); + byte[] hash = Hash.h256_s(data, null); byte[] sig = key.sign(hash).toBytes(); logger.info("signature size: {} B, {} GB per year", sig.length, diff --git a/src/test/java/org/semux/crypto/NativeTest.java b/src/test/java/org/semux/crypto/NativeTest.java index a6088f7a2..038f42ff0 100644 --- a/src/test/java/org/semux/crypto/NativeTest.java +++ b/src/test/java/org/semux/crypto/NativeTest.java @@ -54,12 +54,12 @@ public static void teardown() { @Test(expected = CryptoException.class) public void testH256Null() { - Native.h256(null); + Native.h256(null, null); } @Test public void testH256() { - assertArrayEquals(H256, Native.h256(MESSAGE)); + assertArrayEquals(H256, Native.h256(MESSAGE, null)); } @Test(expected = CryptoException.class) @@ -335,7 +335,7 @@ public void testVerifyBatch_large() { @Test public void testCompatibility() { - assertArrayEquals(Native.h256(MESSAGE), Hash.h256(MESSAGE)); + assertArrayEquals(Native.h256(MESSAGE, null), Hash.h256_s(MESSAGE, null)); assertArrayEquals(Native.h160(MESSAGE), Hash.h160(MESSAGE)); Key key = new Key(); @@ -354,13 +354,13 @@ public void benchmarkH256() { // warm up for (int i = 0; i < repeat / 10; i++) { - Hash.h256(data); + Hash.h256_s(data, null); } // native Instant start = Instant.now(); for (int i = 0; i < repeat; i++) { - Native.h256(data); + Native.h256(data, null); } Instant end = Instant.now(); logger.debug("H256 Native: " + Duration.between(start, end).toMillis() + "ms"); @@ -368,12 +368,12 @@ public void benchmarkH256() { // java (JIT) start = Instant.now(); for (int i = 0; i < repeat; i++) { - Hash.h256(data); + Hash.h256_s(data, null); } end = Instant.now(); logger.debug("H256 Java: " + Duration.between(start, end).toMillis() + "ms"); - assertArrayEquals(Hash.h256(data), Native.h256(data)); + assertArrayEquals(Hash.h256_s(data, null), Native.h256(data, null)); } @Test @@ -402,7 +402,7 @@ public void benchmarkH160() { end = Instant.now(); logger.debug("H160 Java: " + Duration.between(start, end).toMillis() + "ms"); - assertArrayEquals(Hash.h256(data), Native.h256(data)); + assertArrayEquals(Hash.h256_s(data, null), Native.h256(data, null)); } @Test diff --git a/src/test/java/org/semux/gui/dialog/TransactionDialogTest.java b/src/test/java/org/semux/gui/dialog/TransactionDialogTest.java index a5ff5ee40..7cb813f67 100644 --- a/src/test/java/org/semux/gui/dialog/TransactionDialogTest.java +++ b/src/test/java/org/semux/gui/dialog/TransactionDialogTest.java @@ -21,6 +21,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.semux.Kernel; import org.semux.core.Amount; import org.semux.core.Transaction; import org.semux.crypto.Hex; @@ -40,7 +41,8 @@ public class TransactionDialogTest extends AssertJSwingJUnitTestCase { @Test public void testDisplayTransferTransaction() { - kernelRule1.getKernel().start(); + Kernel kernel = kernelRule1.getKernel(); + kernel.start(); Key from = new Key(); Key to = new Key(); @@ -49,8 +51,8 @@ public void testDisplayTransferTransaction() { long nonce = 0L; long now = Instant.now().toEpochMilli(); byte[] data = "some data".getBytes(); - Transaction tx = new Transaction(kernelRule1.getKernel().getConfig().network(), TRANSFER, to.toAddress(), value, - fee, nonce, now, data).sign(from); + Transaction tx = new Transaction(kernel.getConfig().network(), TRANSFER, to.toAddress(), + from.toAddress(), value, fee, nonce, now, data, kernel.getConfig().forkEd25519ContractEnabled()).sign(from); TransactionDialogTestApplication application = GuiActionRunner .execute(() -> new TransactionDialogTestApplication(walletModel, kernelRule1.getKernel(), tx)); diff --git a/src/test/java/org/semux/gui/dialog/TransactionDialogTestApplication.java b/src/test/java/org/semux/gui/dialog/TransactionDialogTestApplication.java index f4a0c8dc4..cba196a27 100644 --- a/src/test/java/org/semux/gui/dialog/TransactionDialogTestApplication.java +++ b/src/test/java/org/semux/gui/dialog/TransactionDialogTestApplication.java @@ -8,7 +8,6 @@ import org.semux.KernelMock; import org.semux.core.Transaction; -import org.semux.core.TransactionResult; import org.semux.gui.BaseTestApplication; import org.semux.gui.SemuxGui; import org.semux.gui.model.WalletModel; @@ -25,7 +24,7 @@ public class TransactionDialogTestApplication extends BaseTestApplication { Transaction tx) { super(); gui = new SemuxGui(walletModel, kernelMock); - TransactionResult result = new TransactionResult(TransactionResult.Code.SUCCESS); + //TransactionResult result = new TransactionResult(TransactionResult.Code.SUCCESS); transactionDialog = new TransactionDialog(this, tx, gui.getKernel()); transactionDialog.setVisible(true); } diff --git a/src/test/java/org/semux/gui/dialog/TransactionResultDialogTest.java b/src/test/java/org/semux/gui/dialog/TransactionResultDialogTest.java index e7f9df71d..797aa5b60 100644 --- a/src/test/java/org/semux/gui/dialog/TransactionResultDialogTest.java +++ b/src/test/java/org/semux/gui/dialog/TransactionResultDialogTest.java @@ -23,6 +23,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; +import org.semux.Kernel; import org.semux.core.Amount; import org.semux.core.Transaction; import org.semux.core.TransactionResult; @@ -42,7 +43,8 @@ public class TransactionResultDialogTest extends AssertJSwingJUnitTestCase { @Test public void testTransactionResult() { - kernelRule1.getKernel().start(); + Kernel kernel = kernelRule1.getKernel(); + kernel.start(); Key from = new Key(); Key to = new Key(); @@ -53,8 +55,8 @@ public void testTransactionResult() { byte[] data = "some data".getBytes(); long gas = 10_000; Amount gasPrice = Amount.of(10); - Transaction tx = new Transaction(kernelRule1.getKernel().getConfig().network(), CREATE, to.toAddress(), value, - fee, nonce, now, data, gas, gasPrice).sign(from); + Transaction tx = new Transaction(kernel.getConfig().network(), CREATE, to.toAddress(), from.toAddress(), + value, fee, nonce, now, data, gas, gasPrice, kernel.getConfig().forkEd25519ContractEnabled()).sign(from); TransactionResult result = new TransactionResult(); result.setCode(TransactionResult.Code.FAILURE); diff --git a/src/test/java/org/semux/gui/panel/TransactionsPanelTest.java b/src/test/java/org/semux/gui/panel/TransactionsPanelTest.java index 88e12f7e8..b5d0ba48a 100644 --- a/src/test/java/org/semux/gui/panel/TransactionsPanelTest.java +++ b/src/test/java/org/semux/gui/panel/TransactionsPanelTest.java @@ -59,19 +59,25 @@ protected void onSetUp() { } @Test - public void testTransactions() { + public void testTransactions() + { + KernelMock kernel = kernelRule.getKernel(); + kernel.start(); + Key key = new Key(); Amount $1 = Amount.of(1); WalletAccount acc = spy(new WalletAccount(key, new Account(key.toAddress(), $1, $1, 1), null)); - Transaction tx = new Transaction(kernelRule.getKernel().getConfig().network(), + Transaction tx = new Transaction(kernel.getConfig().network(), TransactionType.TRANSFER, Bytes.random(Key.ADDRESS_LEN), + key.toAddress(), Amount.of(1, SEM), Amount.of(10, MILLI_SEM), 0, TimeUtil.currentTimeMillis(), - Bytes.EMPTY_BYTES); + Bytes.EMPTY_BYTES, + kernel.getConfig().forkEd25519ContractEnabled()); tx.sign(new Key()); acc.setTransactions(Collections.singletonList(tx)); @@ -79,7 +85,7 @@ public void testTransactions() { when(walletModel.getAccounts()).thenReturn(Collections.singletonList(acc)); // mock kernel - KernelMock kernelMock = spy(kernelRule.getKernel()); + KernelMock kernelMock = spy(kernel); Blockchain chain = mock(Blockchain.class); DelegateState ds = mock(DelegateState.class); PendingManager pendingManager = mock(PendingManager.class); diff --git a/src/test/java/org/semux/integration/SyncingTest.java b/src/test/java/org/semux/integration/SyncingTest.java index 756eb0da0..289ae0f93 100644 --- a/src/test/java/org/semux/integration/SyncingTest.java +++ b/src/test/java/org/semux/integration/SyncingTest.java @@ -141,7 +141,7 @@ public void testSync() { Block previousBlock = kernel4.getBlockchain().getBlock(i - 1); assertTrue(block.validateHeader(block.getHeader(), previousBlock.getHeader())); assertTrue(block.validateTransactions(previousBlock.getHeader(), block.getTransactions(), - kernel4.getConfig().network())); + kernel4.getConfig().network(), kernel4.getConfig().forkEd25519ContractEnabled())); assertTrue(block.validateResults(previousBlock.getHeader(), block.getResults())); assertTrue(block.getVotes().size() >= 3 * 2 / 3); diff --git a/src/test/java/org/semux/integration/UniformDistForkSyncingTest.java b/src/test/java/org/semux/integration/UniformDistForkSyncingTest.java index b0c42c6f3..a05b4954e 100644 --- a/src/test/java/org/semux/integration/UniformDistForkSyncingTest.java +++ b/src/test/java/org/semux/integration/UniformDistForkSyncingTest.java @@ -6,9 +6,6 @@ */ package org.semux.integration; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - import org.junit.experimental.categories.Category; import org.semux.IntegrationTest; import org.semux.TestUtils; diff --git a/src/test/java/org/semux/net/msg/p2p/TransactionMessageTest.java b/src/test/java/org/semux/net/msg/p2p/TransactionMessageTest.java index 4ee5985f8..5ab2e3ae3 100644 --- a/src/test/java/org/semux/net/msg/p2p/TransactionMessageTest.java +++ b/src/test/java/org/semux/net/msg/p2p/TransactionMessageTest.java @@ -29,9 +29,11 @@ public void testSerialization() { long nonce = 1; long timestamp = TimeUtil.currentTimeMillis(); byte[] data = Bytes.of("data"); + + Key key = new Key(); - Transaction tx = new Transaction(network, type, to, value, fee, nonce, timestamp, data); - tx.sign(new Key()); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, fee, nonce, timestamp, data, true); + tx.sign(key); TransactionMessage msg = new TransactionMessage(tx); TransactionMessage msg2 = new TransactionMessage(msg.getBody()); diff --git a/src/test/java/org/semux/util/MerkleTreeTest.java b/src/test/java/org/semux/util/MerkleTreeTest.java index 73da6db17..550ae7b99 100644 --- a/src/test/java/org/semux/util/MerkleTreeTest.java +++ b/src/test/java/org/semux/util/MerkleTreeTest.java @@ -47,7 +47,7 @@ public void testOneElement() { @Test public void testTwoElements() { - byte[] hash12 = Hash.h256(hash1, hash2); + byte[] hash12 = Hash.h256_s(hash1, hash2, null); MerkleTree tree = new MerkleTree(Arrays.asList(hash1, hash2)); assertEquals(2, tree.size()); @@ -61,9 +61,9 @@ public void testTwoElements() { @Test public void testThreeElements() { - byte[] hash12 = Hash.h256(hash1, hash2); + byte[] hash12 = Hash.h256_s(hash1, hash2, null); byte[] hash33 = hash3; - byte[] hash1233 = Hash.h256(hash12, hash33); + byte[] hash1233 = Hash.h256_s(hash12, hash33, null); MerkleTree tree = new MerkleTree(Arrays.asList(hash1, hash2, hash3)); assertEquals(3, tree.size()); diff --git a/src/test/java/org/semux/util/MerkleUtilTest.java b/src/test/java/org/semux/util/MerkleUtilTest.java index 5df9e8623..5b75ab30b 100644 --- a/src/test/java/org/semux/util/MerkleUtilTest.java +++ b/src/test/java/org/semux/util/MerkleUtilTest.java @@ -33,8 +33,12 @@ public void testComputeTransactionsRoot() { long nonce = 1; long timestamp = TimeUtil.currentTimeMillis(); byte[] data = Bytes.random(128); - Transaction tx1 = new Transaction(network, type, to, value, fee, nonce, timestamp, data).sign(new Key()); - Transaction tx2 = new Transaction(network, type, to, value, fee, nonce, timestamp, data).sign(new Key()); + + Key key1 = new Key(); + Key key2 = new Key(); + + Transaction tx1 = new Transaction(network, type, to, key1.toAddress(), value, fee, nonce, timestamp, data, true).sign(key1); + Transaction tx2 = new Transaction(network, type, to, key2.toAddress(), value, fee, nonce, timestamp, data, true).sign(key2); byte[] b1 = tx1.getHash(); byte[] b2 = tx2.getHash(); byte[] root = new MerkleTree(Arrays.asList(b1, b2)).getRootHash(); @@ -51,8 +55,8 @@ public void testComputeResultsRoot() { res1.setReturnData(Bytes.random(20)); res2.setReturnData(Bytes.random(20)); - byte[] b1 = Hash.h256(res1.toBytesForMerkle()); - byte[] b2 = Hash.h256(res2.toBytesForMerkle()); + byte[] b1 = Hash.h256_s(res1.toBytesForMerkle(), null); + byte[] b2 = Hash.h256_s(res2.toBytesForMerkle(), null); byte[] root = new MerkleTree(Arrays.asList(b1, b2)).getRootHash(); byte[] merkle = MerkleUtil.computeResultsRoot(Arrays.asList(res1, res2)); diff --git a/src/test/java/org/semux/vm/client/InternalTransactionTest.java b/src/test/java/org/semux/vm/client/InternalTransactionTest.java index 6636bf10f..bfedbe892 100644 --- a/src/test/java/org/semux/vm/client/InternalTransactionTest.java +++ b/src/test/java/org/semux/vm/client/InternalTransactionTest.java @@ -69,7 +69,8 @@ public void prepare() { // } @Test public void testInternalTransfer() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key key = new Key(); TransactionType type = TransactionType.CALL; @@ -93,8 +94,8 @@ public void testInternalTransfer() { long gas = 100000; Amount gasPrice = Amount.of(1); - Transaction tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, contract, gas, - gasPrice); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, Amount.ZERO, nonce, timestamp, contract, gas, + gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); TransactionResult result = exec.execute(tx, as, ds, bh, 0); diff --git a/src/test/java/org/semux/vm/client/PrecompiledContractTest.java b/src/test/java/org/semux/vm/client/PrecompiledContractTest.java index c640109f2..cdece932c 100644 --- a/src/test/java/org/semux/vm/client/PrecompiledContractTest.java +++ b/src/test/java/org/semux/vm/client/PrecompiledContractTest.java @@ -6,9 +6,7 @@ */ package org.semux.vm.client; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.*; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; @@ -16,6 +14,11 @@ import static org.semux.core.Amount.ZERO; import static org.semux.core.Unit.SEM; +import java.util.Random; + +import org.hamcrest.core.IsEqual; +import org.hamcrest.core.IsNot; +import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -80,7 +83,8 @@ public void prepare() { @Test public void testSuccess() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key key = new Key(); byte[] delegate = Bytes.random(20); @@ -96,7 +100,7 @@ public void testSuccess() { long gas = 100000; Amount gasPrice = Amount.of(1); - Transaction tx = new Transaction(network, type, to, value, ZERO, nonce, timestamp, data, gas, gasPrice); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); SemuxBlock block = new SemuxBlock( @@ -128,7 +132,7 @@ public void testSuccess() { Hex.decode("000000000000000000000000"), delegate, Hex.decode("000000000000000000000000000000000000000000000000000000003B9ACA00")); // 1 nanoSEM - tx = new Transaction(network, type, to, value, ZERO, nonce + 1, timestamp, data, gas, gasPrice); + tx = new Transaction(network, type, to, key.toAddress(), value, ZERO, nonce + 1, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); result = exec.execute(tx, as, ds, block, 0); @@ -145,7 +149,8 @@ public void testSuccess() { // it would fail because the contract doesn't have balance. @Test public void testFailure1() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key key = new Key(); byte[] delegate = Bytes.random(20); @@ -161,7 +166,7 @@ public void testFailure1() { long gas = 100000; Amount gasPrice = Amount.of(1); - Transaction tx = new Transaction(network, type, to, value, ZERO, nonce, timestamp, data, gas, gasPrice); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); SemuxBlock block = new SemuxBlock( @@ -181,7 +186,8 @@ public void testFailure1() { // it would fail because the sender doesn't have enough balance. @Test public void testFailure2() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key key = new Key(); TransactionType type = TransactionType.CALL; @@ -197,7 +203,7 @@ public void testFailure2() { long gas = 100000; Amount gasPrice = Amount.of(1); - Transaction tx = new Transaction(network, type, to, value, ZERO, nonce, timestamp, data, gas, gasPrice); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); SemuxBlock block = new SemuxBlock( @@ -211,4 +217,186 @@ public void testFailure2() { TransactionResult result = exec.execute(tx, as, ds, block, 0); assertFalse(result.getCode().isSuccess()); } + + @Test + public void testEd25519Vfy() { + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); + Key key = new Key(); + + byte[] message = new byte[32]; + new Random().nextBytes(message); + + Key signingKey = new Key(); + Key.Signature sig = signingKey.sign(message); + byte[] signature = sig.getS(); + byte[] publicKey = sig.getA(); + + // our signatures are (S,A), eth spec is (A,S) + TransactionType type = TransactionType.CALL; + byte[] from = key.toAddress(); + byte[] to = Hex.decode0x("0x0000000000000000000000000000000000000009"); + byte[] delegate = Bytes.random(20); + Amount value = Amount.of(0); + + long nonce = as.getAccount(from).getNonce(); + long timestamp = TimeUtil.currentTimeMillis(); + byte[] data = Bytes.merge(message, publicKey, signature); + + long gas = 100000; + Amount gasPrice = Amount.of(1); + + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); + tx.sign(key); + + SemuxBlock block = new SemuxBlock( + new BlockHeader(123, Bytes.random(20), Bytes.random(20), TimeUtil.currentTimeMillis(), + Bytes.random(20), Bytes.random(20), Bytes.random(20), Bytes.random(20)), + config.spec().maxBlockGasLimit()); + as.adjustAvailable(from, Amount.of(1000, SEM)); + as.adjustAvailable(to, Amount.of(1000, SEM)); + ds.register(delegate, "abc".getBytes()); + + TransactionResult result = exec.execute(tx, as, ds, block, 0); + assertTrue(result.getCode().isSuccess()); + assertArrayEquals(new byte[0], result.getReturnData()); + + // check if message is tampered + nonce = as.getAccount(from).getNonce(); + timestamp = TimeUtil.currentTimeMillis(); + message[0] = (byte) ((int) message[0] + 1 % 8); + data = Bytes.merge(message, publicKey, signature); + + tx = new Transaction(network, type, to, key.toAddress(), value, ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); + tx.sign(key); + + block = new SemuxBlock( + new BlockHeader(123, Bytes.random(20), Bytes.random(20), TimeUtil.currentTimeMillis(), + Bytes.random(20), Bytes.random(20), Bytes.random(20), Bytes.random(20)), + config.spec().maxBlockGasLimit()); + as.adjustAvailable(from, Amount.of(1000, SEM)); + as.adjustAvailable(to, Amount.of(1000, SEM)); + ds.register(delegate, "abc".getBytes()); + + result = exec.execute(tx, as, ds, block, 0); + + // call is still a success, but data is not empty + assertTrue(result.getCode().isSuccess()); + Assert.assertThat(new byte[0], IsNot.not(IsEqual.equalTo(result.getReturnData()))); + + // check that invalid set of data is failure + nonce = as.getAccount(from).getNonce(); + timestamp = TimeUtil.currentTimeMillis(); + message[0] = (byte) ((int) message[0] + 1 % 8); + data = Bytes.merge(message, publicKey); // no signature + + tx = new Transaction(network, type, to, key.toAddress(), value, ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); + tx.sign(key); + + block = new SemuxBlock( + new BlockHeader(123, Bytes.random(20), Bytes.random(20), TimeUtil.currentTimeMillis(), + Bytes.random(20), Bytes.random(20), Bytes.random(20), Bytes.random(20)), + config.spec().maxBlockGasLimit()); + as.adjustAvailable(from, Amount.of(1000, SEM)); + as.adjustAvailable(to, Amount.of(1000, SEM)); + ds.register(delegate, "abc".getBytes()); + + result = exec.execute(tx, as, ds, block, 0); + + // call is still a success, but data is not empty + assertFalse(result.getCode().isSuccess()); + assertArrayEquals(new byte[0], result.getReturnData()); + } + + @Test + public void testEd25519Vfy_Prefork() { + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + false); + Key key = new Key(); + + byte[] message = new byte[32]; + new Random().nextBytes(message); + + Key signingKey = new Key(); + Key.Signature sig = signingKey.sign(message); + byte[] signature = sig.getS(); + byte[] publicKey = sig.getA(); + + // our signatures are (S,A), eth spec is (A,S) + TransactionType type = TransactionType.CALL; + byte[] from = key.toAddress(); + byte[] to = Hex.decode0x("0x0000000000000000000000000000000000000009"); + byte[] delegate = Bytes.random(20); + Amount value = Amount.of(0); + + long nonce = as.getAccount(from).getNonce(); + long timestamp = TimeUtil.currentTimeMillis(); + byte[] data = Bytes.merge(message, publicKey, signature); + + long gas = 100000; + Amount gasPrice = Amount.of(1); + + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); + tx.sign(key); + + SemuxBlock block = new SemuxBlock( + new BlockHeader(123, Bytes.random(20), Bytes.random(20), TimeUtil.currentTimeMillis(), + Bytes.random(20), Bytes.random(20), Bytes.random(20), Bytes.random(20)), + config.spec().maxBlockGasLimit()); + as.adjustAvailable(from, Amount.of(1000, SEM)); + as.adjustAvailable(to, Amount.of(1000, SEM)); + ds.register(delegate, "abc".getBytes()); + + TransactionResult result = exec.execute(tx, as, ds, block, 0); + // calls to nonimplemented precompiled contracts just return success/empty + assertTrue(result.getCode().isSuccess()); + assertArrayEquals(new byte[0], result.getReturnData()); + + // check if message is tampered + nonce = as.getAccount(from).getNonce(); + timestamp = TimeUtil.currentTimeMillis(); + message[0] = (byte) ((int) message[0] + 1 % 8); + data = Bytes.merge(message, publicKey, signature); + + tx = new Transaction(network, type, to, key.toAddress(), value, ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); + tx.sign(key); + + block = new SemuxBlock( + new BlockHeader(123, Bytes.random(20), Bytes.random(20), TimeUtil.currentTimeMillis(), + Bytes.random(20), Bytes.random(20), Bytes.random(20), Bytes.random(20)), + config.spec().maxBlockGasLimit()); + as.adjustAvailable(from, Amount.of(1000, SEM)); + as.adjustAvailable(to, Amount.of(1000, SEM)); + ds.register(delegate, "abc".getBytes()); + + result = exec.execute(tx, as, ds, block, 0); + // calls to nonimplemented precompiled contracts just return success/empty + assertTrue(result.getCode().isSuccess()); + assertArrayEquals(new byte[0], result.getReturnData()); + + // check that invalid set of data is not a failure (since it should default to + // default calling of non-address + nonce = as.getAccount(from).getNonce(); + timestamp = TimeUtil.currentTimeMillis(); + message[0] = (byte) ((int) message[0] + 1 % 8); + data = Bytes.merge(message, publicKey); // no signature + + tx = new Transaction(network, type, to, key.toAddress(), value, ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); + tx.sign(key); + + block = new SemuxBlock( + new BlockHeader(123, Bytes.random(20), Bytes.random(20), TimeUtil.currentTimeMillis(), + Bytes.random(20), Bytes.random(20), Bytes.random(20), Bytes.random(20)), + config.spec().maxBlockGasLimit()); + as.adjustAvailable(from, Amount.of(1000, SEM)); + as.adjustAvailable(to, Amount.of(1000, SEM)); + ds.register(delegate, "abc".getBytes()); + + result = exec.execute(tx, as, ds, block, 0); + + // call is still a success, but data is not empty + assertTrue(result.getCode().isSuccess()); + assertArrayEquals(new byte[0], result.getReturnData()); + + } } diff --git a/src/test/java/org/semux/vm/client/VmTransactionTest.java b/src/test/java/org/semux/vm/client/VmTransactionTest.java index e706ea3a1..cf2d65b46 100644 --- a/src/test/java/org/semux/vm/client/VmTransactionTest.java +++ b/src/test/java/org/semux/vm/client/VmTransactionTest.java @@ -77,7 +77,8 @@ public void prepare() { */ @Test public void testCall() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key key = new Key(); TransactionType type = TransactionType.CALL; @@ -98,9 +99,9 @@ public void testCall() { long gas = 30000; Amount gasPrice = Amount.of(1); - Transaction tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); - assertTrue(tx.validate(network)); + assertTrue(tx.validate_verify_sign(network, config.forkEd25519ContractEnabled())); // insufficient available TransactionResult result = exec.execute(tx, as.track(), ds.track(), block, 0); @@ -128,7 +129,8 @@ public void testCall() { */ @Test public void testCreate() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key key = new Key(); TransactionType type = TransactionType.CREATE; @@ -146,10 +148,10 @@ public void testCreate() { long gas = 1000000; Amount gasPrice = Amount.of(1); - Transaction tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, create, gas, - gasPrice); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, Amount.ZERO, nonce, timestamp, create, gas, + gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); - assertTrue(tx.validate(network)); + assertTrue(tx.validate_verify_sign(network, config.forkEd25519ContractEnabled())); // insufficient available TransactionResult result = exec.execute(tx, as.track(), ds.track(), block, 0); @@ -190,7 +192,8 @@ public void testCreate() { // } @Test public void testCreateAndCall() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key key = new Key(); TransactionType type = TransactionType.CREATE; @@ -210,9 +213,9 @@ public void testCreateAndCall() { Amount available = Amount.of(1000, SEM); as.adjustAvailable(key.toAddress(), available); - Transaction tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); - assertTrue(tx.validate(network)); + assertTrue(tx.validate_verify_sign(network, config.forkEd25519ContractEnabled())); TransactionResult result = exec.execute(tx, as, ds, block, 0); assertTrue(result.getCode().isSuccess()); @@ -223,9 +226,9 @@ public void testCreateAndCall() { to = newContractAddress; nonce += 1; data = Hex.decode0x("0x60fe47b10000000000000000000000000000000000000000000000000000000000000009"); - tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice); + tx = new Transaction(network, type, to, key.toAddress(), value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); - assertTrue(tx.validate(network)); + assertTrue(tx.validate_verify_sign(network, config.forkEd25519ContractEnabled())); result = exec.execute(tx, as, ds, block, 0); assertTrue(result.getCode().isSuccess()); @@ -241,7 +244,8 @@ public void testCreateAndCall() { // } @Test public void testInternalTransferNotEnoughGas() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key key = new Key(); TransactionType type = TransactionType.CREATE; @@ -261,9 +265,9 @@ public void testInternalTransferNotEnoughGas() { Amount available = Amount.of(1000, SEM); as.adjustAvailable(key.toAddress(), available); - Transaction tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); - assertTrue(tx.validate(network)); + assertTrue(tx.validate_verify_sign(network, config.forkEd25519ContractEnabled())); TransactionResult result = exec.execute(tx, as, ds, block, 0); assertFalse(result.getCode().isSuccess()); @@ -271,7 +275,8 @@ public void testInternalTransferNotEnoughGas() { @Test public void testInternalTransfer() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key key = new Key(); TransactionType type = TransactionType.CREATE; @@ -291,9 +296,9 @@ public void testInternalTransfer() { Amount available = Amount.of(1000, SEM); as.adjustAvailable(key.toAddress(), available); - Transaction tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); - assertTrue(tx.validate(network)); + assertTrue(tx.validate_verify_sign(network, config.forkEd25519ContractEnabled())); TransactionResult result = exec.execute(tx, as, ds, block, 0); assertTrue(result.getCode().isSuccess()); @@ -305,9 +310,9 @@ public void testInternalTransfer() { nonce += 1; data = Hex.decode0x("0x3e58c58c000000000000000000000000791f1c3f06b19f1b3a4c7774675df9933a091d10"); value = Amount.of(1, SEM); - tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice); + tx = new Transaction(network, type, to, key.toAddress(), value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); - assertTrue(tx.validate(network)); + assertTrue(tx.validate_verify_sign(network, config.forkEd25519ContractEnabled())); assertEquals(ZERO, as.getAccount(newContractAddress).getAvailable()); assertEquals(ZERO, as.getAccount(Hex.decode0x("791f1c3f06b19f1b3a4c7774675df9933a091d10")).getAvailable()); @@ -324,7 +329,8 @@ public void testInternalTransfer() { @Test public void testTransferToContract() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key key = new Key(); TransactionType type = TransactionType.CALL; @@ -341,8 +347,8 @@ public void testTransferToContract() { long gas = 100000; Amount gasPrice = Amount.of(1); - Transaction tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, contract, gas, - gasPrice); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, Amount.ZERO, nonce, timestamp, contract, gas, + gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); TransactionResult result = exec.execute(tx, as, ds, block, 0); @@ -359,7 +365,8 @@ public void testTransferToContract() { @Test public void testTransferToContractOutOfGas() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key key = new Key(); TransactionType type = TransactionType.CALL; @@ -376,8 +383,8 @@ public void testTransferToContractOutOfGas() { long gas = 21073; Amount gasPrice = Amount.of(1); - Transaction tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, contract, gas, - gasPrice); + Transaction tx = new Transaction(network, type, to, key.toAddress(), value, Amount.ZERO, nonce, timestamp, contract, gas, + gasPrice, config.forkEd25519ContractEnabled()); tx.sign(key); TransactionResult result = exec.execute(tx, as, ds, block, 0); @@ -394,7 +401,8 @@ public void testTransferToContractOutOfGas() { // tx: 0x31d6c6c1c5e82b286b8179f4368543fb4595beb57ee1fd2a01dbbb22f6cca9f1 @Test public void testCallFailureRevertBeforeFork() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, false); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, false, + true); Key sender = new Key(); TransactionType type = TransactionType.CREATE; @@ -406,7 +414,7 @@ public void testCallFailureRevertBeforeFork() { "0x608060405234801561001057600080fd5b50610165806100206000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bc5de3014610046575b600080fd5b34801561005257600080fd5b5061005b6100d6565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561009b578082015181840152602081019050610080565b50505050905090810190601f1680156100c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60608060405190810160405280602281526020017f466972737420636f6e7472616374212053656d757820746f20746865204d6f6f81526020017f6e210000000000000000000000000000000000000000000000000000000000008152509050905600a165627a7a72305820934582d75405e634939862f4188ebbb6c2765362add401961e8f44aa91b91f040029"); long gas = 1000000; Amount gasPrice = Amount.of(1); - Transaction tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice) + Transaction tx = new Transaction(network, type, to, sender.toAddress(), value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()) .sign(sender); // credit the sender some balance @@ -424,7 +432,8 @@ public void testCallFailureRevertBeforeFork() { nonce = as.getAccount(sender.toAddress()).getNonce(); data = Hex.decode0x("0x3bc5de30"); value = Amount.of(1, SEM); - tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice).sign(sender); + tx = new Transaction(network, type, to, sender.toAddress(), value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()) + .sign(sender); // call the contract result = exec.execute(tx, as, ds, block, 0); @@ -438,7 +447,8 @@ public void testCallFailureRevertBeforeFork() { @Test public void testCallFailureRevertAfterFork() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key sender = new Key(); TransactionType type = TransactionType.CREATE; @@ -450,7 +460,7 @@ public void testCallFailureRevertAfterFork() { "0x608060405234801561001057600080fd5b50610165806100206000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bc5de3014610046575b600080fd5b34801561005257600080fd5b5061005b6100d6565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561009b578082015181840152602081019050610080565b50505050905090810190601f1680156100c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60608060405190810160405280602281526020017f466972737420636f6e7472616374212053656d757820746f20746865204d6f6f81526020017f6e210000000000000000000000000000000000000000000000000000000000008152509050905600a165627a7a72305820934582d75405e634939862f4188ebbb6c2765362add401961e8f44aa91b91f040029"); long gas = 1000000; Amount gasPrice = Amount.of(1); - Transaction tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice) + Transaction tx = new Transaction(network, type, to, sender.toAddress(), value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()) .sign(sender); // credit the sender some balance @@ -468,7 +478,8 @@ public void testCallFailureRevertAfterFork() { nonce = as.getAccount(sender.toAddress()).getNonce(); data = Hex.decode0x("0x3bc5de30"); value = Amount.of(1, SEM); - tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice).sign(sender); + tx = new Transaction(network, type, to, sender.toAddress(), value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()) + .sign(sender); // call the contract result = exec.execute(tx, as, ds, block, 0); @@ -483,7 +494,8 @@ public void testCallFailureRevertAfterFork() { // tx: 0x64fa2479faaeca0dcefbb57c2fc96f785336663f27726e8e7225e7dce3096452 @Test public void testCreateFailure() { - TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true); + TransactionExecutor exec = new TransactionExecutor(config, new SemuxBlockStore(chain), true, true, + true); Key sender = new Key(); TransactionType type = TransactionType.CREATE; @@ -495,7 +507,7 @@ public void testCreateFailure() { "0x608060405234801561001057600080fd5b50610165806100206000396000f300608060405260043610610041576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680633bc5de3014610046575b600080fd5b34801561005257600080fd5b5061005b6100d6565b6040518080602001828103825283818151815260200191508051906020019080838360005b8381101561009b578082015181840152602081019050610080565b50505050905090810190601f1680156100c85780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b60608060405190810160405280602281526020017f466972737420636f6e7472616374212053656d757820746f20746865204d6f6f81526020017f6e210000000000000000000000000000000000000000000000000000000000008152509050905600a165627a7a72305820934582d75405e634939862f4188ebbb6c2765362add401961e8f44aa91b91f040029"); long gas = 121000; Amount gasPrice = Amount.of(200); - Transaction tx = new Transaction(network, type, to, value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice) + Transaction tx = new Transaction(network, type, to, sender.toAddress(), value, Amount.ZERO, nonce, timestamp, data, gas, gasPrice, config.forkEd25519ContractEnabled()) .sign(sender); // credit the sender some balance