diff --git a/.gitignore b/.gitignore
index 71092c5d325..b980800f353 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,4 +51,7 @@ src/main/resources/META-INF/
/output_witness/
output*
nodeId.properties
-Wallet
\ No newline at end of file
+Wallet
+
+# vm_trace
+/vm_trace/
diff --git a/.travis.yml b/.travis.yml
index ff5915a539b..fc2d449d532 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -25,3 +25,5 @@ deploy:
branch: develop
+
+
diff --git a/README.md b/README.md
index 9a72663ee09..677e18b92b5 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
-
+
java-tron
@@ -62,6 +62,12 @@ TRON Protocol and the Tron Virtual Machine (TVM) allow anyone to develop decentr
* JDK 1.8 (JDK 1.9+ are not supported yet)
* On Linux Ubuntu system (e.g. Ubuntu 16.04.4 LTS), ensure that the machine has [__Oracle JDK 8__](https://www.digitalocean.com/community/tutorials/how-to-install-java-with-apt-get-on-ubuntu-16-04), instead of having __Open JDK 8__ in the system. If you are building the source code by using __Open JDK 8__, you will get [__Build Failed__](https://github.com/tronprotocol/java-tron/issues/337) result.
+* Open **UDP** ports for connection to the network
+* **MINIMUM** 2 ENERGY Cores
+
+## Build and Deploy automatically using scripts
+
+- Please take a look at the [Tron Deployment Scripts](https://github.com/tronprotocol/TronDeployment) repository.
## Getting the code with git
@@ -126,7 +132,7 @@ cd java-tron
* Build in [IntelliJ IDEA](https://www.jetbrains.com/idea/) (community version is enough):
- ** Please run ./gradlew build once to build the protocol files **
+ **Please run ./gradlew build once to build the protocol files**
1. Start IntelliJ. Select `File` -> `Open`, then locate to the java-tron folder which you have git cloned to your local drive. Then click `Open` button on the right bottom.
2. Check on `Use auto-import` on the `Import Project from Gradle` dialog. Select JDK 1.8 in the `Gradle JVM` option. Then click `OK`.
@@ -142,10 +148,54 @@ https://github.com/tronprotocol/Documentation/blob/master/TRX/Solidity_and_Full_
## Running a local node and connecting to the public testnet
-* Ensure that the version number is consistent with the version number of the test network. If it is not consistent, please modify the node.p2p.version in the config.conf file and delete the out-directory directory (if it exists).
-* The current p2p.version is **619**
+* Use the [Testnet Config](https://github.com/tronprotocol/TronDeployment/blob/master/test_net_config.conf) or use the [Tron Deployment Scripts](https://github.com/tronprotocol/TronDeployment)
+
+
+### Running a Super Representative Node for mainnet
+
+* Use the executable JAR(Recommended way)
+
+```bash
+java -jar FullNode.jar -p your private key --witness -c your config.conf(Example:/data/java-tron/config.conf)
+Example:
+java -jar FullNode.jar -p 650950B193DDDDB35B6E48912DD28F7AB0E7140C1BFDEFD493348F02295BD812 --witness -c /data/java-tron/config.conf
+
+```
+
+This is similar to running a private testnet, except that the IPs in the `config.conf` are officially declared by TRON.
+
+
+Correct output
+
+```bash
+
+20:43:18.138 INFO [main] [o.t.p.FullNode](FullNode.java:21) Full node running.
+20:43:18.486 INFO [main] [o.t.c.c.a.Args](Args.java:429) Bind address wasn't set, Punching to identify it...
+20:43:18.493 INFO [main] [o.t.c.c.a.Args](Args.java:433) UDP local bound to: 10.0.8.146
+20:43:18.495 INFO [main] [o.t.c.c.a.Args](Args.java:448) External IP wasn't set, using checkip.amazonaws.com to identify it...
+20:43:19.450 INFO [main] [o.t.c.c.a.Args](Args.java:461) External address identified: 47.74.147.87
+20:43:19.599 INFO [main] [o.s.c.a.AnnotationConfigApplicationContext](AbstractApplicationContext.java:573) Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@124c278f: startup date [Fri Apr 27 20:43:19 CST 2018]; root of context hierarchy
+20:43:19.972 INFO [main] [o.s.b.f.a.AutowiredAnnotationBeanPostProcessor](AutowiredAnnotationBeanPostProcessor.java:153) JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
+20:43:20.380 INFO [main] [o.t.c.d.DynamicPropertiesStore](DynamicPropertiesStore.java:244) update latest block header timestamp = 0
+20:43:20.383 INFO [main] [o.t.c.d.DynamicPropertiesStore](DynamicPropertiesStore.java:252) update latest block header number = 0
+20:43:20.393 INFO [main] [o.t.c.d.DynamicPropertiesStore](DynamicPropertiesStore.java:260) update latest block header id = 00
+20:43:20.394 INFO [main] [o.t.c.d.DynamicPropertiesStore](DynamicPropertiesStore.java:265) update state flag = 0
+20:43:20.559 INFO [main] [o.t.c.c.TransactionCapsule](TransactionCapsule.java:83) Transaction create succeeded!
+20:43:20.567 INFO [main] [o.t.c.c.TransactionCapsule](TransactionCapsule.java:83) Transaction create succeeded!
+20:43:20.568 INFO [main] [o.t.c.c.TransactionCapsule](TransactionCapsule.java:83) Transaction create succeeded!
+20:43:20.568 INFO [main] [o.t.c.c.TransactionCapsule](TransactionCapsule.java:83) Transaction create succeeded!
+20:43:20.569 INFO [main] [o.t.c.c.TransactionCapsule](TransactionCapsule.java:83) Transaction create succeeded!
+20:43:20.596 INFO [main] [o.t.c.d.Manager](Manager.java:300) create genesis block
+20:43:20.607 INFO [main] [o.t.c.d.Manager](Manager.java:306) save block: BlockCapsule
+
+```
+
+Then observe whether block synchronization success,If synchronization successfully explains the success of the super node
+
+
+
-### How to run a Super Node
+### Running a Super Representative Node for private testnet
* use master branch
* You should modify the config.conf
1. Replace existing entry in genesis.block.witnesses with your address.
@@ -157,17 +207,11 @@ https://github.com/tronprotocol/Documentation/blob/master/TRX/Solidity_and_Full_
```bash
cd build/libs
-java -jar java-tron.jar -p yourself private key --witness -c yourself config.conf(Example:/data/java-tron/config.conf)
+java -jar FullNode.jar -p your private key --witness -c your config.conf (Example:/data/java-tron/config.conf)
Example:
-java -jar java-tron.jar -p 650950B193DDDDB35B6E48912DD28F7AB0E7140C1BFDEFD493348F02295BD812 --witness -c /data/java-tron/config.conf
+java -jar FullNode.jar -p 650950B193DDDDB35B6E48912DD28F7AB0E7140C1BFDEFD493348F02295BD812 --witness -c /data/java-tron/config.conf
```
-
-* In the Terminal
- Un the config.conf localwitness add your private key.
-```bash
-./gradlew run -Pwitness
-```
Show Output
@@ -286,50 +330,6 @@ In the `Program arguments` option, fill in `--witness`:
Then, run `FullNode::main()` again.
-### Running a Super Node
-
-* Use the executable JAR(Recommended way)
-
-```bash
-cd build/libs
-java -jar java-tron.jar -p yourself private key --witness -c yourself config.conf(Example:/data/java-tron/config.conf)
-Example:
-java -jar java-tron.jar -p 650950B193DDDDB35B6E48912DD28F7AB0E7140C1BFDEFD493348F02295BD812 --witness -c /data/java-tron/config.conf
-
-```
-
-This is similar to running a private testnet, except that the IPs in the `config.conf` are officially declared by TRON.
-
-
-Correct output
-
-```bash
-
-20:43:18.138 INFO [main] [o.t.p.FullNode](FullNode.java:21) Full node running.
-20:43:18.486 INFO [main] [o.t.c.c.a.Args](Args.java:429) Bind address wasn't set, Punching to identify it...
-20:43:18.493 INFO [main] [o.t.c.c.a.Args](Args.java:433) UDP local bound to: 10.0.8.146
-20:43:18.495 INFO [main] [o.t.c.c.a.Args](Args.java:448) External IP wasn't set, using checkip.amazonaws.com to identify it...
-20:43:19.450 INFO [main] [o.t.c.c.a.Args](Args.java:461) External address identified: 47.74.147.87
-20:43:19.599 INFO [main] [o.s.c.a.AnnotationConfigApplicationContext](AbstractApplicationContext.java:573) Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@124c278f: startup date [Fri Apr 27 20:43:19 CST 2018]; root of context hierarchy
-20:43:19.972 INFO [main] [o.s.b.f.a.AutowiredAnnotationBeanPostProcessor](AutowiredAnnotationBeanPostProcessor.java:153) JSR-330 'javax.inject.Inject' annotation found and supported for autowiring
-20:43:20.380 INFO [main] [o.t.c.d.DynamicPropertiesStore](DynamicPropertiesStore.java:244) update latest block header timestamp = 0
-20:43:20.383 INFO [main] [o.t.c.d.DynamicPropertiesStore](DynamicPropertiesStore.java:252) update latest block header number = 0
-20:43:20.393 INFO [main] [o.t.c.d.DynamicPropertiesStore](DynamicPropertiesStore.java:260) update latest block header id = 00
-20:43:20.394 INFO [main] [o.t.c.d.DynamicPropertiesStore](DynamicPropertiesStore.java:265) update state flag = 0
-20:43:20.559 INFO [main] [o.t.c.c.TransactionCapsule](TransactionCapsule.java:83) Transaction create succeeded!
-20:43:20.567 INFO [main] [o.t.c.c.TransactionCapsule](TransactionCapsule.java:83) Transaction create succeeded!
-20:43:20.568 INFO [main] [o.t.c.c.TransactionCapsule](TransactionCapsule.java:83) Transaction create succeeded!
-20:43:20.568 INFO [main] [o.t.c.c.TransactionCapsule](TransactionCapsule.java:83) Transaction create succeeded!
-20:43:20.569 INFO [main] [o.t.c.c.TransactionCapsule](TransactionCapsule.java:83) Transaction create succeeded!
-20:43:20.596 INFO [main] [o.t.c.d.Manager](Manager.java:300) create genesis block
-20:43:20.607 INFO [main] [o.t.c.d.Manager](Manager.java:306) save block: BlockCapsule
-
-```
-
-Then observe whether block synchronization success,If synchronization successfully explains the success of the super node
-
-
-
# Quick Start
Read the [Quick Start](http://wiki.tron.network/en/latest/The_TRON_Network.html#how-to-build).
diff --git a/build.gradle b/build.gradle
index 1c42dd1d362..7941bff43d8 100755
--- a/build.gradle
+++ b/build.gradle
@@ -49,6 +49,7 @@ repositories {
maven { url 'http://mvnrepository.com' }
mavenLocal()
mavenCentral()
+ maven { url 'http://repo.spring.io/plugins-release' }
}
def versions = [
checkstyle: '8.7',
@@ -68,6 +69,24 @@ configurations.getByName('checkstyleConfig') {
transitive = false
}
+static def isWindows() {
+ return org.gradle.internal.os.OperatingSystem.current().isWindows()
+}
+
+if (isWindows()) {
+ ext {
+ leveldbGroup = "org.ethereum"
+ leveldbName = "leveldbjni-all"
+ leveldbVersion = "1.18.3"
+ }
+} else {
+ ext {
+ leveldbGroup = "org.fusesource.leveldbjni"
+ leveldbName = "leveldbjni-all"
+ leveldbVersion = "1.8"
+ }
+}
+
dependencies {
//local libraries
compile fileTree(dir: 'libs', include: '*.jar')
@@ -95,8 +114,7 @@ dependencies {
compile "org.iq80.leveldb:leveldb:0.7"
- compile group: 'org.fusesource.leveldbjni', name: 'leveldbjni-all',
- version: '1.8'
+ compile group: leveldbGroup, name: leveldbName, version: leveldbVersion
compile "org.apache.commons:commons-collections4:4.0"
diff --git a/core/Contract.proto b/core/Contract.proto
deleted file mode 100644
index 0306580d19f..00000000000
--- a/core/Contract.proto
+++ /dev/null
@@ -1,29 +0,0 @@
-syntax = "proto3";
-
-package protocol;
-
-option java_package = "org.tron.protos"; //Specify the name of the package that generated the Java file
-option java_outer_classname = "Contract"; //Specify the class name of the generated Java file
-option go_package = "github.com/tronprotocol/grpc-gateway/core";
-
-
-message VoteContract {
- bytes address = 1;
- repeated bytes voidAddress = 2;
- bool support = 3;
-}
-
-message TransferContract {
-
-}
-
-
-message DeployContract {
- bytes address = 1;
- bytes script = 2;
-}
-
-
-message CustomContract {
-
-}
\ No newline at end of file
diff --git a/deploy.sh b/deploy.sh
index 7a0486beff9..9576bcc254b 100644
--- a/deploy.sh
+++ b/deploy.sh
@@ -1,3 +1,3 @@
#!/bin/bash
ssh tron@47.93.9.236 -p 22008 sh /home/tron/workspace/deploy_all.sh
-
+./gradlew stest
diff --git a/src/main/java/org/tron/common/application/Application.java b/src/main/java/org/tron/common/application/Application.java
index c408b4419f9..d9279ddb25b 100644
--- a/src/main/java/org/tron/common/application/Application.java
+++ b/src/main/java/org/tron/common/application/Application.java
@@ -43,4 +43,5 @@ public interface Application {
void addService(Service service);
Manager getDbManager();
+
}
diff --git a/src/main/java/org/tron/common/application/ApplicationFactory.java b/src/main/java/org/tron/common/application/ApplicationFactory.java
index 319bb5e8bb6..7c0146afc37 100644
--- a/src/main/java/org/tron/common/application/ApplicationFactory.java
+++ b/src/main/java/org/tron/common/application/ApplicationFactory.java
@@ -15,22 +15,10 @@
package org.tron.common.application;
-import com.google.inject.Guice;
-import com.google.inject.Injector;
import org.springframework.context.ApplicationContext;
public class ApplicationFactory {
- /**
- * Build a Guice instance.
- *
- * @return Guice
- */
- public Injector buildGuice() {
- return Guice.createInjector(
- new Module());
- }
-
/**
* Build a new application.
*/
diff --git a/src/main/java/org/tron/common/application/ApplicationImpl.java b/src/main/java/org/tron/common/application/ApplicationImpl.java
index aa94fe96f49..e5961f3f11a 100644
--- a/src/main/java/org/tron/common/application/ApplicationImpl.java
+++ b/src/main/java/org/tron/common/application/ApplicationImpl.java
@@ -6,7 +6,6 @@
import org.tron.core.config.args.Args;
import org.tron.core.db.BlockStore;
import org.tron.core.db.Manager;
-import org.tron.core.db.RevokingStore;
import org.tron.core.net.node.Node;
import org.tron.core.net.node.NodeDelegate;
import org.tron.core.net.node.NodeDelegateImpl;
@@ -25,7 +24,7 @@ public class ApplicationImpl implements Application {
@Autowired
private Manager dbManager;
-
+
private boolean isProducer;
private void resetP2PNode() {
@@ -76,6 +75,7 @@ public void shutdown() {
closeAllStore();
}
closeConnection();
+ dbManager.stopRepushThread();
System.err.println("******** end to shutdown ********");
}
diff --git a/src/main/java/org/tron/common/application/CliApplication.java b/src/main/java/org/tron/common/application/CliApplication.java
index e56093eaa53..9bcffd106b2 100644
--- a/src/main/java/org/tron/common/application/CliApplication.java
+++ b/src/main/java/org/tron/common/application/CliApplication.java
@@ -75,4 +75,5 @@ public void addService(Service service) {
public Manager getDbManager() {
return null;
}
+
}
diff --git a/src/main/java/org/tron/common/application/Module.java b/src/main/java/org/tron/common/application/Module.java
deleted file mode 100644
index 5b50d9173b4..00000000000
--- a/src/main/java/org/tron/common/application/Module.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * java-tron is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * java-tron is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.tron.common.application;
-
-import static org.tron.core.Constant.BLOCK_DB_NAME;
-import static org.tron.core.Constant.TRANSACTION_DB_NAME;
-
-import com.google.inject.AbstractModule;
-import com.google.inject.Provides;
-import com.google.inject.Singleton;
-import javax.inject.Named;
-import org.tron.common.storage.leveldb.LevelDbDataSourceImpl;
-import org.tron.core.config.args.Args;
-
-public class Module extends AbstractModule {
-
- @Override
- protected void configure() {
-
- }
-
- /**
- * build transaction database.
- */
- @Provides
- @Singleton
- @Named("transaction")
- public LevelDbDataSourceImpl buildTransactionDb() {
- LevelDbDataSourceImpl db = new LevelDbDataSourceImpl(Args.getInstance().getOutputDirectory(),
- TRANSACTION_DB_NAME);
- db.initDB();
- return db;
- }
-
- /**
- * build block database.
- */
- @Provides
- @Singleton
- @Named("block")
- public LevelDbDataSourceImpl buildBlockDb() {
- LevelDbDataSourceImpl db = new LevelDbDataSourceImpl(Args.getInstance().getOutputDirectory(),
- BLOCK_DB_NAME);
- db.initDB();
- return db;
- }
-}
diff --git a/src/main/java/org/tron/common/application/TronApplicationContext.java b/src/main/java/org/tron/common/application/TronApplicationContext.java
new file mode 100644
index 00000000000..50cda6935f5
--- /dev/null
+++ b/src/main/java/org/tron/common/application/TronApplicationContext.java
@@ -0,0 +1,32 @@
+package org.tron.common.application;
+
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.core.db.Manager;
+
+public class TronApplicationContext extends AnnotationConfigApplicationContext {
+
+ public TronApplicationContext() {
+ }
+
+ public TronApplicationContext(DefaultListableBeanFactory beanFactory) {
+ super(beanFactory);
+ }
+
+ public TronApplicationContext(Class>... annotatedClasses) {
+ super(annotatedClasses);
+ }
+
+ public TronApplicationContext(String... basePackages) {
+ super(basePackages);
+ }
+
+ @Override
+ public void destroy() {
+
+ Manager dbManager = getBean(Manager.class);
+ dbManager.stopRepushThread();
+
+ super.destroy();
+ }
+}
diff --git a/src/main/java/org/tron/common/net/udp/handler/MessageHandler.java b/src/main/java/org/tron/common/net/udp/handler/MessageHandler.java
index 23660f12939..b497f36f6cf 100644
--- a/src/main/java/org/tron/common/net/udp/handler/MessageHandler.java
+++ b/src/main/java/org/tron/common/net/udp/handler/MessageHandler.java
@@ -38,8 +38,8 @@ public class MessageHandler extends SimpleChannelInboundHandler
private EventHandler eventHandler;
- public MessageHandler(NioDatagramChannel ch, EventHandler eventHandler) {
- channel = ch;
+ public MessageHandler(NioDatagramChannel channel, EventHandler eventHandler) {
+ this.channel = channel;
this.eventHandler = eventHandler;
}
diff --git a/src/main/java/org/tron/common/net/udp/handler/PacketDecoder.java b/src/main/java/org/tron/common/net/udp/handler/PacketDecoder.java
index 182f6df35bd..bd239e40550 100644
--- a/src/main/java/org/tron/common/net/udp/handler/PacketDecoder.java
+++ b/src/main/java/org/tron/common/net/udp/handler/PacketDecoder.java
@@ -29,7 +29,7 @@ public class PacketDecoder extends MessageToMessageDecoder {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger("PacketDecoder");
- private int maxSize = 2048;
+ private final int maxSize = 2048;
@Override
public void decode(ChannelHandlerContext ctx, DatagramPacket packet, List out) throws Exception {
diff --git a/src/main/java/org/tron/common/net/udp/handler/UdpEvent.java b/src/main/java/org/tron/common/net/udp/handler/UdpEvent.java
index e7f41bd9616..e6691db6777 100644
--- a/src/main/java/org/tron/common/net/udp/handler/UdpEvent.java
+++ b/src/main/java/org/tron/common/net/udp/handler/UdpEvent.java
@@ -25,9 +25,9 @@ public class UdpEvent {
private Message message;
private InetSocketAddress address;
- public UdpEvent(Message m, InetSocketAddress a) {
- message = m;
- address = a;
+ public UdpEvent(Message message, InetSocketAddress address) {
+ this.message = message;
+ this.address = address;
}
public Message getMessage() {
diff --git a/src/main/java/org/tron/common/overlay/discover/node/NodeHandler.java b/src/main/java/org/tron/common/overlay/discover/node/NodeHandler.java
index 7daddf77823..0ba03d1323c 100644
--- a/src/main/java/org/tron/common/overlay/discover/node/NodeHandler.java
+++ b/src/main/java/org/tron/common/overlay/discover/node/NodeHandler.java
@@ -20,7 +20,6 @@
import java.net.InetSocketAddress;
import java.util.List;
import java.util.concurrent.TimeUnit;
-import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
@@ -99,6 +98,7 @@ public NodeHandler(Node node, NodeManager nodeManager) {
this.node = node;
this.nodeManager = nodeManager;
this.inetSocketAddress = new InetSocketAddress(node.getHost(), node.getPort());
+ this.nodeStatistics = new NodeStatistics(node);
changeState(State.Discovered);
}
@@ -127,9 +127,6 @@ public void setNode(Node node) {
}
public NodeStatistics getNodeStatistics() {
- if (nodeStatistics == null) {
- nodeStatistics = new NodeStatistics(node);
- }
return nodeStatistics;
}
@@ -194,7 +191,6 @@ public void changeState(State newState) {
}
public void handlePing(PingMessage msg) {
- getNodeStatistics().discoverInPing.add();
if (!nodeManager.getTable().getNode().equals(node)) {
sendPong();
}
@@ -208,7 +204,6 @@ public void handlePing(PingMessage msg) {
public void handlePong(PongMessage msg) {
if (waitForPong) {
waitForPong = false;
- getNodeStatistics().discoverInPong.add();
getNodeStatistics().discoverMessageLatency
.add((double) System.currentTimeMillis() - pingSent);
getNodeStatistics().lastPongReplyTime.set(System.currentTimeMillis());
@@ -227,7 +222,6 @@ public void handleNeighbours(NeighborsMessage msg) {
return;
}
waitForNeighbors = false;
- getNodeStatistics().discoverInNeighbours.add();
for (Node n : msg.getNodes()) {
if (!nodeManager.getPublicHomeNode().getHexId().equals(n.getHexId())) {
nodeManager.getNodeHandler(n);
@@ -236,7 +230,6 @@ public void handleNeighbours(NeighborsMessage msg) {
}
public void handleFindNode(FindNodeMessage msg) {
- getNodeStatistics().discoverInFind.add();
List closest = nodeManager.getTable().getClosestNodes(msg.getTargetId());
sendNeighbours(closest);
}
@@ -261,7 +254,6 @@ public void sendPing() {
waitForPong = true;
pingSent = System.currentTimeMillis();
sendMessage(ping);
- getNodeStatistics().discoverOutPing.add();
if (nodeManager.getPongTimer().isShutdown()) {
return;
@@ -281,24 +273,22 @@ public void sendPing() {
public void sendPong() {
Message pong = new PongMessage(nodeManager.getPublicHomeNode());
sendMessage(pong);
- getNodeStatistics().discoverOutPong.add();
}
public void sendNeighbours(List neighbours) {
Message neighbors = new NeighborsMessage(nodeManager.getPublicHomeNode(), neighbours);
sendMessage(neighbors);
- getNodeStatistics().discoverOutNeighbours.add();
}
public void sendFindNode(byte[] target) {
waitForNeighbors = true;
Message findNode = new FindNodeMessage(nodeManager.getPublicHomeNode(), target);
sendMessage(findNode);
- getNodeStatistics().discoverOutFind.add();
}
private void sendMessage(Message msg) {
nodeManager.sendOutbound(new UdpEvent(msg, getInetSocketAddress()));
+ nodeStatistics.messageStatistics.addUdpOutMessage(msg.getType());
}
@Override
diff --git a/src/main/java/org/tron/common/overlay/discover/node/NodeManager.java b/src/main/java/org/tron/common/overlay/discover/node/NodeManager.java
index dab51430252..c47fe886e45 100644
--- a/src/main/java/org/tron/common/overlay/discover/node/NodeManager.java
+++ b/src/main/java/org/tron/common/overlay/discover/node/NodeManager.java
@@ -48,21 +48,18 @@
import org.tron.common.net.udp.message.discover.PongMessage;
import org.tron.common.overlay.discover.DiscoverListener;
import org.tron.common.overlay.discover.node.NodeHandler.State;
+import org.tron.common.overlay.discover.node.statistics.MessageStatistics;
import org.tron.common.overlay.discover.node.statistics.NodeStatistics;
import org.tron.common.overlay.discover.table.NodeTable;
import org.tron.common.utils.CollectionUtils;
import org.tron.core.config.args.Args;
import org.tron.core.db.Manager;
-import org.tron.protos.Protocol.ReasonCode;
@Component
public class NodeManager implements EventHandler {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger("NodeManager");
- private Cache badNodes = CacheBuilder.newBuilder().maximumSize(10000)
- .expireAfterWrite(1, TimeUnit.HOURS).recordStats().build();
-
private Args args = Args.getInstance();
private Manager dbManager;
@@ -240,10 +237,7 @@ public void handleEvent(UdpEvent udpEvent) {
}
NodeHandler nodeHandler = getNodeHandler(n);
- if (badNodes.getIfPresent(nodeHandler.getInetSocketAddress()) != null){
- logger.warn("Receive packet from bad node {}.", sender.getAddress());
- return;
- }
+ nodeHandler.getNodeStatistics().messageStatistics.addUdpInMessage(m.getType());
switch (m.getType()) {
case DISCOVER_PING:
@@ -259,7 +253,6 @@ public void handleEvent(UdpEvent udpEvent) {
nodeHandler.handleNeighbours((NeighborsMessage) m);
break;
}
- calculateMsgCount(nodeHandler);
}
public void sendOutbound(UdpEvent udpEvent) {
@@ -383,17 +376,4 @@ void checkAll() {
}
}
- private void calculateMsgCount(NodeHandler nodeHandler){
- int interval = 10;
- int maxCount = 10;
- NodeStatistics statistics = nodeHandler.getNodeStatistics();
- int count = statistics.discoverInPing.getCount(interval) + statistics.discoverInPong.getCount(interval)
- + statistics.discoverInFind.getCount(interval) + statistics.discoverInNeighbours.getCount(interval);
- if (count > maxCount){
- logger.warn("UDP attack found: {}.", nodeHandler);
- badNodes.put(nodeHandler.getInetSocketAddress(), nodeHandler);
- table.dropNode(nodeHandler.getNode());
- }
- }
-
}
diff --git a/src/main/java/org/tron/common/overlay/discover/node/statistics/MessageCount.java b/src/main/java/org/tron/common/overlay/discover/node/statistics/MessageCount.java
new file mode 100644
index 00000000000..43ef657ede6
--- /dev/null
+++ b/src/main/java/org/tron/common/overlay/discover/node/statistics/MessageCount.java
@@ -0,0 +1,69 @@
+package org.tron.common.overlay.discover.node.statistics;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class MessageCount {
+
+ private static int SIZE = 60;
+
+ private int[] szCount = new int[SIZE];
+
+ private long indexTime = System.currentTimeMillis() / 1000;
+
+ private int index = (int) (indexTime % SIZE);
+
+ private long totalCount = 0;
+
+ private void update() {
+ long time = System.currentTimeMillis() / 1000;
+ long gap = time - indexTime;
+ int k = gap > SIZE ? SIZE : (int) gap;
+ if (k > 0) {
+ for (int i = 1; i <= k; i++) {
+ szCount[(index + i) % SIZE] = 0;
+ }
+ index = (int) (time % SIZE);
+ indexTime = time;
+ }
+ }
+
+ public void add() {
+ update();
+ szCount[index]++;
+ totalCount++;
+ }
+
+ public void add(int count) {
+ update();
+ szCount[index] += count;
+ totalCount += count;
+ }
+
+ public int getCount(int interval) {
+ if (interval > SIZE) {
+ logger.warn("Param interval({}) is gt SIZE({})", interval, SIZE);
+ return 0;
+ }
+ update();
+ int count = 0;
+ for (int i = 0; i < interval; i++) {
+ count += szCount[(SIZE + index - i) % SIZE];
+ }
+ return count;
+ }
+
+ public long getTotalCount() {
+ return totalCount;
+ }
+
+ public void reset() {
+ totalCount = 0;
+ }
+
+ @Override
+ public String toString() {
+ return String.valueOf(totalCount);
+ }
+
+}
diff --git a/src/main/java/org/tron/common/overlay/discover/node/statistics/MessageCountStatistics.java b/src/main/java/org/tron/common/overlay/discover/node/statistics/MessageCountStatistics.java
deleted file mode 100644
index b205cf7fcee..00000000000
--- a/src/main/java/org/tron/common/overlay/discover/node/statistics/MessageCountStatistics.java
+++ /dev/null
@@ -1,53 +0,0 @@
-package org.tron.common.overlay.discover.node.statistics;
-
-import lombok.extern.slf4j.Slf4j;
-
-@Slf4j
-public class MessageCountStatistics {
-
- private static int SIZE = 60;
-
- private int [] szCount = new int[SIZE];
-
- private long indexTime = System.currentTimeMillis() / 1000;
-
- private int index = (int)(indexTime % SIZE);
-
- private long totalCount = 0;
-
- private void update(){
- long time = System.currentTimeMillis() / 1000;
- long gap = time - indexTime;
- int k = gap > SIZE ? SIZE : (int)gap;
- if (k > 0){
- for (int i = 1; i <= k; i++){
- szCount[(index + i) % SIZE] = 0;
- }
- index = (int)(time % SIZE);
- indexTime = time;
- }
- }
-
- public void add() {
- update();
- szCount[index]++;
- totalCount++;
- }
-
- public int getCount(int interval){
- if (interval > SIZE){
- logger.warn("Param interval({}) is gt SIZE({})", interval, SIZE);
- return 0;
- }
- update();
- int count = 0;
- for (int i = 0; i < interval; i++){
- count += szCount[(SIZE + index - i) % SIZE];
- }
- return count;
- }
-
- public long getTotalCount() {
- return totalCount;
- }
-}
diff --git a/src/main/java/org/tron/common/overlay/discover/node/statistics/MessageStatistics.java b/src/main/java/org/tron/common/overlay/discover/node/statistics/MessageStatistics.java
new file mode 100644
index 00000000000..89f92d8a218
--- /dev/null
+++ b/src/main/java/org/tron/common/overlay/discover/node/statistics/MessageStatistics.java
@@ -0,0 +1,197 @@
+package org.tron.common.overlay.discover.node.statistics;
+
+import lombok.extern.slf4j.Slf4j;
+import org.tron.common.net.udp.message.UdpMessageTypeEnum;
+import org.tron.common.overlay.message.Message;
+import org.tron.core.net.message.FetchInvDataMessage;
+import org.tron.core.net.message.InventoryMessage;
+import org.tron.core.net.message.MessageTypes;
+import org.tron.core.net.message.TransactionsMessage;
+
+@Slf4j
+public class MessageStatistics {
+
+ //udp discovery
+ public final MessageCount discoverInPing = new MessageCount();
+ public final MessageCount discoverOutPing = new MessageCount();
+ public final MessageCount discoverInPong = new MessageCount();
+ public final MessageCount discoverOutPong = new MessageCount();
+ public final MessageCount discoverInFindNode = new MessageCount();
+ public final MessageCount discoverOutFindNode = new MessageCount();
+ public final MessageCount discoverInNeighbours = new MessageCount();
+ public final MessageCount discoverOutNeighbours = new MessageCount();
+
+ //tcp p2p
+ public final MessageCount p2pInHello = new MessageCount();
+ public final MessageCount p2pOutHello = new MessageCount();
+ public final MessageCount p2pInPing = new MessageCount();
+ public final MessageCount p2pOutPing = new MessageCount();
+ public final MessageCount p2pInPong = new MessageCount();
+ public final MessageCount p2pOutPong = new MessageCount();
+ public final MessageCount p2pInDisconnect = new MessageCount();
+ public final MessageCount p2pOutDisconnect = new MessageCount();
+
+ //tcp tron
+ public final MessageCount tronInMessage = new MessageCount();
+ public final MessageCount tronOutMessage = new MessageCount();
+
+ public final MessageCount tronInSyncBlockChain = new MessageCount();
+ public final MessageCount tronOutSyncBlockChain = new MessageCount();
+ public final MessageCount tronInBlockChainInventory = new MessageCount();
+ public final MessageCount tronOutBlockChainInventory = new MessageCount();
+
+ public final MessageCount tronInTrxInventory = new MessageCount();
+ public final MessageCount tronOutTrxInventory = new MessageCount();
+ public final MessageCount tronInTrxInventoryElement = new MessageCount();
+ public final MessageCount tronOutTrxInventoryElement = new MessageCount();
+
+ public final MessageCount tronInBlockInventory = new MessageCount();
+ public final MessageCount tronOutBlockInventory = new MessageCount();
+ public final MessageCount tronInBlockInventoryElement = new MessageCount();
+ public final MessageCount tronOutBlockInventoryElement = new MessageCount();
+
+ public final MessageCount tronInTrxFetchInvData = new MessageCount();
+ public final MessageCount tronOutTrxFetchInvData = new MessageCount();
+ public final MessageCount tronInTrxFetchInvDataElement = new MessageCount();
+ public final MessageCount tronOutTrxFetchInvDataElement = new MessageCount();
+
+ public final MessageCount tronInBlockFetchInvData = new MessageCount();
+ public final MessageCount tronOutBlockFetchInvData = new MessageCount();
+ public final MessageCount tronInBlockFetchInvDataElement = new MessageCount();
+ public final MessageCount tronOutBlockFetchInvDataElement = new MessageCount();
+
+
+ public final MessageCount tronInTrx = new MessageCount();
+ public final MessageCount tronOutTrx = new MessageCount();
+ public final MessageCount tronInTrxs = new MessageCount();
+ public final MessageCount tronOutTrxs = new MessageCount();
+ public final MessageCount tronInBlock = new MessageCount();
+ public final MessageCount tronOutBlock = new MessageCount();
+ public final MessageCount tronOutAdvBlock = new MessageCount();
+
+ public void addUdpInMessage(UdpMessageTypeEnum type){
+ addUdpMessage(type, true);
+ }
+
+ public void addUdpOutMessage(UdpMessageTypeEnum type){
+ addUdpMessage(type, false);
+ }
+
+ public void addTcpInMessage(Message msg){
+ addTcpMessage(msg, true);
+ }
+
+ public void addTcpOutMessage(Message msg){
+ addTcpMessage(msg, false);
+ }
+
+ private void addUdpMessage(UdpMessageTypeEnum type, boolean flag){
+ switch (type){
+ case DISCOVER_PING:
+ if (flag) discoverInPing.add(); else discoverOutPing.add();
+ break;
+ case DISCOVER_PONG:
+ if (flag) discoverInPong.add(); else discoverOutPong.add();
+ break;
+ case DISCOVER_FIND_NODE:
+ if (flag) discoverInFindNode.add(); else discoverOutFindNode.add();
+ break;
+ case DISCOVER_NEIGHBORS:
+ if (flag) discoverInNeighbours.add(); else discoverOutNeighbours.add();
+ break;
+ default:
+ break;
+ }
+ }
+
+ private void addTcpMessage(Message msg, boolean flag){
+
+ if (flag) {
+ tronInMessage.add();
+ } else {
+ tronOutMessage.add();
+ }
+
+ switch (msg.getType()){
+ case P2P_HELLO:
+ if (flag) p2pInHello.add(); else p2pOutHello.add();
+ break;
+ case P2P_PING:
+ if (flag) p2pInPing.add(); else p2pOutPing.add();
+ break;
+ case P2P_PONG:
+ if (flag) p2pInPong.add(); else p2pOutPong.add();
+ break;
+ case P2P_DISCONNECT:
+ if (flag) p2pInDisconnect.add(); else p2pOutDisconnect.add();
+ break;
+ case SYNC_BLOCK_CHAIN:
+ if (flag) tronInSyncBlockChain.add(); else tronOutSyncBlockChain.add();
+ break;
+ case BLOCK_CHAIN_INVENTORY:
+ if (flag) tronInBlockChainInventory.add(); else tronOutBlockChainInventory.add();
+ break;
+ case INVENTORY:
+ InventoryMessage inventoryMessage = (InventoryMessage) msg;
+ int inventorySize = inventoryMessage.getInventory().getIdsCount();
+ if (flag) {
+ if (inventoryMessage.getInvMessageType() == MessageTypes.TRX){
+ tronInTrxInventory.add();
+ tronInTrxInventoryElement.add(inventorySize);
+ }else {
+ tronInBlockInventory.add();
+ tronInBlockInventoryElement.add(inventorySize);
+ }
+ } else {
+ if (inventoryMessage.getInvMessageType() == MessageTypes.TRX){
+ tronOutTrxInventory.add();
+ tronOutTrxInventoryElement.add(inventorySize);
+ }else {
+ tronOutBlockInventory.add();
+ tronOutBlockInventoryElement.add(inventorySize);
+ }
+ }
+ break;
+ case FETCH_INV_DATA:
+ FetchInvDataMessage fetchInvDataMessage = (FetchInvDataMessage) msg;
+ int fetchSize = fetchInvDataMessage.getInventory().getIdsCount();
+ if (flag) {
+ if (fetchInvDataMessage.getInvMessageType() == MessageTypes.TRX){
+ tronInTrxFetchInvData.add();
+ tronInTrxFetchInvDataElement.add(fetchSize);
+ }else {
+ tronInBlockFetchInvData.add();
+ tronInBlockFetchInvDataElement.add(fetchSize);
+ }
+ } else {
+ if (fetchInvDataMessage.getInvMessageType() == MessageTypes.TRX){
+ tronOutTrxFetchInvData.add();
+ tronOutTrxFetchInvDataElement.add(fetchSize);
+ }else {
+ tronOutBlockFetchInvData.add();
+ tronOutBlockFetchInvDataElement.add(fetchSize);
+ }
+ }
+ break;
+ case TRXS:
+ TransactionsMessage transactionsMessage = (TransactionsMessage)msg;
+ if (flag) {
+ tronInTrxs.add();
+ tronInTrx.add(transactionsMessage.getTransactions().getTransactionsCount());
+ } else {
+ tronOutTrxs.add();
+ tronOutTrx.add(transactionsMessage.getTransactions().getTransactionsCount());
+ }
+ break;
+ case TRX:
+ if (flag) tronInMessage.add(); else tronOutMessage.add();
+ break;
+ case BLOCK:
+ if (flag) tronInBlock.add(); tronOutBlock.add();
+ break;
+ default:
+ break;
+ }
+ }
+
+}
diff --git a/src/main/java/org/tron/common/overlay/discover/node/statistics/NodeStatistics.java b/src/main/java/org/tron/common/overlay/discover/node/statistics/NodeStatistics.java
index d627307de20..e262956375b 100644
--- a/src/main/java/org/tron/common/overlay/discover/node/statistics/NodeStatistics.java
+++ b/src/main/java/org/tron/common/overlay/discover/node/statistics/NodeStatistics.java
@@ -18,12 +18,10 @@
package org.tron.common.overlay.discover.node.statistics;
-import static java.lang.Math.min;
-
-import java.util.Date;
import java.util.concurrent.atomic.AtomicLong;
-import org.joda.time.DateTime;
+import lombok.Getter;
import org.tron.common.overlay.discover.node.Node;
+import org.tron.core.config.args.Args;
import org.tron.protos.Protocol.ReasonCode;
public class NodeStatistics {
@@ -31,87 +29,37 @@ public class NodeStatistics {
public final static int REPUTATION_PREDEFINED = 100000;
public final static long TOO_MANY_PEERS_PENALIZE_TIMEOUT = 60 * 1000L;
private static final long CLEAR_CYCLE_TIME = 60 * 60 * 1000L;
+ private final long MIN_DATA_LENGTH = Args.getInstance().getReceiveTcpMinDataLength();
private boolean isPredefined = false;
-
private int persistedReputation = 0;
-
+ @Getter
private int disconnectTimes = 0;
-
- // discovery stat
- public final MessageCountStatistics discoverInPing = new MessageCountStatistics();
- public final MessageCountStatistics discoverOutPing = new MessageCountStatistics();
- public final MessageCountStatistics discoverInPong = new MessageCountStatistics();
- public final MessageCountStatistics discoverOutPong = new MessageCountStatistics();
- public final MessageCountStatistics discoverInFind = new MessageCountStatistics();
- public final MessageCountStatistics discoverOutFind = new MessageCountStatistics();
- public final MessageCountStatistics discoverInNeighbours = new MessageCountStatistics();
- public final MessageCountStatistics discoverOutNeighbours = new MessageCountStatistics();
-
- public final SimpleStatter discoverMessageLatency;
- public final AtomicLong lastPongReplyTime = new AtomicLong(0l); // in milliseconds
-
- // stat
- public final MessageCountStatistics p2pInHello = new MessageCountStatistics();
- public final MessageCountStatistics p2pOutHello = new MessageCountStatistics();
- public final MessageCountStatistics tronInMessage = new MessageCountStatistics();
- public final MessageCountStatistics tronOutMessage = new MessageCountStatistics();
-
- public final MessageCountStatistics p2pHandShake = new MessageCountStatistics();
-
+ @Getter
private ReasonCode tronLastRemoteDisconnectReason = null;
+ @Getter
private ReasonCode tronLastLocalDisconnectReason = null;
private long lastDisconnectedTime = 0;
private long firstDisconnectedTime = 0;
+ public final MessageStatistics messageStatistics = new MessageStatistics();
+ public final MessageCount p2pHandShake = new MessageCount();
+ public final MessageCount tcpFlow = new MessageCount();
+
+ public final SimpleStatter discoverMessageLatency;
+ public final AtomicLong lastPongReplyTime = new AtomicLong(0l); // in milliseconds
+
+ private Reputation reputation;
public NodeStatistics(Node node) {
discoverMessageLatency = new SimpleStatter(node.getIdString());
- }
-
- private int getSessionFairReputation() {
- int discoverReput = 0;
-
- discoverReput +=
- min(discoverInPong.getTotalCount(), 1) * (discoverOutPing.getTotalCount() == discoverInPong.getTotalCount() ? 50 : 1);
-
- discoverReput +=
- min(discoverInNeighbours.getTotalCount(), 1) * (discoverOutFind.getTotalCount() == discoverInNeighbours.getTotalCount() ? 50 : 1);
-
- discoverReput += (int)discoverMessageLatency.getAvrg() == 0 ? 0 : 1000 / discoverMessageLatency.getAvrg();
-
- int reput = 0;
- reput += p2pHandShake.getTotalCount() > 0 ? 20 : 0;
- reput += min(tronInMessage.getTotalCount(), 10) * 3;
-
- if (wasDisconnected()) {
- if (tronLastLocalDisconnectReason == null && tronLastRemoteDisconnectReason == null) {
- // means connection was dropped without reporting any reason - bad
- reput *= 0.3;
- } else if (tronLastLocalDisconnectReason != ReasonCode.REQUESTED) {
- // the disconnect was not initiated by discover mode
- if (tronLastRemoteDisconnectReason == ReasonCode.TOO_MANY_PEERS) {
- // The peer is popular, but we were unlucky
- reput *= 0.3;
- } else if (tronLastRemoteDisconnectReason != ReasonCode.REQUESTED) {
- // other disconnect reasons
- reput *= 0.2;
- }
- }
- }
- if (disconnectTimes > 20) {
- return 0;
- }
- int score =
- discoverReput + 10 * reput - (int) Math.pow(2, disconnectTimes) * (disconnectTimes > 0 ? 10
- : 0);
- return score > 0 ? score : 0;
+ reputation = new Reputation(this);
}
public int getReputation() {
int score = 0;
if (!isReputationPenalized()){
- score += persistedReputation / 2 + getSessionFairReputation();
+ score += persistedReputation / 5 + reputation.calculate();
}
if (isPredefined){
score += REPUTATION_PREDEFINED;
@@ -150,9 +98,7 @@ public boolean isReputationPenalized() {
firstDisconnectedTime = 0;
}
- if (tronLastLocalDisconnectReason == ReasonCode.NULL_IDENTITY ||
- tronLastRemoteDisconnectReason == ReasonCode.NULL_IDENTITY ||
- tronLastLocalDisconnectReason == ReasonCode.INCOMPATIBLE_PROTOCOL ||
+ if (tronLastLocalDisconnectReason == ReasonCode.INCOMPATIBLE_PROTOCOL ||
tronLastRemoteDisconnectReason == ReasonCode.INCOMPATIBLE_PROTOCOL ||
tronLastLocalDisconnectReason == ReasonCode.BAD_PROTOCOL ||
tronLastRemoteDisconnectReason == ReasonCode.BAD_PROTOCOL ||
@@ -164,12 +110,12 @@ public boolean isReputationPenalized() {
tronLastRemoteDisconnectReason == ReasonCode.FORKED ||
tronLastLocalDisconnectReason == ReasonCode.UNLINKABLE ||
tronLastRemoteDisconnectReason == ReasonCode.UNLINKABLE ||
- tronLastLocalDisconnectReason == ReasonCode.INCOMPATIBLE_VERSION ||
- tronLastRemoteDisconnectReason == ReasonCode.INCOMPATIBLE_VERSION ||
tronLastLocalDisconnectReason == ReasonCode.INCOMPATIBLE_CHAIN ||
tronLastRemoteDisconnectReason == ReasonCode.INCOMPATIBLE_CHAIN ||
tronLastRemoteDisconnectReason == ReasonCode.SYNC_FAIL ||
- tronLastLocalDisconnectReason == ReasonCode.SYNC_FAIL) {
+ tronLastLocalDisconnectReason == ReasonCode.SYNC_FAIL ||
+ tronLastRemoteDisconnectReason == ReasonCode.INCOMPATIBLE_VERSION ||
+ tronLastLocalDisconnectReason == ReasonCode.INCOMPATIBLE_VERSION) {
persistedReputation = 0;
return true;
}
@@ -191,6 +137,9 @@ public void notifyDisconnect() {
if (firstDisconnectedTime <= 0) {
firstDisconnectedTime = lastDisconnectedTime;
}
+ if (tronLastLocalDisconnectReason == ReasonCode.RESET) {
+ return;
+ }
disconnectTimes++;
persistedReputation = persistedReputation / 2;
}
@@ -203,6 +152,10 @@ public void setPredefined(boolean isPredefined) {
this.isPredefined = isPredefined;
}
+ public boolean isPredefined() {
+ return isPredefined;
+ }
+
public void setPersistedReputation(int persistedReputation) {
this.persistedReputation = persistedReputation;
}
@@ -210,16 +163,17 @@ public void setPersistedReputation(int persistedReputation) {
@Override
public String toString() {
return "NodeStat[reput: " + getReputation() + "(" + persistedReputation + "), discover: " +
- discoverInPong + "/" + discoverOutPing + " " +
- discoverOutPong + "/" + discoverInPing + " " +
- discoverInNeighbours + "/" + discoverOutFind + " " +
- discoverOutNeighbours + "/" + discoverInFind + " " +
+ messageStatistics.discoverInPong + "/" + messageStatistics.discoverOutPing + " " +
+ messageStatistics.discoverOutPong + "/" + messageStatistics.discoverInPing + " " +
+ messageStatistics.discoverInNeighbours + "/" + messageStatistics.discoverOutFindNode + " " +
+ messageStatistics.discoverOutNeighbours + "/" + messageStatistics.discoverInFindNode + " " +
((int) discoverMessageLatency.getAvrg()) + "ms" +
- ", p2p: " + p2pHandShake + "/" + p2pInHello + "/" + p2pOutHello + " " +
- ", tron: " + tronInMessage + "/" + tronOutMessage + " " +
+ ", p2p: " + p2pHandShake + "/" + messageStatistics.p2pInHello + "/" + messageStatistics.p2pOutHello + " " +
+ ", tron: " + messageStatistics.tronInMessage + "/" + messageStatistics.tronOutMessage + " " +
(wasDisconnected() ? "X " + disconnectTimes : "") +
(tronLastLocalDisconnectReason != null ? ("<=" + tronLastLocalDisconnectReason) : " ") +
- (tronLastRemoteDisconnectReason != null ? ("=>" + tronLastRemoteDisconnectReason) : " ");
+ (tronLastRemoteDisconnectReason != null ? ("=>" + tronLastRemoteDisconnectReason) : " ") +
+ ", tcp flow: " + tcpFlow.getTotalCount();
}
public class SimpleStatter {
@@ -261,4 +215,12 @@ public String getName() {
}
+ public boolean nodeIsHaveDataTransfer() {
+ return tcpFlow.getTotalCount() > MIN_DATA_LENGTH;
+ }
+
+ public void resetTcpFlow() {
+ tcpFlow.reset();
+ }
+
}
diff --git a/src/main/java/org/tron/common/overlay/discover/node/statistics/Reputation.java b/src/main/java/org/tron/common/overlay/discover/node/statistics/Reputation.java
new file mode 100644
index 00000000000..e02f447fd4a
--- /dev/null
+++ b/src/main/java/org/tron/common/overlay/discover/node/statistics/Reputation.java
@@ -0,0 +1,167 @@
+package org.tron.common.overlay.discover.node.statistics;
+
+import static java.lang.Math.min;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.tron.protos.Protocol.ReasonCode;
+
+public class Reputation {
+
+ public abstract class Score implements Comparable {
+
+ protected T t;
+
+ public Score(T t) {
+ this.t = t;
+ }
+
+ abstract int calculate(int baseScore);
+
+ public boolean isContinue() {
+ return true;
+ }
+
+ public int getOrder() {
+ return 0;
+ }
+
+ @Override
+ public int compareTo(Score score) {
+ if (getOrder() > score.getOrder()) {
+ return 1;
+ } else if (getOrder() < score.getOrder()) {
+ return -1;
+ }
+ return 0;
+ }
+ }
+
+ public class DiscoverScore extends Score {
+
+ public DiscoverScore(MessageStatistics messageStatistics) {
+ super(messageStatistics);
+ }
+
+ @Override
+ int calculate(int baseScore) {
+ int discoverReput = baseScore;
+ discoverReput +=
+ min(t.discoverInPong.getTotalCount(), 1) * (t.discoverOutPing.getTotalCount()
+ == t.discoverInPong.getTotalCount() ? 101 : 1);
+ discoverReput +=
+ min(t.discoverInNeighbours.getTotalCount(), 1) * (t.discoverOutFindNode.getTotalCount()
+ == t.discoverInNeighbours.getTotalCount() ? 10 : 1);
+ return discoverReput;
+ }
+
+ @Override
+ public boolean isContinue() {
+ return t.discoverOutPing.getTotalCount() == t.discoverInPong.getTotalCount()
+ && t.discoverInNeighbours.getTotalCount() <= t.discoverOutFindNode.getTotalCount();
+ }
+ }
+
+ public class TcpScore extends Score {
+
+ public TcpScore(NodeStatistics nodeStatistics) {
+ super(nodeStatistics);
+ }
+
+ @Override
+ int calculate(int baseScore) {
+ int reput = baseScore;
+ reput += t.p2pHandShake.getTotalCount() > 0 ? 10 : 0;
+ reput += min(t.tcpFlow.getTotalCount() / 10240, 20);
+ reput += t.messageStatistics.p2pOutPing.getTotalCount() == t.messageStatistics.p2pInPong
+ .getTotalCount() ? 10 : 0;
+ return reput;
+ }
+ }
+
+ public class DisConnectScore extends Score {
+
+ public DisConnectScore(NodeStatistics nodeStatistics) {
+ super(nodeStatistics);
+ }
+
+ @Override
+ int calculate(int baseScore) {
+ if (t.wasDisconnected()) {
+ if (t.getTronLastLocalDisconnectReason() == null
+ && t.getTronLastRemoteDisconnectReason() == null) {
+ // means connection was dropped without reporting any reason - bad
+ baseScore *= 0.8;
+ } else if (t.getTronLastLocalDisconnectReason() != ReasonCode.REQUESTED) {
+ // the disconnect was not initiated by discover mode
+ if (t.getTronLastRemoteDisconnectReason() == ReasonCode.TOO_MANY_PEERS
+ || t.getTronLastLocalDisconnectReason() == ReasonCode.TOO_MANY_PEERS
+ || t.getTronLastRemoteDisconnectReason() == ReasonCode.TOO_MANY_PEERS_WITH_SAME_IP
+ || t.getTronLastLocalDisconnectReason() == ReasonCode.TOO_MANY_PEERS_WITH_SAME_IP
+ || t.getTronLastRemoteDisconnectReason() == ReasonCode.DUPLICATE_PEER
+ || t.getTronLastLocalDisconnectReason() == ReasonCode.DUPLICATE_PEER
+ || t.getTronLastRemoteDisconnectReason() == ReasonCode.TIME_OUT
+ || t.getTronLastLocalDisconnectReason() == ReasonCode.TIME_OUT
+ || t.getTronLastRemoteDisconnectReason() == ReasonCode.PING_TIMEOUT
+ || t.getTronLastLocalDisconnectReason() == ReasonCode.PING_TIMEOUT
+ || t.getTronLastRemoteDisconnectReason() == ReasonCode.CONNECT_FAIL
+ || t.getTronLastLocalDisconnectReason() == ReasonCode.CONNECT_FAIL) {
+ // The peer is popular, but we were unlucky
+ baseScore *= 0.9;
+ } else if (t.getTronLastLocalDisconnectReason() == ReasonCode.RESET) {
+ baseScore *= 0.95;
+ } else if (t.getTronLastRemoteDisconnectReason() != ReasonCode.REQUESTED) {
+ // other disconnect reasons
+ baseScore *= 0.7;
+ }
+ }
+ }
+ if (t.getDisconnectTimes() > 20) {
+ return 0;
+ }
+ int score = baseScore - (int) Math.pow(2, t.getDisconnectTimes())
+ * (t.getDisconnectTimes() > 0 ? 10 : 0);
+ return score;
+ }
+ }
+
+ public class OtherScore extends Score {
+
+ public OtherScore(NodeStatistics nodeStatistics) {
+ super(nodeStatistics);
+ }
+
+ @Override
+ int calculate(int baseScore) {
+ baseScore += (int) t.discoverMessageLatency.getAvrg() == 0 ? 0
+ : min(1000 / t.discoverMessageLatency.getAvrg(), 20);
+ return baseScore;
+ }
+ }
+
+ private List scoreList = new ArrayList<>();
+
+ public Reputation(NodeStatistics nodeStatistics) {
+ Score discoverScore = new DiscoverScore(nodeStatistics.messageStatistics);
+ Score otherScore = new OtherScore(nodeStatistics);
+ Score tcpScore = new TcpScore(nodeStatistics);
+ Score disconnectScore = new DisConnectScore(nodeStatistics);
+
+ scoreList.add(discoverScore);
+ scoreList.add(tcpScore);
+ scoreList.add(otherScore);
+ scoreList.add(disconnectScore);
+ }
+
+ public int calculate() {
+ int scoreNumber = 0;
+ for (Score score : scoreList) {
+ scoreNumber = score.calculate(scoreNumber);
+ if (!score.isContinue()) {
+ break;
+ }
+ }
+ return scoreNumber > 0 ? scoreNumber : 0;
+ }
+
+}
diff --git a/src/main/java/org/tron/common/overlay/message/MessageCodec.java b/src/main/java/org/tron/common/overlay/message/MessageCodec.java
index 3e3428d57fd..16bba7c035e 100644
--- a/src/main/java/org/tron/common/overlay/message/MessageCodec.java
+++ b/src/main/java/org/tron/common/overlay/message/MessageCodec.java
@@ -3,14 +3,7 @@
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
-import java.io.IOException;
import java.util.List;
-import org.apache.commons.lang3.ArrayUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.spongycastle.util.encoders.Hex;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.tron.common.overlay.server.Channel;
@@ -28,11 +21,12 @@ public class MessageCodec extends ByteToMessageDecoder {
@Override
protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List out) throws Exception {
- byte[] encoded = new byte[buffer.readableBytes()];
+ int length = buffer.readableBytes();
+ byte[] encoded = new byte[length];
buffer.readBytes(encoded);
try {
Message msg = createMessage(encoded);
- channel.getNodeStatistics().tronInMessage.add();
+ channel.getNodeStatistics().tcpFlow.add(length);
out.add(msg);
} catch (Exception e) {
channel.processException(e);
diff --git a/src/main/java/org/tron/common/overlay/message/P2pMessageFactory.java b/src/main/java/org/tron/common/overlay/message/P2pMessageFactory.java
index 832a638d4c3..dec9d3080ef 100644
--- a/src/main/java/org/tron/common/overlay/message/P2pMessageFactory.java
+++ b/src/main/java/org/tron/common/overlay/message/P2pMessageFactory.java
@@ -28,7 +28,8 @@ public class P2pMessageFactory extends MessageFactory {
@Override
public P2pMessage create(byte[] data) throws Exception{
if (data.length <= 1){
- throw new P2pException(TypeEnum.MESSAGE_WITH_WRONG_LENGTH, "len=" + data.length);
+ throw new P2pException(TypeEnum.MESSAGE_WITH_WRONG_LENGTH, "len=" + data.length
+ + ", MessageType=" + (data.length == 1 ? data[0] : "unknow"));
}
try {
byte type = data[0];
diff --git a/src/main/java/org/tron/common/overlay/server/Channel.java b/src/main/java/org/tron/common/overlay/server/Channel.java
index 1cf1f42a3ae..8cdddf36baa 100644
--- a/src/main/java/org/tron/common/overlay/server/Channel.java
+++ b/src/main/java/org/tron/common/overlay/server/Channel.java
@@ -98,6 +98,8 @@ public class Channel {
private PeerStatistics peerStats = new PeerStatistics();
+ private boolean isTrustPeer;
+
public void init(ChannelPipeline pipeline, String remoteId, boolean discoveryMode,
ChannelManager channelManager, PeerConnectionDelegate peerDel) {
@@ -107,6 +109,8 @@ public void init(ChannelPipeline pipeline, String remoteId, boolean discoveryMod
isActive = remoteId != null && !remoteId.isEmpty();
+ startTime = System.currentTimeMillis();
+
//TODO: use config here
pipeline.addLast("readTimeoutHandler", new ReadTimeoutHandler(60, TimeUnit.SECONDS));
pipeline.addLast(stats.tcp);
@@ -131,6 +135,7 @@ public void init(ChannelPipeline pipeline, String remoteId, boolean discoveryMod
}
public void publicHandshakeFinished(ChannelHandlerContext ctx, HelloMessage msg) {
+ isTrustPeer = channelManager.getTrustPeers().containsKey(getInetAddress());
ctx.pipeline().remove(handshakeHandler);
msgQueue.activate(ctx);
ctx.pipeline().addLast("messageCodec", messageCodec);
@@ -260,6 +265,10 @@ public boolean isProtocolsInitialized() {
return tronState.ordinal() > TronState.INIT.ordinal();
}
+ public boolean isTrustPeer() {
+ return isTrustPeer;
+ }
+
@Override
public boolean equals(Object o) {
@@ -291,5 +300,6 @@ public int hashCode() {
public String toString() {
return String.format("%s | %s", inetSocketAddress, getPeerId());
}
+
}
diff --git a/src/main/java/org/tron/common/overlay/server/ChannelManager.java b/src/main/java/org/tron/common/overlay/server/ChannelManager.java
index 3123e536a78..6109c014669 100644
--- a/src/main/java/org/tron/common/overlay/server/ChannelManager.java
+++ b/src/main/java/org/tron/common/overlay/server/ChannelManager.java
@@ -30,8 +30,6 @@ public class ChannelManager {
private static final Logger logger = LoggerFactory.getLogger("ChannelManager");
- private static final int inboundConnectionBanTimeout = 30 * 1000;
-
private final Map activePeers = new ConcurrentHashMap<>();
private Cache badPeers = CacheBuilder.newBuilder().maximumSize(10000)
diff --git a/src/main/java/org/tron/common/overlay/server/HandshakeHandler.java b/src/main/java/org/tron/common/overlay/server/HandshakeHandler.java
index 3a9668ba5d1..ffa18d2e86c 100644
--- a/src/main/java/org/tron/common/overlay/server/HandshakeHandler.java
+++ b/src/main/java/org/tron/common/overlay/server/HandshakeHandler.java
@@ -37,6 +37,7 @@
import org.tron.common.overlay.message.P2pMessageFactory;
import org.tron.core.config.args.Args;
import org.tron.core.db.Manager;
+import org.tron.core.net.message.MessageTypes;
import org.tron.core.net.peer.PeerConnection;
import org.tron.protos.Protocol.ReasonCode;
@@ -119,7 +120,7 @@ private void sendHelloMsg(ChannelHandlerContext ctx, long time){
HelloMessage message = new HelloMessage(nodeManager.getPublicHomeNode(), time,
manager.getGenesisBlockId(), manager.getSolidBlockId(), manager.getHeadBlockId());
ctx.writeAndFlush(message.getSendData());
- channel.getNodeStatistics().p2pOutHello.add();
+ channel.getNodeStatistics().messageStatistics.addTcpOutMessage(message);
logger.info("Handshake Send to {}, {} ", ctx.channel().remoteAddress(), message);
}
@@ -136,7 +137,7 @@ private void handleHelloMsg(ChannelHandlerContext ctx, HelloMessage msg) {
if (msg.getVersion() != Args.getInstance().getNodeP2pVersion()) {
logger.info("Peer {} different p2p version, peer->{}, me->{}",
ctx.channel().remoteAddress(), msg.getVersion(), Args.getInstance().getNodeP2pVersion());
- channel.disconnect(ReasonCode.INCOMPATIBLE_PROTOCOL);
+ channel.disconnect(ReasonCode.INCOMPATIBLE_VERSION);
return;
}
@@ -156,7 +157,7 @@ private void handleHelloMsg(ChannelHandlerContext ctx, HelloMessage msg) {
((PeerConnection)channel).setHelloMessage(msg);
- channel.getNodeStatistics().p2pInHello.add();
+ channel.getNodeStatistics().messageStatistics.addTcpInMessage(msg);
channel.publicHandshakeFinished(ctx, msg);
if (!channelManager.processPeer(channel)) {
diff --git a/src/main/java/org/tron/common/overlay/server/MessageQueue.java b/src/main/java/org/tron/common/overlay/server/MessageQueue.java
index 6ef4cf1dd22..20992d75c63 100644
--- a/src/main/java/org/tron/common/overlay/server/MessageQueue.java
+++ b/src/main/java/org/tron/common/overlay/server/MessageQueue.java
@@ -91,6 +91,7 @@ public boolean sendMessage(Message msg) {
return false;
}
logger.info("Send to {}, {} ", ctx.channel().remoteAddress(), msg);
+ channel.getNodeStatistics().messageStatistics.addTcpOutMessage(msg);
sendTime = System.currentTimeMillis();
if (msg.getAnswerMessage() != null){
requestQueue.add(new MessageRoundtrip(msg));
@@ -102,6 +103,7 @@ public boolean sendMessage(Message msg) {
public void receivedMessage(Message msg){
logger.info("Receive from {}, {}", ctx.channel().remoteAddress(), msg);
+ channel.getNodeStatistics().messageStatistics.addTcpInMessage(msg);
MessageRoundtrip messageRoundtrip = requestQueue.peek();
if (messageRoundtrip != null && messageRoundtrip.getMsg().getAnswerMessage() == msg.getClass()){
requestQueue.remove();
diff --git a/src/main/java/org/tron/common/overlay/server/P2pHandler.java b/src/main/java/org/tron/common/overlay/server/P2pHandler.java
index 993cf177e35..0e37a53c047 100644
--- a/src/main/java/org/tron/common/overlay/server/P2pHandler.java
+++ b/src/main/java/org/tron/common/overlay/server/P2pHandler.java
@@ -26,11 +26,16 @@
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
+import org.tron.common.overlay.discover.node.statistics.MessageStatistics;
+import org.tron.common.overlay.discover.node.statistics.NodeStatistics;
import org.tron.common.overlay.message.DisconnectMessage;
import org.tron.common.overlay.message.P2pMessage;
+import org.tron.protos.Protocol.ReasonCode;
+@Slf4j
@Component
@Scope("prototype")
public class P2pHandler extends SimpleChannelInboundHandler {
@@ -65,12 +70,26 @@ public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
public void channelRead0(final ChannelHandlerContext ctx, P2pMessage msg) throws InterruptedException {
msgQueue.receivedMessage(msg);
-
+ MessageStatistics messageStatistics = channel.getNodeStatistics().messageStatistics;
switch (msg.getType()) {
case P2P_PING:
+ int count = messageStatistics.p2pInPing.getCount(10);
+ if (count > 3){
+ logger.warn("TCP attack found: {} with ping count({})", ctx.channel().remoteAddress(), count);
+ channel.disconnect(ReasonCode.BAD_PROTOCOL);
+ return;
+ }
msgQueue.sendMessage(PONG_MESSAGE);
break;
case P2P_PONG:
+ if (messageStatistics.p2pInPong.getTotalCount() > messageStatistics.p2pOutPing.getTotalCount()){
+ logger.warn("TCP attack found: {} with ping count({}), pong count({})",
+ ctx.channel().remoteAddress(),
+ messageStatistics.p2pOutPing.getTotalCount(),
+ messageStatistics.p2pInPong.getTotalCount());
+ channel.disconnect(ReasonCode.BAD_PROTOCOL);
+ return;
+ }
hasPing = false;
channel.getNodeStatistics().lastPongReplyTime.set(System.currentTimeMillis());
channel.getPeerStats().pong(sendPingTime);
diff --git a/src/main/java/org/tron/common/overlay/server/PeerConnectionCheckService.java b/src/main/java/org/tron/common/overlay/server/PeerConnectionCheckService.java
new file mode 100644
index 00000000000..cf86f63729e
--- /dev/null
+++ b/src/main/java/org/tron/common/overlay/server/PeerConnectionCheckService.java
@@ -0,0 +1,122 @@
+package org.tron.common.overlay.server;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.PostConstruct;
+import javax.annotation.PreDestroy;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.tron.common.overlay.discover.node.statistics.NodeStatistics;
+import org.tron.common.utils.CollectionUtils;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.net.peer.PeerConnection;
+import org.tron.protos.Protocol.ReasonCode;
+
+@Slf4j
+@Service
+public class PeerConnectionCheckService {
+
+ public static final long CHECK_TIME = 5 * 60 * 1000L;
+ private double disconnectNumberFactor = Args.getInstance().getDisconnectNumberFactor();
+ private double maxConnectNumberFactor = Args.getInstance().getMaxConnectNumberFactor();
+
+ @Autowired
+ private SyncPool pool;
+
+ @Autowired
+ private ChannelManager channelManager;
+
+ @Autowired
+ private Manager manager;
+
+ private ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(2,
+ r -> new Thread(r, "check-peer-connect"));
+
+ @PostConstruct
+ public void check() {
+ logger.info("start the PeerConnectionCheckService");
+ scheduledExecutorService
+ .scheduleWithFixedDelay(new CheckDataTransferTask(), 5, 5, TimeUnit.MINUTES);
+ if (Args.getInstance().isOpenFullTcpDisconnect()) {
+ scheduledExecutorService
+ .scheduleWithFixedDelay(new CheckConnectNumberTask(), 4, 1, TimeUnit.MINUTES);
+ }
+ }
+
+ @PreDestroy
+ public void destroy() {
+ scheduledExecutorService.shutdown();
+ }
+
+ private class CheckDataTransferTask implements Runnable {
+
+ @Override
+ public void run() {
+ List peerConnectionList = pool.getActivePeers();
+ List willDisconnectPeerList = new ArrayList<>();
+ for (PeerConnection peerConnection : peerConnectionList) {
+ NodeStatistics nodeStatistics = peerConnection.getNodeStatistics();
+ if (!nodeStatistics.nodeIsHaveDataTransfer()
+ && System.currentTimeMillis() - peerConnection.getStartTime() >= CHECK_TIME
+ && !peerConnection.isTrustPeer()
+ && !nodeStatistics.isPredefined()) {
+ //&& !peerConnection.isActive()
+ //if xxx minutes not have data transfer,disconnect the peer,exclude trust peer and active peer
+ willDisconnectPeerList.add(peerConnection);
+ }
+ nodeStatistics.resetTcpFlow();
+ }
+ if (!willDisconnectPeerList.isEmpty() && peerConnectionList.size()
+ > Args.getInstance().getNodeMaxActiveNodes() * maxConnectNumberFactor) {
+ Collections.shuffle(willDisconnectPeerList);
+ for (int i = 0; i < willDisconnectPeerList.size() * disconnectNumberFactor; i++) {
+ logger.error("{} not have data transfer, disconnect the peer",
+ willDisconnectPeerList.get(i).getInetAddress());
+ willDisconnectPeerList.get(i).disconnect(ReasonCode.TOO_MANY_PEERS);
+ }
+ }
+// else if (willDisconnectPeerList.size() == peerConnectionList.size()) {
+// for (int i = 0; i < willDisconnectPeerList.size(); i++) {
+// logger.error("all peer not have data transfer, disconnect the peer {}",
+// willDisconnectPeerList.get(i).getInetAddress());
+// willDisconnectPeerList.get(i).disconnect(ReasonCode.RESET);
+// willDisconnectPeerList.get(i).cleanAll();
+// }
+// }
+ }
+ }
+
+ private class CheckConnectNumberTask implements Runnable {
+
+ @Override
+ public void run() {
+ if (pool.getActivePeers().size() >= Args.getInstance().getNodeMaxActiveNodes()) {
+ logger.warn("connection pool is full");
+ List peerList = new ArrayList<>();
+ for (PeerConnection peer : pool.getActivePeers()) {
+ if (!peer.isTrustPeer() && !peer.getNodeStatistics().isPredefined()) {
+ peerList.add(peer);
+ }
+ }
+ if (peerList.size() >= 2) {
+ peerList.sort(
+ Comparator.comparingInt((PeerConnection o) -> o.getNodeStatistics().getReputation()));
+ peerList = CollectionUtils.truncateRandom(peerList, 2, 1);
+ }
+ for (PeerConnection peerConnection : peerList) {
+ logger.warn("connection pool is full, disconnect the peer : {}",
+ peerConnection.getInetAddress());
+ peerConnection.disconnect(ReasonCode.RESET);
+ }
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/tron/common/overlay/server/SyncPool.java b/src/main/java/org/tron/common/overlay/server/SyncPool.java
index b701a3c0f37..c29e9200520 100644
--- a/src/main/java/org/tron/common/overlay/server/SyncPool.java
+++ b/src/main/java/org/tron/common/overlay/server/SyncPool.java
@@ -101,7 +101,7 @@ public void init(PeerConnectionDelegate peerDel) {
} catch (Throwable t) {
logger.error("Exception in sync worker", t);
}
- }, 30, 3600, TimeUnit.MILLISECONDS);
+ }, 30000, 3600, TimeUnit.MILLISECONDS);
logExecutor.scheduleWithFixedDelay(() -> {
try {
diff --git a/src/main/java/org/tron/common/runtime/DepositController.java b/src/main/java/org/tron/common/runtime/DepositController.java
deleted file mode 100644
index 0a0a75b1289..00000000000
--- a/src/main/java/org/tron/common/runtime/DepositController.java
+++ /dev/null
@@ -1,165 +0,0 @@
-package org.tron.common.runtime;
-
-import static org.tron.common.runtime.utils.MUtil.transfer;
-
-import org.spongycastle.util.encoders.Hex;
-import org.tron.common.runtime.vm.program.ProgramResult;
-import org.tron.common.runtime.vm.program.invoke.ProgramInvokeFactory;
-import org.tron.common.runtime.vm.program.invoke.ProgramInvokeFactoryImpl;
-import org.tron.common.storage.Deposit;
-import org.tron.common.storage.DepositImpl;
-import org.tron.common.storage.DepositQueue;
-import org.tron.common.storage.Key;
-import org.tron.common.storage.Type;
-import org.tron.common.storage.Value;
-import org.tron.core.capsule.BlockCapsule;
-import org.tron.core.capsule.TransactionCapsule;
-import org.tron.core.db.Manager;
-import org.tron.core.db.TransactionTrace;
-import org.tron.core.exception.ContractExeException;
-import org.tron.core.exception.ContractValidateException;
-
-/**
- * Deposit controller : process pre transaction , block, query contract and etc..
- *
- * @author Guo Yonggang
- * @since 27.04.2018
- */
-public class DepositController {
-
- private Manager dbManager;
- private ProgramInvokeFactory programInvokeFactory = new ProgramInvokeFactoryImpl();
- ;
- private static int QUEUE_SIZE = 4;
- private DepositQueue depositQueue = new DepositQueue<>(QUEUE_SIZE);
-
- private DepositController(Manager dbManager) {
- this.dbManager = dbManager;
- }
-
- private Deposit getLastDeposit() {
- if (depositQueue.isEmpty()) {
- return null;
- }
- return depositQueue.last();
- }
-
- /**
- * @API roll back one block's data
- */
- public Deposit rollback() {
- Deposit deposit = depositQueue.removeLast();
- Deposit lastDeposit = getLastDeposit();
- if (lastDeposit != null) {
- lastDeposit.setNextDeposit(null);
- }
- return deposit;
- }
-
- /**
- * The trx may be invalid due to check with not newest data.
- */
- public int preProcessTransaction(TransactionCapsule trxCap)
- throws ContractValidateException, ContractExeException {
- DepositImpl deposit = DepositImpl.createRoot(dbManager);
- Runtime runtime = new Runtime(trxCap.getInstance(), deposit, programInvokeFactory);
- runtime.init();
- runtime.execute();
- runtime.go();
- ProgramResult programResult = runtime.getResult();
- if (programResult.getException() != null) {
- return -1;
- }
-
- return 0;
- }
-
- /**
- * @param block
- * @return
- */
- public int processBlock(BlockCapsule block)
- throws ContractValidateException, ContractExeException {
- Deposit lastDeposit = getLastDeposit();
- Deposit currentDeposit;
- if (lastDeposit == null) {
- currentDeposit = DepositImpl.createRoot(dbManager);
- } else {
- currentDeposit = lastDeposit.newDepositNext();
- }
-
- depositQueue.put(currentDeposit);
- for (TransactionCapsule trxCap : block.getTransactions()) {
- Deposit trxDeposit = currentDeposit.newDepositChild();
- Runtime runtime = new Runtime(new TransactionTrace(trxCap), block.getInstance(), trxDeposit,
- programInvokeFactory);
- runtime.init();
- runtime.execute();
- runtime.go();
-
- ProgramResult programResult = runtime.getResult();
- if (programResult.getException() != null) {
- rollback();
- return -1;
- }
-
- Key key = Key.create(trxCap.getTransactionId().getBytes());
- Value value = Value.create(trxCap.getData(), Type.VALUE_TYPE_CREATE);
- currentDeposit.putTransaction(key, value);
- }
-
- Key bKey = Key.create(block.getBlockId().getBytes());
- Value bValue = Value.create(block.getData(), Type.VALUE_TYPE_CREATE);
- currentDeposit.putBlock(bKey, bValue);
-
- // reward witness node
- byte[] foundAddress = Hex.decode("FF00");
- byte[] coinBase = block.getWitnessAddress().toByteArray();
- transfer(currentDeposit, foundAddress, coinBase, 36 * 1000000);
-
- if (depositQueue.size() > QUEUE_SIZE) {
- Deposit deposit = depositQueue.get();
- deposit.commit();
- depositQueue.peek().setPrevDeposit(null);
- }
-
- return 0;
- }
-
- /**
- *
- * @param trxCap
- * @return
- */
- public ProgramResult processConstantTransaction(TransactionCapsule trxCap)
- throws ContractValidateException, ContractExeException {
- DepositImpl deposit = DepositImpl.createRoot(dbManager);
- Runtime runtime = new Runtime(trxCap.getInstance(), programInvokeFactory, deposit);
- runtime.init();
- runtime.execute();
- runtime.go();
- ProgramResult programResult = runtime.getResult();
- return programResult;
- }
-
- public ProgramInvokeFactory getProgramInvokeFactory() {
- return programInvokeFactory;
- }
-
- /**
- * Single instance
- */
- private static DepositController instance = null;
-
- public static DepositController create(Manager dbManager) {
- if (instance != null) {
- return instance;
- }
- instance = new DepositController(dbManager);
- return instance;
- }
-
- public static DepositController getInstance() {
- return instance;
- }
-}
diff --git a/src/main/java/org/tron/common/runtime/Runtime.java b/src/main/java/org/tron/common/runtime/Runtime.java
index 1e58f2ff6b4..c741030683f 100644
--- a/src/main/java/org/tron/common/runtime/Runtime.java
+++ b/src/main/java/org/tron/common/runtime/Runtime.java
@@ -3,10 +3,13 @@
import static com.google.common.primitives.Longs.max;
import static com.google.common.primitives.Longs.min;
import static org.apache.commons.lang3.ArrayUtils.isEmpty;
-import static org.tron.common.runtime.vm.program.InternalTransaction.ExecuterType.ET_CONSTANT_TYPE;
-import static org.tron.common.runtime.vm.program.InternalTransaction.ExecuterType.ET_NORMAL_TYPE;
-import static org.tron.common.runtime.vm.program.InternalTransaction.ExecuterType.ET_PRE_TYPE;
-import static org.tron.common.runtime.vm.program.InternalTransaction.ExecuterType.ET_UNKNOWN_TYPE;
+import static org.tron.common.runtime.utils.MUtil.transfer;
+import static org.tron.common.runtime.vm.VMUtils.saveProgramTraceFile;
+import static org.tron.common.runtime.vm.VMUtils.zipAndEncode;
+import static org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType.ET_CONSTANT_TYPE;
+import static org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType.ET_NORMAL_TYPE;
+import static org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType.ET_PRE_TYPE;
+import static org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType.ET_UNKNOWN_TYPE;
import static org.tron.common.runtime.vm.program.InternalTransaction.TrxType.TRX_CONTRACT_CALL_TYPE;
import static org.tron.common.runtime.vm.program.InternalTransaction.TrxType.TRX_CONTRACT_CREATION_TYPE;
import static org.tron.common.runtime.vm.program.InternalTransaction.TrxType.TRX_PRECOMPILED_TYPE;
@@ -14,16 +17,18 @@
import com.google.protobuf.ByteString;
import java.math.BigInteger;
+import java.util.Arrays;
import java.util.List;
import java.util.Objects;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import org.tron.common.runtime.config.SystemProperties;
import org.tron.common.runtime.vm.PrecompiledContracts;
import org.tron.common.runtime.vm.VM;
import org.tron.common.runtime.vm.program.InternalTransaction;
+import org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType;
import org.tron.common.runtime.vm.program.Program;
import org.tron.common.runtime.vm.program.Program.OutOfResourceException;
import org.tron.common.runtime.vm.program.ProgramPrecompile;
@@ -37,15 +42,15 @@
import org.tron.core.actuator.Actuator;
import org.tron.core.actuator.ActuatorFactory;
import org.tron.core.capsule.AccountCapsule;
-import org.tron.core.capsule.BytesCapsule;
import org.tron.core.capsule.ContractCapsule;
import org.tron.core.capsule.TransactionCapsule;
-import org.tron.core.db.TransactionTrace;
import org.tron.core.config.Parameter.ChainConstant;
-import org.tron.core.db.CpuProcessor;
+import org.tron.core.db.EnergyProcessor;
+import org.tron.core.db.StorageMarket;
+import org.tron.core.db.TransactionTrace;
import org.tron.core.exception.ContractExeException;
import org.tron.core.exception.ContractValidateException;
-import org.tron.core.exception.TronException;
+import org.tron.core.exception.OutOfSlotTimeException;
import org.tron.protos.Contract;
import org.tron.protos.Contract.CreateSmartContract;
import org.tron.protos.Contract.TriggerSmartContract;
@@ -56,15 +61,11 @@
import org.tron.protos.Protocol.Transaction;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
-/**
- * @author Guo Yonggang
- * @since 28.04.2018
- */
+@Slf4j(topic = "Runtime")
public class Runtime {
- private static final Logger logger = LoggerFactory.getLogger("execute");
- SystemProperties config;
+ private SystemProperties config = SystemProperties.getInstance();
private Transaction trx;
private Block block = null;
@@ -73,7 +74,8 @@ public class Runtime {
private String runtimeError;
private boolean readyToExecute = false;
- private CpuProcessor cpuProcessor = null;
+ private EnergyProcessor energyProcessor = null;
+ private StorageMarket storageMarket = null;
PrecompiledContracts.PrecompiledContract precompiledContract = null;
private ProgramResult result = new ProgramResult();
@@ -82,7 +84,7 @@ public class Runtime {
private Program program = null;
private InternalTransaction.TrxType trxType = TRX_UNKNOWN_TYPE;
- private InternalTransaction.ExecuterType executerType = ET_UNKNOWN_TYPE;
+ private ExecutorType executorType = ET_UNKNOWN_TYPE;
//tx trace
private TransactionTrace trace;
@@ -98,14 +100,15 @@ public Runtime(TransactionTrace trace, Block block, Deposit deosit,
if (Objects.nonNull(block)) {
this.block = block;
- this.executerType = ET_NORMAL_TYPE;
+ this.executorType = ET_NORMAL_TYPE;
} else {
this.block = Block.newBuilder().build();
- this.executerType = ET_PRE_TYPE;
+ this.executorType = ET_PRE_TYPE;
}
this.deposit = deosit;
this.programInvokeFactory = programInvokeFactory;
- this.cpuProcessor = new CpuProcessor(deposit.getDbManager());
+ this.energyProcessor = new EnergyProcessor(deposit.getDbManager());
+ this.storageMarket = new StorageMarket(deposit.getDbManager());
Transaction.Contract.ContractType contractType = this.trx.getRawData().getContract(0).getType();
switch (contractType.getNumber()) {
@@ -123,11 +126,12 @@ public Runtime(TransactionTrace trace, Block block, Deposit deosit,
/**
* For pre trx run
*/
+ @Deprecated
public Runtime(Transaction tx, DepositImpl deposit, ProgramInvokeFactory programInvokeFactory) {
this.trx = tx;
this.deposit = deposit;
this.programInvokeFactory = programInvokeFactory;
- this.executerType = ET_PRE_TYPE;
+ this.executorType = ET_PRE_TYPE;
Transaction.Contract.ContractType contractType = tx.getRawData().getContract(0).getType();
switch (contractType.getNumber()) {
case Transaction.Contract.ContractType.TriggerSmartContract_VALUE:
@@ -145,16 +149,43 @@ public Runtime(Transaction tx, DepositImpl deposit, ProgramInvokeFactory program
/**
* For constant trx
*/
+ @Deprecated
public Runtime(Transaction tx, ProgramInvokeFactory programInvokeFactory, Deposit deposit) {
trx = tx;
this.deposit = deposit;
this.programInvokeFactory = programInvokeFactory;
- executerType = ET_CONSTANT_TYPE;
+ executorType = ET_CONSTANT_TYPE;
trxType = TRX_CONTRACT_CALL_TYPE;
}
+ /**
+ * For constant trx with latest block.
+ */
+ public Runtime(Transaction tx, Block block, DepositImpl deposit,
+ ProgramInvokeFactory programInvokeFactory) {
+ this.trx = tx;
+ this.deposit = deposit;
+ this.programInvokeFactory = programInvokeFactory;
+ this.executorType = ET_PRE_TYPE;
+ this.block = block;
+ this.energyProcessor = new EnergyProcessor(deposit.getDbManager());
+ this.storageMarket = new StorageMarket(deposit.getDbManager());
+ Transaction.Contract.ContractType contractType = tx.getRawData().getContract(0).getType();
+ switch (contractType.getNumber()) {
+ case Transaction.Contract.ContractType.TriggerSmartContract_VALUE:
+ trxType = TRX_CONTRACT_CALL_TYPE;
+ break;
+ case Transaction.Contract.ContractType.CreateSmartContract_VALUE:
+ trxType = TRX_CONTRACT_CREATION_TYPE;
+ break;
+ default:
+ trxType = TRX_PRECOMPILED_TYPE;
+ }
+ }
+
+
public void precompiled() throws ContractValidateException, ContractExeException {
TransactionCapsule trxCap = new TransactionCapsule(trx);
final List actuatorList = ActuatorFactory
@@ -169,20 +200,22 @@ public void precompiled() throws ContractValidateException, ContractExeException
/**
*/
public void init() {
-
- switch (trxType) {
- case TRX_PRECOMPILED_TYPE:
- readyToExecute = true;
- break;
- case TRX_CONTRACT_CREATION_TYPE:
- case TRX_CONTRACT_CALL_TYPE:
- if (!curCPULimitReachedBlockCPULimit()) {
- readyToExecute = true;
- }
- break;
- default:
- break;
- }
+ readyToExecute = true;
+ // switch (trxType) {
+ // case TRX_PRECOMPILED_TYPE:
+ // readyToExecute = true;
+ // break;
+ // case TRX_CONTRACT_CREATION_TYPE:
+ // case TRX_CONTRACT_CALL_TYPE:
+ // // if (!curENERGYLimitReachedBlockENERGYLimit()) {
+ // // readyToExecute = true;
+ // // }
+ // readyToExecute = true;
+ // break;
+ // default:
+ // readyToExecute = true;
+ // break;
+ // }
}
@@ -191,7 +224,7 @@ public BigInteger getBlockCPULeftInUs() {
// insure block is not null
BigInteger curBlockHaveElapsedCPUInUs =
BigInteger.valueOf(
- 1000 * (DateTime.now().getMillis() - block.getBlockHeader().getRawDataOrBuilder()
+ 1000 * (DateTime.now().getMillis() - block.getBlockHeader().getRawData()
.getTimestamp())); // us
BigInteger curBlockCPULimitInUs = BigInteger.valueOf((long)
(1000 * ChainConstant.BLOCK_PRODUCED_INTERVAL * 0.5
@@ -204,10 +237,10 @@ public BigInteger getBlockCPULeftInUs() {
public boolean curCPULimitReachedBlockCPULimit() {
- if (executerType == ET_NORMAL_TYPE) {
+ if (executorType == ET_NORMAL_TYPE) {
BigInteger blockCPULeftInUs = getBlockCPULeftInUs();
BigInteger oneTxCPULimitInUs = BigInteger
- .valueOf(Constant.CPU_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT);
+ .valueOf(Constant.MAX_CPU_TIME_OF_ONE_TX);
// TODO get from account
BigInteger increasedStorageLimit = BigInteger.valueOf(10000000);
@@ -224,44 +257,6 @@ public boolean curCPULimitReachedBlockCPULimit() {
return false;
}
- private long getAccountCPULimitInUs(AccountCapsule creator,
- CreateSmartContract contract) {
-
- CpuProcessor cpuProcessor = new CpuProcessor(this.deposit.getDbManager());
- long cpuFromFrozen = cpuProcessor.calculateGlobalCpuLimit(
- creator.getAccountResource().getFrozenBalanceForCpu().getFrozenBalance());
- logger.info("cpuFromFrozen: {}", cpuFromFrozen);
-
- long cpuFromTRX = Constant.CPU_IN_US_PER_TRX * contract.getCpuLimitInTrx();
-
- return max(cpuFromFrozen, cpuFromTRX); // us
-
- }
-
- private long getAccountCPULimitInUs(AccountCapsule creator, AccountCapsule sender,
- TriggerSmartContract contract) {
-
- CpuProcessor cpuProcessor = new CpuProcessor(this.deposit.getDbManager());
- SmartContract smartContract = this.deposit
- .getContract(contract.getContractAddress().toByteArray()).getInstance();
- long consumeUserResourcePercent = smartContract.getConsumeUserResourcePercent();
-
- long senderCpuFromTrx = Constant.CPU_IN_US_PER_TRX * contract.getCpuLimitInTrx();
- long senderCpuFromFrozen = cpuProcessor.calculateGlobalCpuLimit(
- sender.getAccountResource().getFrozenBalanceForCpu().getFrozenBalance());
- long creatorCpuFromFrozen = cpuProcessor.calculateGlobalCpuLimit(
- creator.getAccountResource().getFrozenBalanceForCpu().getFrozenBalance());
- long senderCpuMax = max(senderCpuFromTrx, senderCpuFromFrozen);
- if (consumeUserResourcePercent >= 1.0) {
- return senderCpuMax;
- } else if (consumeUserResourcePercent <= 0.0) {
- return creatorCpuFromFrozen;
- } else {
- return max(min(creatorCpuFromFrozen / (1 - consumeUserResourcePercent),
- senderCpuMax / consumeUserResourcePercent), consumeUserResourcePercent);
- }
- }
-
public void execute() throws ContractValidateException, ContractExeException {
if (!readyToExecute) {
@@ -282,62 +277,77 @@ public void execute() throws ContractValidateException, ContractExeException {
}
}
- private void call()
- throws ContractExeException {
- Contract.TriggerSmartContract contract = ContractCapsule.getTriggerContractFromTransaction(trx);
- if (contract == null) {
- return;
+ private long getEnergyLimit(AccountCapsule account, long feeLimit, long callValue) {
+
+ long SUN_PER_ENERGY = deposit.getDbManager().getDynamicPropertiesStore().getEnergyFee() == 0
+ ? Constant.SUN_PER_ENERGY :
+ deposit.getDbManager().getDynamicPropertiesStore().getEnergyFee();
+ // can change the calc way
+ long leftEnergyFromFreeze = energyProcessor.getAccountLeftEnergyFromFreeze(account);
+ callValue = max(callValue, 0);
+ long energyFromBalance = Math
+ .floorDiv(max(account.getBalance() - callValue, 0), SUN_PER_ENERGY);
+
+ long energyFromFeeLimit;
+ long totalBalanceForEnergyFreeze = account.getAccountResource().getFrozenBalanceForEnergy()
+ .getFrozenBalance();
+ if (0 == totalBalanceForEnergyFreeze) {
+ energyFromFeeLimit =
+ feeLimit / SUN_PER_ENERGY;
+ } else {
+ long totalEnergyFromFreeze = energyProcessor
+ .calculateGlobalEnergyLimit(totalBalanceForEnergyFreeze);
+ long leftBalanceForEnergyFreeze = getEnergyFee(totalBalanceForEnergyFreeze,
+ leftEnergyFromFreeze,
+ totalEnergyFromFreeze);
+
+ if (leftBalanceForEnergyFreeze >= feeLimit) {
+ energyFromFeeLimit = BigInteger.valueOf(totalEnergyFromFreeze)
+ .multiply(BigInteger.valueOf(feeLimit))
+ .divide(BigInteger.valueOf(totalBalanceForEnergyFreeze)).longValue();
+ } else {
+ energyFromFeeLimit = Math
+ .addExact(leftEnergyFromFreeze,
+ (feeLimit - leftBalanceForEnergyFreeze) / SUN_PER_ENERGY);
+ }
}
- byte[] contractAddress = contract.getContractAddress().toByteArray();
- byte[] code = this.deposit.getCode(contractAddress);
- if (isEmpty(code)) {
+ return min(Math.addExact(leftEnergyFromFreeze, energyFromBalance), energyFromFeeLimit);
+ }
- } else {
+ private long getEnergyLimit(AccountCapsule creator, AccountCapsule caller,
+ TriggerSmartContract contract, long feeLimit, long callValue) {
- AccountCapsule sender = this.deposit.getAccount(contract.getOwnerAddress().toByteArray());
- AccountCapsule creator = this.deposit.getAccount(
- this.deposit.getContract(contractAddress).getInstance()
- .getOriginAddress().toByteArray());
+ long callerEnergyLimit = getEnergyLimit(caller, feeLimit, callValue);
+ if (Arrays.equals(creator.getAddress().toByteArray(), caller.getAddress().toByteArray())) {
+ return callerEnergyLimit;
+ }
- long thisTxCPULimitInUs;
- long accountCPULimitInUs = getAccountCPULimitInUs(creator, sender, contract);
- if (executerType == ET_NORMAL_TYPE) {
- long blockCPULeftInUs = getBlockCPULeftInUs().longValue();
- thisTxCPULimitInUs = min(accountCPULimitInUs, blockCPULeftInUs,
- Constant.CPU_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT);
- } else {
- thisTxCPULimitInUs = min(accountCPULimitInUs,
- Constant.CPU_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT);
- }
+ // creatorEnergyFromFreeze
+ long creatorEnergyLimit = energyProcessor.getAccountLeftEnergyFromFreeze(creator);
- long vmStartInUs = System.nanoTime() / 1000;
- long vmShouldEndInUs = vmStartInUs + thisTxCPULimitInUs;
+ SmartContract smartContract = this.deposit
+ .getContract(contract.getContractAddress().toByteArray()).getInstance();
+ long consumeUserResourcePercent = smartContract.getConsumeUserResourcePercent();
- ProgramInvoke programInvoke = programInvokeFactory
- .createProgramInvoke(TRX_CONTRACT_CALL_TYPE, executerType, trx,
- block, deposit, vmStartInUs, vmShouldEndInUs);
- this.vm = new VM(config);
- InternalTransaction internalTransaction = new InternalTransaction(trx);
- this.program = new Program(null, code, programInvoke, internalTransaction, config);
- }
+ consumeUserResourcePercent = max(0, min(consumeUserResourcePercent, 100));
- program.getResult().setContractAddress(contractAddress);
- //transfer from callerAddress to targetAddress according to callValue
- byte[] callerAddress = contract.getOwnerAddress().toByteArray();
- byte[] callValue = contract.getCallValue().toByteArray();
- if (null != callValue && callValue.length != 0) {
- long callValueLong = new BigInteger(Hex.toHexString(callValue), 16).longValue();
- this.deposit.addBalance(callerAddress, -callValueLong);
- this.deposit.addBalance(contractAddress, callValueLong);
+ if (consumeUserResourcePercent <= 0) {
+ return creatorEnergyLimit;
}
+ if (creatorEnergyLimit * consumeUserResourcePercent
+ >= (100 - consumeUserResourcePercent) * callerEnergyLimit) {
+ return 100 * Math.floorDiv(callerEnergyLimit, consumeUserResourcePercent);
+ } else {
+ return Math.addExact(callerEnergyLimit, creatorEnergyLimit);
+ }
}
/*
**/
private void create()
- throws ContractExeException {
+ throws ContractExeException, ContractValidateException {
CreateSmartContract contract = ContractCapsule.getSmartContractFromTransaction(trx);
SmartContract newSmartContract = contract.getNewContract();
@@ -345,52 +355,58 @@ private void create()
byte[] contractAddress = Wallet.generateContractAddress(trx);
byte[] ownerAddress = contract.getOwnerAddress().toByteArray();
- // insure one owner just have one contract
- if (this.deposit.getContractByNormalAccount(ownerAddress) != null) {
- logger.error("Trying to create second contract with one account: address: " + Wallet
- .encode58Check(ownerAddress));
- return;
+ long percent = contract.getNewContract().getConsumeUserResourcePercent();
+ if (percent < 0 || percent > 100) {
+ throw new ContractExeException("percent must be >= 0 and <= 100");
}
// insure the new contract address haven't exist
if (deposit.getAccount(contractAddress) != null) {
- logger.error("Trying to create a contract with existing contract address: " + Wallet
- .encode58Check(contractAddress));
- return;
+ throw new ContractExeException(
+ "Trying to create a contract with existing contract address: " + Wallet
+ .encode58Check(contractAddress));
}
newSmartContract = newSmartContract.toBuilder()
.setContractAddress(ByteString.copyFrom(contractAddress)).build();
-
+ long callValue = newSmartContract.getCallValue();
// create vm to constructor smart contract
try {
AccountCapsule creator = this.deposit
.getAccount(newSmartContract.getOriginAddress().toByteArray());
+ // if (executorType == ET_NORMAL_TYPE) {
+ // long blockENERGYLeftInUs = getBlockENERGYLeftInUs().longValue();
+ // thisTxENERGYLimitInUs = min(blockENERGYLeftInUs,
+ // Constant.ENERGY_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT);
+ // } else {
+ // thisTxENERGYLimitInUs = Constant.ENERGY_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT;
+ // }
+
long thisTxCPULimitInUs;
- long accountCPULimitInUs = getAccountCPULimitInUs(creator, contract);
- if (executerType == ET_NORMAL_TYPE) {
- long blockCPULeftInUs = getBlockCPULeftInUs().longValue();
- thisTxCPULimitInUs = min(accountCPULimitInUs, blockCPULeftInUs,
- Constant.CPU_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT);
+ if (ET_NORMAL_TYPE == executorType) {
+ thisTxCPULimitInUs = Constant.MAX_CPU_TIME_OF_ONE_TX_WHEN_VERIFY_BLOCK;
} else {
- thisTxCPULimitInUs = min(accountCPULimitInUs,
- Constant.CPU_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT);
+ thisTxCPULimitInUs = Constant.MAX_CPU_TIME_OF_ONE_TX;
}
-
long vmStartInUs = System.nanoTime() / 1000;
long vmShouldEndInUs = vmStartInUs + thisTxCPULimitInUs;
+ long feeLimit = trx.getRawData().getFeeLimit();
+ long energyLimit = getEnergyLimit(creator, feeLimit, callValue);
byte[] ops = newSmartContract.getBytecode().toByteArray();
InternalTransaction internalTransaction = new InternalTransaction(trx);
+
ProgramInvoke programInvoke = programInvokeFactory
- .createProgramInvoke(TRX_CONTRACT_CREATION_TYPE, executerType, trx,
- block, deposit, vmStartInUs, vmShouldEndInUs);
+ .createProgramInvoke(TRX_CONTRACT_CREATION_TYPE, executorType, trx,
+ block, deposit, vmStartInUs, vmShouldEndInUs, energyLimit);
this.vm = new VM(config);
this.program = new Program(ops, programInvoke, internalTransaction, config);
+ Program.setRootTransactionId(new TransactionCapsule(trx).getTransactionId().getBytes());
+ Program.resetNonce();
} catch (Exception e) {
logger.error(e.getMessage());
- return;
+ throw new ContractExeException(e.getMessage());
}
program.getResult().setContractAddress(contractAddress);
@@ -400,21 +416,82 @@ private void create()
deposit.createContract(contractAddress, new ContractCapsule(newSmartContract));
deposit.saveCode(contractAddress, ProgramPrecompile.getCode(code));
- deposit.createContractByNormalAccountIndex(ownerAddress, new BytesCapsule(contractAddress));
+ // deposit.createContractByNormalAccountIndex(ownerAddress, new BytesCapsule(contractAddress));
// transfer from callerAddress to contractAddress according to callValue
byte[] callerAddress = contract.getOwnerAddress().toByteArray();
- byte[] callValue = newSmartContract.getCallValue().toByteArray();
- if (null != callValue && callValue.length != 0) {
- long callValueLong = new BigInteger(Hex.toHexString(callValue), 16).longValue();
- this.deposit.addBalance(callerAddress, -callValueLong);
- this.deposit.addBalance(contractAddress, callValueLong);
+ if (callValue > 0) {
+ transfer(this.deposit, callerAddress, contractAddress, callValue);
}
}
- public void go() {
+ /**
+ * **
+ */
+
+ private void call()
+ throws ContractExeException, ContractValidateException {
+ Contract.TriggerSmartContract contract = ContractCapsule.getTriggerContractFromTransaction(trx);
+ if (contract == null) {
+ return;
+ }
+
+ byte[] contractAddress = contract.getContractAddress().toByteArray();
+ byte[] code = this.deposit.getCode(contractAddress);
+ long callValue = contract.getCallValue();
+ if (isEmpty(code)) {
+
+ } else {
+ AccountCapsule caller = this.deposit.getAccount(contract.getOwnerAddress().toByteArray());
+ AccountCapsule creator = this.deposit.getAccount(
+ this.deposit.getContract(contractAddress).getInstance()
+ .getOriginAddress().toByteArray());
+
+ long thisTxENERGYLimitInUs;
+ if (ET_NORMAL_TYPE == executorType) {
+ thisTxENERGYLimitInUs = Constant.MAX_CPU_TIME_OF_ONE_TX_WHEN_VERIFY_BLOCK;
+ } else {
+ thisTxENERGYLimitInUs = Constant.MAX_CPU_TIME_OF_ONE_TX;
+ }
+
+ long vmStartInUs = System.nanoTime() / 1000;
+ long vmShouldEndInUs = vmStartInUs + thisTxENERGYLimitInUs;
+
+ long feeLimit = trx.getRawData().getFeeLimit();
+ long energyLimit;
+ try {
+ energyLimit = getEnergyLimit(creator, caller, contract, feeLimit, callValue);
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ throw new ContractExeException(e.getMessage());
+ }
+
+ if (isCallConstant(contractAddress)) {
+ energyLimit = Constant.MAX_ENERGY_IN_TX;
+ }
+
+ ProgramInvoke programInvoke = programInvokeFactory
+ .createProgramInvoke(TRX_CONTRACT_CALL_TYPE, executorType, trx,
+ block, deposit, vmStartInUs, vmShouldEndInUs, energyLimit);
+ this.vm = new VM(config);
+ InternalTransaction internalTransaction = new InternalTransaction(trx);
+ this.program = new Program(null, code, programInvoke, internalTransaction, config);
+ Program.setRootTransactionId(new TransactionCapsule(trx).getTransactionId().getBytes());
+ Program.resetNonce();
+ }
+
+ program.getResult().setContractAddress(contractAddress);
+ //transfer from callerAddress to targetAddress according to callValue
+ byte[] callerAddress = contract.getOwnerAddress().toByteArray();
+ if (callValue > 0) {
+ transfer(this.deposit, callerAddress, contractAddress, callValue);
+ }
+
+ }
+
+ public void go() throws OutOfSlotTimeException {
if (!readyToExecute) {
return;
}
@@ -423,11 +500,17 @@ public void go() {
if (vm != null) {
vm.play(program);
+ program.getResult().setRet(result.getRet());
result = program.getResult();
if (isCallConstant()) {
+ long callValue = TransactionCapsule.getCallValue(trx.getRawData().getContract(0));
+ if (callValue > 0) {
+ runtimeError = "constant cannot set call value.";
+ }
return;
}
- spendUsage(true);
+
+ // todo: consume bandwidth for successful creating contract
if (result.getException() != null || result.isRevert()) {
result.getDeleteAccounts().clear();
@@ -435,84 +518,39 @@ public void go() {
result.resetFutureRefund();
if (result.getException() != null) {
+ program.spendAllEnergy();
+ runtimeError = result.getException().getMessage();
throw result.getException();
} else {
runtimeError = "REVERT opcode executed";
}
} else {
-
- // touchedAccounts.addAll(result.getTouchedAccounts());
- // check storage useage
- long useedStorageSize =
- deposit.getBeforeRunStorageSize() - deposit.computeAfterRunStorageSize();
- if (useedStorageSize > 1000000) {
- result.setException(Program.Exception.notEnoughStorage());
- throw result.getException();
- }
- if (executerType == ET_NORMAL_TYPE) {
- deposit.commit();
- }
+ deposit.commit();
}
} else {
- if (executerType == ET_NORMAL_TYPE) {
- deposit.commit();
- }
+ deposit.commit();
}
} catch (OutOfResourceException e) {
logger.error(e.getMessage());
- runtimeError = e.getMessage();
- } catch (TronException e) {
- spendUsage(false);
+ throw new OutOfSlotTimeException(e.getMessage());
+ } catch (Throwable e) {
+ result.setException(new RuntimeException("Unknown Throwable"));
logger.error(e.getMessage());
- runtimeError = e.getMessage();
+ if (StringUtils.isEmpty(runtimeError)) {
+ runtimeError = e.getMessage();
+ }
}
- //todo catch over resource exception
-// catch (Exception e) {
-// logger.error(e.getMessage());
-// runtimeError = e.getMessage()
-// }
-
+ trace.setBill(result.getEnergyUsed());
}
- private void spendUsage(boolean spandStorage) {
- cpuProcessor = new CpuProcessor(deposit.getDbManager());
- long cpuUsage, storageUsage;
- storageUsage = 0;
- long now = System.nanoTime() / 1000;
- cpuUsage = now - program.getVmStartInUs();
- if (executerType == ET_NORMAL_TYPE) {
- /*
- * trx.getCpuRecipt
- *
- * */
+ private long getEnergyFee(long callerEnergyUsage, long callerEnergyFrozen,
+ long callerEnergyTotal) {
+ if (callerEnergyTotal <= 0) {
+ return 0;
}
- ContractCapsule contract = deposit.getContract(result.getContractAddress());
- ByteString originAddress = contract.getInstance().getOriginAddress();
- AccountCapsule origin = deposit.getAccount(originAddress.toByteArray());
-
- byte[] callerAddressBytes = TransactionCapsule.getOwner(trx.getRawData().getContract(0));
- AccountCapsule caller = deposit.getAccount(callerAddressBytes);
-
- spendCpuUsage(cpuUsage, origin, caller);
- if (spandStorage) {
- spendStorageUsage(storageUsage, origin, caller);
- }
- }
-
- private void spendCpuUsage(long cpuUsage, AccountCapsule origin, AccountCapsule caller) {
-
- this.cpuProcessor.useCpu(origin, cpuUsage * (100 - 36) / 100,
- deposit.getDbManager().getHeadBlockTimeStamp());
- this.cpuProcessor
- .useCpu(caller, cpuUsage * 36 / 100, deposit.getDbManager().getHeadBlockTimeStamp());
-
- }
-
- private void spendStorageUsage(long storageUsage, AccountCapsule origin, AccountCapsule caller) {
-
- origin.setStorageUsage(storageUsage * (100 - 36) / 100);
- caller.setStorageUsage(storageUsage * 36 / 100);
+ return BigInteger.valueOf(callerEnergyFrozen).multiply(BigInteger.valueOf(callerEnergyUsage))
+ .divide(BigInteger.valueOf(callerEnergyTotal)).longValue();
}
private boolean isCallConstant() {
@@ -525,12 +563,38 @@ private boolean isCallConstant() {
return false;
}
- public RuntimeSummary finalization() {
- return null;
+ private boolean isCallConstant(byte[] address) {
+ if (TRX_CONTRACT_CALL_TYPE.equals(trxType)) {
+ ABI abi = deposit.getContract(address).getInstance().getAbi();
+ if (Wallet.isConstant(abi, ContractCapsule.getTriggerContractFromTransaction(trx))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void finalization() {
+ if (config.vmTrace() && program != null && result != null) {
+ String trace = program.getTrace()
+ .result(result.getHReturn())
+ .error(result.getException())
+ .toString();
+
+ if (config.vmTraceCompressed()) {
+ trace = zipAndEncode(trace);
+ }
+
+ String txHash = Hex.toHexString(new InternalTransaction(trx).getHash());
+ saveProgramTraceFile(config, txHash, trace);
+ }
+
}
public ProgramResult getResult() {
return result;
}
+ public String getRuntimeError() {
+ return runtimeError;
+ }
}
diff --git a/src/main/java/org/tron/common/runtime/config/SystemProperties.java b/src/main/java/org/tron/common/runtime/config/SystemProperties.java
index 7bbff85a7b3..77ec2aaf28d 100644
--- a/src/main/java/org/tron/common/runtime/config/SystemProperties.java
+++ b/src/main/java/org/tron/common/runtime/config/SystemProperties.java
@@ -17,234 +17,43 @@
*/
package org.tron.common.runtime.config;
-import com.typesafe.config.Config;
-import com.typesafe.config.ConfigFactory;
-import com.typesafe.config.ConfigRenderOptions;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.util.*;
-
-//import org.ethereum.config.blockchain.OlympicConfig;
-//import org.ethereum.config.net.*;
+/**
+ * For developer only
+ */
public class SystemProperties {
- private static Logger logger = LoggerFactory.getLogger("general");
-
- private static SystemProperties CONFIG;
- private static boolean useOnlySpringConfig = true; //false;
- /**
- * Returns the static config instance. If the config is passed
- * as a Spring bean by the application this instance shouldn't
- * be used
- * This method is mainly used for testing purposes
- * (Autowired fields are initialized with this static instance
- * but when running within Spring context they replaced with the
- * bean config instance)
- */
- public static SystemProperties getDefault() {
- return useOnlySpringConfig ? null : getSpringDefault();
- }
-
- static SystemProperties getSpringDefault() {
- if (CONFIG == null) {
- CONFIG = new SystemProperties();
- }
- return CONFIG;
- }
-
- /**
- * Used mostly for testing purposes to ensure the application
- * refers only to the config passed as a Spring bean.
- * If this property is set to true {@link #getDefault()} returns null
- */
- public static void setUseOnlySpringConfig(boolean useOnlySpringConfig) {
- SystemProperties.useOnlySpringConfig = useOnlySpringConfig;
- }
-
- static boolean isUseOnlySpringConfig() {
- return useOnlySpringConfig;
- }
-
- /**
- * Marks config accessor methods which need to be called (for value validation)
- * upon config creation or modification
- */
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- private @interface ValidateMe {};
-
-
- private Config config;
-
- private final ClassLoader classLoader;
-
- public SystemProperties() {
- this(ConfigFactory.empty());
- }
-
- public SystemProperties(File configFile) {
- this(ConfigFactory.parseFile(configFile));
- }
-
- public SystemProperties(String configResource) {
- this(ConfigFactory.parseResources(configResource));
- }
-
- public SystemProperties(Config apiConfig) {
- this(apiConfig, SystemProperties.class.getClassLoader());
- }
-
- public SystemProperties(Config apiConfig, ClassLoader classLoader) {
- try {
- this.classLoader = classLoader;
-
- Config javaSystemProperties = ConfigFactory.load("no-such-resource-only-system-props");
- Config referenceConfig = ConfigFactory.parseResources("ethereumj.conf");
- logger.info("Config (" + (referenceConfig.entrySet().size() > 0 ? " yes " : " no ") + "): default properties from resource 'ethereumj.conf'");
- String res = System.getProperty("ethereumj.conf.res");
- Config cmdLineConfigRes = res != null ? ConfigFactory.parseResources(res) : ConfigFactory.empty();
- logger.info("Config (" + (cmdLineConfigRes.entrySet().size() > 0 ? " yes " : " no ") + "): user properties from -Dethereumj.conf.res resource '" + res + "'");
- Config userConfig = ConfigFactory.parseResources("user.conf");
- logger.info("Config (" + (userConfig.entrySet().size() > 0 ? " yes " : " no ") + "): user properties from resource 'user.conf'");
- File userDirFile = new File(System.getProperty("user.dir"), "/config/ethereumj.conf");
- Config userDirConfig = ConfigFactory.parseFile(userDirFile);
- logger.info("Config (" + (userDirConfig.entrySet().size() > 0 ? " yes " : " no ") + "): user properties from file '" + userDirFile + "'");
- Config testConfig = ConfigFactory.parseResources("test-ethereumj.conf");
- logger.info("Config (" + (testConfig.entrySet().size() > 0 ? " yes " : " no ") + "): test properties from resource 'test-ethereumj.conf'");
- Config testUserConfig = ConfigFactory.parseResources("test-user.conf");
- logger.info("Config (" + (testUserConfig.entrySet().size() > 0 ? " yes " : " no ") + "): test properties from resource 'test-user.conf'");
- String file = System.getProperty("ethereumj.conf.file");
- Config cmdLineConfigFile = file != null ? ConfigFactory.parseFile(new File(file)) : ConfigFactory.empty();
- logger.info("Config (" + (cmdLineConfigFile.entrySet().size() > 0 ? " yes " : " no ") + "): user properties from -Dethereumj.conf.file file '" + file + "'");
- logger.info("Config (" + (apiConfig.entrySet().size() > 0 ? " yes " : " no ") + "): config passed via constructor");
- config = apiConfig
- .withFallback(cmdLineConfigFile)
- .withFallback(testUserConfig)
- .withFallback(testConfig)
- .withFallback(userDirConfig)
- .withFallback(userConfig)
- .withFallback(cmdLineConfigRes)
- .withFallback(referenceConfig);
-
- logger.debug("Config trace: " + config.root().render(ConfigRenderOptions.defaults().
- setComments(false).setJson(false)));
-
- config = javaSystemProperties.withFallback(config)
- .resolve(); // substitute variables in config if any
- validateConfig();
-
- // There could be several files with the same name from other packages,
- // "version.properties" is a very common name
- List iStreams = loadResources("version.properties", this.getClass().getClassLoader());
- for (InputStream is : iStreams) {
- Properties props = new Properties();
- props.load(is);
- if (props.getProperty("versionNumber") == null || props.getProperty("databaseVersion") == null) {
- continue;
- }
- break;
- }
- } catch (Exception e) {
- logger.error("Can't read config.", e);
- throw new RuntimeException(e);
- }
- }
- /**
- * Loads resources using given ClassLoader assuming, there could be several resources
- * with the same name
- */
- public static List loadResources(
- final String name, final ClassLoader classLoader) throws IOException {
- final List list = new ArrayList();
- final Enumeration systemResources =
- (classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader)
- .getResources(name);
- while (systemResources.hasMoreElements()) {
- list.add(systemResources.nextElement().openStream());
- }
- return list;
- }
+ private static Logger logger = LoggerFactory.getLogger("general");
- public Config getConfig() {
- return config;
- }
+ private boolean vmTraceCompressed = false;
+ private boolean vmOn = true;
+ private boolean vmTrace = false;
- public boolean vmOn() {
- return true;
- }
+ private SystemProperties() {
+ }
- public boolean vmTrace() {
- return false;
- }
+ private static class SystemPropertiesInstance {
- /**
- * Puts a new config atop of existing stack making the options
- * in the supplied config overriding existing options
- * Once put this config can't be removed
- *
- * @param overrideOptions - atop config
- */
- public void overrideParams(Config overrideOptions) {
- config = overrideOptions.withFallback(config);
- validateConfig();
- }
+ private static final SystemProperties INSTANCE = new SystemProperties();
+ }
- /**
- * Puts a new config atop of existing stack making the options
- * in the supplied config overriding existing options
- * Once put this config can't be removed
- *
- * @param keyValuePairs [name] [value] [name] [value] ...
- */
- public void overrideParams(String ... keyValuePairs) {
- if (keyValuePairs.length % 2 != 0) throw new RuntimeException("Odd argument number");
- Map map = new HashMap<>();
- for (int i = 0; i < keyValuePairs.length; i += 2) {
- map.put(keyValuePairs[i], keyValuePairs[i + 1]);
- }
- overrideParams(map);
- }
+ public static SystemProperties getInstance() {
+ return SystemPropertiesInstance.INSTANCE;
+ }
- /**
- * Puts a new config atop of existing stack making the options
- * in the supplied config overriding existing options
- * Once put this config can't be removed
- *
- * @param cliOptions - command line options to take presidency
- */
- public void overrideParams(Map cliOptions) {
- Config cliConf = ConfigFactory.parseMap(cliOptions);
- overrideParams(cliConf);
- }
+ public boolean vmOn() {
+ return vmOn;
+ }
- private void validateConfig() {
- for (Method method : getClass().getMethods()) {
- try {
- if (method.isAnnotationPresent(ValidateMe.class)) {
- method.invoke(this);
- }
- } catch (Exception e) {
- throw new RuntimeException("Error validating config method: " + method, e);
- }
- }
- }
+ public boolean vmTrace() {
+ return vmTrace;
+ }
- public T getProperty(String propName, T defaultValue) {
- if (!config.hasPath(propName)) return defaultValue;
- String string = config.getString(propName);
- if (string.trim().isEmpty()) return defaultValue;
- return (T) config.getAnyRef(propName);
- }
+ public boolean vmTraceCompressed() {
+ return vmTraceCompressed;
+ }
}
diff --git a/src/main/java/org/tron/common/runtime/utils/MUtil.java b/src/main/java/org/tron/common/runtime/utils/MUtil.java
index 56e19d54a86..b2675fbc3a2 100644
--- a/src/main/java/org/tron/common/runtime/utils/MUtil.java
+++ b/src/main/java/org/tron/common/runtime/utils/MUtil.java
@@ -5,16 +5,17 @@
import org.tron.common.crypto.Hash;
import org.tron.common.storage.Deposit;
import org.tron.core.Wallet;
-import org.tron.core.exception.ContractExeException;
+import org.tron.core.actuator.TransferActuator;
+import org.tron.core.exception.ContractValidateException;
-/**
- * @author Guo Yonggang
- * @since 02.05.2018
- */
public class MUtil {
public static void transfer(Deposit deposit, byte[] fromAddress, byte[] toAddress, long amount)
- throws ContractExeException {
+ throws ContractValidateException {
+ if (0 == amount) {
+ return;
+ }
+ TransferActuator.validateForSmartContract(deposit, fromAddress, toAddress, amount);
if (deposit.getBalance(fromAddress) < amount) {
throw new RuntimeException(
Hex.toHexString(fromAddress).toUpperCase() + " not enough balance!");
@@ -26,8 +27,8 @@ public static void transfer(Deposit deposit, byte[] fromAddress, byte[] toAddres
deposit.addBalance(fromAddress, -amount);
}
- public static void burn(Deposit deposit, byte[] address, long amount)
- throws ContractExeException {
+
+ public static void burn(Deposit deposit, byte[] address, long amount) {
if (deposit.getBalance(address) < amount) {
throw new RuntimeException("Not enough balance!");
}
@@ -48,4 +49,18 @@ public static byte[] convertToTronAddress(byte[] address) {
public static String get4BytesSha3HexString(String data) {
return Hex.toHexString(Arrays.copyOf(Hash.sha3(data.getBytes()), 4));
}
+
+ public static byte[] generateByteArray(byte[] ...parameters){
+ int length =0;
+ for(int i=0;i topics = Lists.newArrayList();
+ logInfo.getTopics().forEach(topic -> {
+ topics.add(ByteString.copyFrom(topic.getData()));
+ });
+ ByteString address = ByteString.copyFrom(logInfo.getAddress());
+ ByteString data = ByteString.copyFrom(logInfo.getData());
+ return Log.newBuilder().setAddress(address).addAllTopics(topics).setData(data).build();
+ }
+
}
diff --git a/src/main/java/org/tron/common/runtime/vm/MessageCall.java b/src/main/java/org/tron/common/runtime/vm/MessageCall.java
index 7655a4ef5d7..88a50c5fe97 100644
--- a/src/main/java/org/tron/common/runtime/vm/MessageCall.java
+++ b/src/main/java/org/tron/common/runtime/vm/MessageCall.java
@@ -29,9 +29,9 @@ public class MessageCall {
private final OpCode type;
/**
- * gas to pay for the call, remaining gas will be refunded to the caller
+ * energy to pay for the call, remaining energy will be refunded to the caller
*/
- private final DataWord gas;
+ private final DataWord energy;
/**
* address of account which code to call
*/
@@ -57,20 +57,20 @@ public class MessageCall {
*/
private DataWord outDataSize;
- public MessageCall(OpCode type, DataWord gas, DataWord codeAddress,
+ public MessageCall(OpCode type, DataWord energy, DataWord codeAddress,
DataWord endowment, DataWord inDataOffs, DataWord inDataSize) {
this.type = type;
- this.gas = gas;
+ this.energy = energy;
this.codeAddress = codeAddress;
this.endowment = endowment;
this.inDataOffs = inDataOffs;
this.inDataSize = inDataSize;
}
- public MessageCall(OpCode type, DataWord gas, DataWord codeAddress,
+ public MessageCall(OpCode type, DataWord energy, DataWord codeAddress,
DataWord endowment, DataWord inDataOffs, DataWord inDataSize,
DataWord outDataOffs, DataWord outDataSize) {
- this(type, gas, codeAddress, endowment, inDataOffs, inDataSize);
+ this(type, energy, codeAddress, endowment, inDataOffs, inDataSize);
this.outDataOffs = outDataOffs;
this.outDataSize = outDataSize;
}
@@ -79,8 +79,8 @@ public OpCode getType() {
return type;
}
- public DataWord getGas() {
- return gas;
+ public DataWord getEnergy() {
+ return energy;
}
public DataWord getCodeAddress() {
diff --git a/src/main/java/org/tron/common/runtime/vm/PrecompiledContracts.java b/src/main/java/org/tron/common/runtime/vm/PrecompiledContracts.java
index 27b843f63e1..6388fddfd9f 100644
--- a/src/main/java/org/tron/common/runtime/vm/PrecompiledContracts.java
+++ b/src/main/java/org/tron/common/runtime/vm/PrecompiledContracts.java
@@ -56,14 +56,12 @@
import org.tron.core.exception.ContractExeException;
import org.tron.core.exception.ContractValidateException;
import org.tron.protos.Contract;
-import org.tron.protos.Contract.FreezeBalanceContract;
import org.tron.protos.Contract.ProposalApproveContract;
import org.tron.protos.Contract.ProposalCreateContract;
import org.tron.protos.Contract.ProposalDeleteContract;
-import org.tron.protos.Contract.UnfreezeBalanceContract;
+import org.tron.protos.Contract.TransferAssetContract;
import org.tron.protos.Contract.VoteWitnessContract;
import org.tron.protos.Contract.WithdrawBalanceContract;
-import org.tron.protos.Protocol.AccountType;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
/**
@@ -91,6 +89,8 @@ public class PrecompiledContracts {
private static final ProposalDeleteNative proposalDelete = new ProposalDeleteNative();
private static final ConvertFromTronBytesAddressNative convertFromTronBytesAddress = new ConvertFromTronBytesAddressNative();
private static final ConvertFromTronBase58AddressNative convertFromTronBase58Address = new ConvertFromTronBase58AddressNative();
+ private static final TransferAssetNative transferAsset = new TransferAssetNative();
+ private static final GetTransferAssetNative getTransferAssetAmount = new GetTransferAssetNative();
private static final DataWord ecRecoverAddr = new DataWord(
@@ -127,6 +127,10 @@ public class PrecompiledContracts {
"0000000000000000000000000000000000000000000000000000000000010008");
private static final DataWord convertFromTronBase58AddressAddr = new DataWord(
"0000000000000000000000000000000000000000000000000000000000010009");
+ private static final DataWord transferAssetAddr = new DataWord(
+ "000000000000000000000000000000000000000000000000000000000001000a");
+ private static final DataWord getTransferAssetAmountAddr = new DataWord(
+ "000000000000000000000000000000000000000000000000000000000001000b");
public static PrecompiledContract getContractForAddress(DataWord address) {
@@ -172,6 +176,12 @@ public static PrecompiledContract getContractForAddress(DataWord address) {
if (address.equals(convertFromTronBase58AddressAddr)) {
return convertFromTronBase58Address;
}
+ if (address.equals(transferAssetAddr)) {
+ return transferAsset;
+ }
+ if (address.equals(getTransferAssetAmountAddr)) {
+ return getTransferAssetAmount;
+ }
/*
@@ -199,7 +209,7 @@ private static byte[] encodeRes(byte[] w1, byte[] w2) {
public static abstract class PrecompiledContract {
- public abstract long getGasForData(byte[] data);
+ public abstract long getEnergyForData(byte[] data);
public abstract Pair execute(byte[] data);
@@ -240,9 +250,9 @@ public Identity() {
}
@Override
- public long getGasForData(byte[] data) {
+ public long getEnergyForData(byte[] data) {
- // gas charge for the execution:
+ // energy charge for the execution:
// minimum 1 and additional 1 for each 32 bytes word (round up)
if (data == null) {
return 15;
@@ -260,9 +270,9 @@ public static class Sha256 extends PrecompiledContract {
@Override
- public long getGasForData(byte[] data) {
+ public long getEnergyForData(byte[] data) {
- // gas charge for the execution:
+ // energy charge for the execution:
// minimum 50 and additional 50 for each 32 bytes word (round up)
if (data == null) {
return 60;
@@ -285,10 +295,10 @@ public static class Ripempd160 extends PrecompiledContract {
@Override
- public long getGasForData(byte[] data) {
+ public long getEnergyForData(byte[] data) {
// TODO #POC9 Replace magic numbers with constants
- // gas charge for the execution:
+ // energy charge for the execution:
// minimum 50 and additional 50 for each 32 bytes word (round up)
if (data == null) {
return 600;
@@ -313,7 +323,7 @@ public Pair execute(byte[] data) {
public static class ECRecover extends PrecompiledContract {
@Override
- public long getGasForData(byte[] data) {
+ public long getEnergyForData(byte[] data) {
return 3000;
}
@@ -375,7 +385,7 @@ public static class ModExp extends PrecompiledContract {
private static final int ARGS_OFFSET = 32 * 3; // addresses length part
@Override
- public long getGasForData(byte[] data) {
+ public long getEnergyForData(byte[] data) {
if (data == null) {
data = EMPTY_BYTE_ARRAY;
@@ -391,11 +401,12 @@ public long getGasForData(byte[] data) {
long adjExpLen = getAdjustedExponentLength(expHighBytes, expLen);
// use big numbers to stay safe in case of overflow
- BigInteger gas = BigInteger.valueOf(multComplexity)
+ BigInteger energy = BigInteger.valueOf(multComplexity)
.multiply(BigInteger.valueOf(Math.max(adjExpLen, 1)))
.divide(GQUAD_DIVISOR);
- return isLessThan(gas, BigInteger.valueOf(Long.MAX_VALUE)) ? gas.longValue() : Long.MAX_VALUE;
+ return isLessThan(energy, BigInteger.valueOf(Long.MAX_VALUE)) ? energy.longValue()
+ : Long.MAX_VALUE;
}
@Override
@@ -488,7 +499,7 @@ private BigInteger parseArg(byte[] data, int offset, int len) {
public static class BN128Addition extends PrecompiledContract {
@Override
- public long getGasForData(byte[] data) {
+ public long getEnergyForData(byte[] data) {
return 500;
}
@@ -535,7 +546,7 @@ public Pair execute(byte[] data) {
public static class BN128Multiplication extends PrecompiledContract {
@Override
- public long getGasForData(byte[] data) {
+ public long getEnergyForData(byte[] data) {
return 40000;
}
@@ -581,7 +592,7 @@ public static class BN128Pairing extends PrecompiledContract {
private static final int PAIR_SIZE = 192;
@Override
- public long getGasForData(byte[] data) {
+ public long getEnergyForData(byte[] data) {
if (data == null) {
return 100000;
@@ -665,8 +676,8 @@ public static class VoteWitnessNative extends PrecompiledContract {
@Override
// TODO: Please re-implement this function after Tron cost is well designed.
- public long getGasForData(byte[] data) {
- return 0;
+ public long getEnergyForData(byte[] data) {
+ return 200;
}
@Override
@@ -703,9 +714,11 @@ public Pair execute(byte[] data) {
} catch (ContractExeException e) {
logger.debug("ContractExeException when calling voteWitness in vm");
logger.debug("ContractExeException: {}", e.getMessage());
+ return null;
} catch (ContractValidateException e) {
logger.debug("ContractValidateException when calling voteWitness in vm");
logger.debug("ContractValidateException: {}", e.getMessage());
+ return null;
}
return Pair.of(true, new DataWord(count).getData());
}
@@ -722,8 +735,8 @@ public static class FreezeBalanceNative extends PrecompiledContract {
@Override
// TODO: Please re-implement this function after Tron cost is well designed.
- public long getGasForData(byte[] data) {
- return 0;
+ public long getEnergyForData(byte[] data) {
+ return 200;
}
@Override
@@ -733,40 +746,42 @@ public Pair execute(byte[] data) {
data = EMPTY_BYTE_ARRAY;
}
- byte[] frozenBalance = new byte[32];
- System.arraycopy(data, 0, frozenBalance, 0, 32);
- byte[] frozenDuration = new byte[32];
- System.arraycopy(data, 32, frozenDuration, 0, 32);
-
- if (getDeposit().getDbManager().getAccountStore().get(getCallerAddress()).getType()
- == AccountType.Contract) {
- logger.debug("caller can't be a contract");
- // TODO: or exception here.
- return Pair.of(false, null);
- }
-
- Contract.FreezeBalanceContract.Builder builder = Contract.FreezeBalanceContract.newBuilder();
- ByteString byteAddress = ByteString.copyFrom(getCallerAddress());
- builder.setOwnerAddress(byteAddress).setFrozenBalance(ByteArray.toLong(frozenBalance))
- .setFrozenDuration(ByteArray.toLong(frozenDuration));
- FreezeBalanceContract contract = builder.build();
-
- TransactionCapsule trx = new TransactionCapsule(contract, ContractType.FreezeBalanceContract);
-
- final List actuatorList = ActuatorFactory
- .createActuator(trx, getDeposit().getDbManager());
- try {
- actuatorList.get(0).validate();
- actuatorList.get(0).execute(getResult().getRet());
- getDeposit()
- .syncCacheFromAccountStore(ByteString.copyFrom(getCallerAddress()).toByteArray());
- } catch (ContractExeException e) {
- logger.debug("ContractExeException when calling freezeBalance in vm");
- logger.debug("ContractExeException: {}", e.getMessage());
- } catch (ContractValidateException e) {
- logger.debug("ContractValidateException when calling freezeBalance in vm");
- logger.debug("ContractValidateException: {}", e.getMessage());
- }
+// byte[] frozenBalance = new byte[32];
+// System.arraycopy(data, 0, frozenBalance, 0, 32);
+// byte[] frozenDuration = new byte[32];
+// System.arraycopy(data, 32, frozenDuration, 0, 32);
+//
+// if (getDeposit().getDbManager().getAccountStore().get(getCallerAddress()).getType()
+// == AccountType.Contract) {
+// logger.debug("caller can't be a contract");
+// // TODO: or exception here.
+// return Pair.of(false, null);
+// }
+//
+// Contract.FreezeBalanceContract.Builder builder = Contract.FreezeBalanceContract.newBuilder();
+// ByteString byteAddress = ByteString.copyFrom(getCallerAddress());
+// builder.setOwnerAddress(byteAddress).setFrozenBalance(ByteArray.toLong(frozenBalance))
+// .setFrozenDuration(ByteArray.toLong(frozenDuration));
+// FreezeBalanceContract contract = builder.build();
+//
+// TransactionCapsule trx = new TransactionCapsule(contract, ContractType.FreezeBalanceContract);
+//
+// final List actuatorList = ActuatorFactory
+// .createActuator(trx, getDeposit().getDbManager());
+// try {
+// actuatorList.get(0).validate();
+// actuatorList.get(0).execute(getResult().getRet());
+// getDeposit()
+// .syncCacheFromAccountStore(ByteString.copyFrom(getCallerAddress()).toByteArray());
+// } catch (ContractExeException e) {
+// logger.debug("ContractExeException when calling freezeBalance in vm");
+// logger.debug("ContractExeException: {}", e.getMessage());
+// return null;
+// } catch (ContractValidateException e) {
+// logger.debug("ContractValidateException when calling freezeBalance in vm");
+// logger.debug("ContractValidateException: {}", e.getMessage());
+// return null;
+// }
return Pair.of(true, new DataWord(1).getData());
}
}
@@ -782,8 +797,8 @@ public static class UnfreezeBalanceNative extends PrecompiledContract {
@Override
// TODO: Please re-implement this function after Tron cost is well designed.
- public long getGasForData(byte[] data) {
- return 0;
+ public long getEnergyForData(byte[] data) {
+ return 200;
}
@Override
@@ -793,30 +808,39 @@ public Pair execute(byte[] data) {
data = EMPTY_BYTE_ARRAY;
}
- Contract.UnfreezeBalanceContract.Builder builder = Contract.UnfreezeBalanceContract
- .newBuilder();
- ByteString byteAddress = ByteString.copyFrom(getCallerAddress());
- builder.setOwnerAddress(byteAddress);
- UnfreezeBalanceContract contract = builder.build();
-
- TransactionCapsule trx = new TransactionCapsule(contract,
- ContractType.UnfreezeBalanceContract);
-
- final List actuatorList = ActuatorFactory
- .createActuator(trx, getDeposit().getDbManager());
- try {
- actuatorList.get(0).validate();
- actuatorList.get(0).execute(getResult().getRet());
- getDeposit()
- .syncCacheFromAccountStore(ByteString.copyFrom(getCallerAddress()).toByteArray());
- getDeposit().syncCacheFromVotesStore(ByteString.copyFrom(getCallerAddress()).toByteArray());
- } catch (ContractExeException e) {
- logger.debug("ContractExeException when calling unfreezeBalance in vm");
- logger.debug("ContractExeException: {}", e.getMessage());
- } catch (ContractValidateException e) {
- logger.debug("ContractValidateException when calling unfreezeBalance in vm");
- logger.debug("ContractValidateException: {}", e.getMessage());
- }
+// if (getDeposit().getDbManager().getAccountStore().get(getCallerAddress()).getType()
+// == AccountType.Contract) {
+// logger.debug("caller can't be a contract");
+// // TODO: or exception here.
+// return Pair.of(false, null);
+// }
+//
+// Contract.UnfreezeBalanceContract.Builder builder = Contract.UnfreezeBalanceContract
+// .newBuilder();
+// ByteString byteAddress = ByteString.copyFrom(getCallerAddress());
+// builder.setOwnerAddress(byteAddress);
+// UnfreezeBalanceContract contract = builder.build();
+//
+// TransactionCapsule trx = new TransactionCapsule(contract,
+// ContractType.UnfreezeBalanceContract);
+//
+// final List actuatorList = ActuatorFactory
+// .createActuator(trx, getDeposit().getDbManager());
+// try {
+// actuatorList.get(0).validate();
+// actuatorList.get(0).execute(getResult().getRet());
+// getDeposit()
+// .syncCacheFromAccountStore(ByteString.copyFrom(getCallerAddress()).toByteArray());
+// getDeposit().syncCacheFromVotesStore(ByteString.copyFrom(getCallerAddress()).toByteArray());
+// } catch (ContractExeException e) {
+// logger.debug("ContractExeException when calling unfreezeBalance in vm");
+// logger.debug("ContractExeException: {}", e.getMessage());
+// return null;
+// } catch (ContractValidateException e) {
+// logger.debug("ContractValidateException when calling unfreezeBalance in vm");
+// logger.debug("ContractValidateException: {}", e.getMessage());
+// return null;
+// }
return Pair.of(true, new DataWord(1).getData());
}
}
@@ -832,8 +856,8 @@ public static class WithdrawBalanceNative extends PrecompiledContract {
@Override
// TODO: Please re-implement this function after Tron cost is well designed.
- public long getGasForData(byte[] data) {
- return 0;
+ public long getEnergyForData(byte[] data) {
+ return 200;
}
@Override
@@ -862,9 +886,11 @@ public Pair execute(byte[] data) {
} catch (ContractExeException e) {
logger.debug("ContractExeException when calling withdrawBalanceNative in vm");
logger.debug("ContractExeException: {}", e.getMessage());
+ return null;
} catch (ContractValidateException e) {
logger.debug("ContractValidateException when calling withdrawBalanceNative in vm");
logger.debug("ContractValidateException: {}", e.getMessage());
+ return null;
}
return Pair.of(true, new DataWord(1).getData());
}
@@ -881,8 +907,8 @@ public static class ProposalApproveNative extends PrecompiledContract {
@Override
// TODO: Please re-implement this function after Tron cost is well designed.
- public long getGasForData(byte[] data) {
- return 0;
+ public long getEnergyForData(byte[] data) {
+ return 200;
}
@Override
@@ -918,9 +944,11 @@ public Pair execute(byte[] data) {
} catch (ContractExeException e) {
logger.debug("ContractExeException when calling proposalApproveNative in vm");
logger.debug("ContractExeException: {}", e.getMessage());
+ return null;
} catch (ContractValidateException e) {
logger.debug("ContractValidateException when calling proposalApproveNative in vm");
logger.debug("ContractValidateException: {}", e.getMessage());
+ return null;
}
return Pair.of(true, new DataWord(1).getData());
}
@@ -938,8 +966,8 @@ public static class ProposalCreateNative extends PrecompiledContract {
@Override
// TODO: Please re-implement this function after Tron cost is well designed.
- public long getGasForData(byte[] data) {
- return 0;
+ public long getEnergyForData(byte[] data) {
+ return 200;
}
@Override
@@ -981,9 +1009,11 @@ public Pair execute(byte[] data) {
} catch (ContractExeException e) {
logger.debug("ContractExeException when calling proposalCreateNative in vm");
logger.debug("ContractExeException: {}", e.getMessage());
+ return null;
} catch (ContractValidateException e) {
logger.debug("ContractValidateException when calling proposalCreateNative in vm");
logger.debug("ContractValidateException: {}", e.getMessage());
+ return null;
}
return Pair.of(true, new DataWord(id).getData());
}
@@ -1000,8 +1030,8 @@ public static class ProposalDeleteNative extends PrecompiledContract {
@Override
// TODO: Please re-implement this function after Tron cost is well designed.
- public long getGasForData(byte[] data) {
- return 0;
+ public long getEnergyForData(byte[] data) {
+ return 200;
}
@Override
@@ -1028,9 +1058,11 @@ public Pair execute(byte[] data) {
} catch (ContractExeException e) {
logger.debug("ContractExeException when calling proposalDeleteContract in vm");
logger.debug("ContractExeException: {}", e.getMessage());
+ return null;
} catch (ContractValidateException e) {
logger.debug("ContractValidateException when calling proposalDeleteContract in vm");
logger.debug("ContractValidateException: {}", e.getMessage());
+ return null;
}
return Pair.of(true, new DataWord(1).getData());
}
@@ -1048,8 +1080,8 @@ public static class ConvertFromTronBytesAddressNative extends PrecompiledContrac
@Override
// TODO: Please re-implement this function after Tron cost is well designed.
- public long getGasForData(byte[] data) {
- return 0;
+ public long getEnergyForData(byte[] data) {
+ return 200;
}
@Override
@@ -1075,8 +1107,8 @@ public static class ConvertFromTronBase58AddressNative extends PrecompiledContra
@Override
// TODO: Please re-implement this function after Tron cost is well designed.
- public long getGasForData(byte[] data) {
- return 0;
+ public long getEnergyForData(byte[] data) {
+ return 200;
}
@Override
@@ -1090,7 +1122,115 @@ public Pair execute(byte[] data) {
byte[] resultBytes = Wallet.decodeFromBase58Check(addressBase58);
String hexString = Hex.toHexString(resultBytes);
- return Pair.of(true, new DataWord(hexString).getData());
+ return Pair.of(true, new DataWord(new DataWord(hexString).getLast20Bytes()).getData());
+ }
+ }
+
+ /**
+ * Native function for transferring Asset to another account.
+ *
+ *
+ * Input data[]: toAddress, amount, assetName
+ *
+ * Output: transfer asset operation success or not
+ */
+ public static class TransferAssetNative extends PrecompiledContract {
+
+ @Override
+ public long getEnergyForData(byte[] data) {
+ return 200;
+ }
+
+ @Override
+ public Pair execute(byte[] data) {
+
+ if (data == null) {
+ data = EMPTY_BYTE_ARRAY;
+ }
+
+ byte[] toAddress = new byte[32];
+ System.arraycopy(data, 0, toAddress, 0, 32);
+ byte[] amount = new byte[32];
+ System.arraycopy(data, 32 + 16 + 8, amount, 0, 8);
+ // we already have a restrict for token name length, no more than 32 bytes. don't need to check again
+ byte[] name = new byte[32];
+ System.arraycopy(data, 64, name, 0, data.length-64);
+ int length =name.length;
+ while(length>0 && name[length -1] ==0){
+ length--;
+ }
+ name = ByteArray.subArray(name,0,length);
+ Contract.TransferAssetContract.Builder builder = Contract.TransferAssetContract
+ .newBuilder();
+ builder.setOwnerAddress(ByteString.copyFrom(getCallerAddress()));
+ builder.setToAddress(ByteString.copyFrom(convertToTronAddress(new DataWord(toAddress).getLast20Bytes())));
+ builder.setAmount(Longs.fromByteArray(amount));
+ builder.setAssetName(ByteString.copyFrom(name));
+
+
+ TransferAssetContract contract = builder.build();
+
+ TransactionCapsule trx = new TransactionCapsule(contract,
+ ContractType.TransferAssetContract);
+
+ final List actuatorList = ActuatorFactory
+ .createActuator(trx, getDeposit().getDbManager());
+ try {
+ actuatorList.get(0).validate();
+ actuatorList.get(0).execute(getResult().getRet());
+ } catch (ContractExeException e) {
+ logger.debug("ContractExeException when calling transferAssetContract in vm");
+ logger.debug("ContractExeException: {}", e.getMessage());
+ return null;
+ } catch (ContractValidateException e) {
+ logger.debug("ContractValidateException when calling transferAssetContract in vm");
+ logger.debug("ContractValidateException: {}", e.getMessage());
+ return null;
+ }
+ return Pair.of(true, new DataWord(1).getData());
+ }
+ }
+
+
+
+ /**
+ * Native function for check Asset balance basing on targetAddress and Asset name.
+ *
+ *
+ * Input data[]: address targetAddress, byte[] assetName
+ *
+ * Output: balance
+ */
+ public static class GetTransferAssetNative extends PrecompiledContract {
+
+ @Override
+ public long getEnergyForData(byte[] data) {
+ return 200;
+ }
+
+ @Override
+ public Pair execute(byte[] data) {
+
+ if (data == null) {
+ data = EMPTY_BYTE_ARRAY;
+ }
+
+ byte[] targetAddress = new byte[32];
+ System.arraycopy(data, 0, targetAddress, 0, 32);
+ // we already have a restrict for token name length, no more than 32 bytes. don't need to check again
+ byte[] name = new byte[32];
+ System.arraycopy(data, 32, name, 0, 32);
+ int length =name.length;
+ while(length>0 && name[length -1] ==0){
+ length--;
+ }
+ name = ByteArray.subArray(name,0,length);
+
+ long assetBalance = this.getDeposit().getDbManager().getAccountStore().
+ get(convertToTronAddress(new DataWord(targetAddress).getLast20Bytes())).
+ getAssetMap().get(ByteArray.toStr(name));
+
+ return Pair.of(true, new DataWord(Longs.toByteArray(assetBalance)).getData());
}
}
}
diff --git a/src/main/java/org/tron/common/runtime/vm/VM.java b/src/main/java/org/tron/common/runtime/vm/VM.java
index 0cd5a56ffe8..48c09f6ad09 100644
--- a/src/main/java/org/tron/common/runtime/vm/VM.java
+++ b/src/main/java/org/tron/common/runtime/vm/VM.java
@@ -1,6 +1,7 @@
package org.tron.common.runtime.vm;
import static org.tron.common.crypto.Hash.sha3;
+import static org.tron.common.runtime.utils.MUtil.convertToTronAddress;
import static org.tron.common.runtime.vm.OpCode.CALL;
import static org.tron.common.runtime.vm.OpCode.PUSH1;
import static org.tron.common.runtime.vm.OpCode.REVERT;
@@ -9,22 +10,22 @@
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
import org.spongycastle.util.encoders.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.tron.common.runtime.config.SystemProperties;
import org.tron.common.runtime.vm.program.Program;
-import org.tron.common.runtime.vm.program.Program.OutOfResourceException;
+import org.tron.common.runtime.vm.program.Program.OutOfEnergyException;
import org.tron.common.runtime.vm.program.Stack;
-import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+
+@Slf4j(topic = "VM")
public class VM {
- private static final Logger logger = LoggerFactory.getLogger("TronVM");
- private static final Logger dumpLogger = LoggerFactory.getLogger("dump");
+ // private static final Logger logger = LoggerFactory.getLogger("TronVM");
private static BigInteger _32_ = BigInteger.valueOf(32);
- private static final String logString = "{} Op: [{}] Gas: [{}] Deep: [{}] Hint: [{}]";
+ private static final String logString = "{} Op: [{}] Energy: [{}] Deep: [{}] Hint: [{}]";
// max mem size which couldn't be paid for ever
// used to reduce expensive BigInt arithmetic
@@ -42,7 +43,7 @@ public class VM {
private final SystemProperties config;
public VM() {
- this(SystemProperties.getDefault());
+ config = SystemProperties.getInstance();
}
@Autowired
@@ -53,23 +54,25 @@ public VM(SystemProperties config) {
}
private void checkMemorySize(OpCode op, BigInteger newMemSize) {
+ // todo: add TVMruntime error
if (newMemSize.compareTo(MEM_LIMIT) > 0) {
throw Program.Exception.memoryOverflow(op);
}
}
- private long calcMemDrop(DropCost dropCosts, long oldMemSize, BigInteger newMemSize,
+ private long calcMemEnergy(EnergyCost energyCosts, long oldMemSize, BigInteger newMemSize,
long copySize) {
- long dropConsume = 0;
+ //todo: simpfy this calc, just use energy relative to energy time
+
+ long energyCost = 0;
// Avoid overflows
if (newMemSize.compareTo(MAX_MEM_SIZE) > 0) {
-// throw VMMemoryOverflowException();
-
- throw Program.Exception.gasOverflow(newMemSize, MAX_MEM_SIZE);
-//
-// throw Program.Exception.memoryOverflow()
+ // throw VMMemoryOverflowException();
+ throw Program.Exception.energyOverflow(newMemSize, MAX_MEM_SIZE);
+ // todo: add memory overflow
+ // throw Program.Exception.memoryOverflow();
}
// memory drop consume calc
@@ -78,21 +81,21 @@ private long calcMemDrop(DropCost dropCosts, long oldMemSize, BigInteger newMemS
long memWords = (memoryUsage / 32);
long memWordsOld = (oldMemSize / 32);
//TODO #POC9 c_quadCoeffDiv = 512, this should be a constant, not magic number
- long memDrop = (dropCosts.getMEMORY() * memWords + memWords * memWords / 512)
- - (dropCosts.getMEMORY() * memWordsOld + memWordsOld * memWordsOld / 512);
- dropConsume += memDrop;
+ long memEnergy = (energyCosts.getMEMORY() * memWords + memWords * memWords / 512)
+ - (energyCosts.getMEMORY() * memWordsOld + memWordsOld * memWordsOld / 512);
+ energyCost += memEnergy;
}
if (copySize > 0) {
- long copyDrop = dropCosts.getCOPY_GAS() * ((copySize + 31) / 32);
- dropConsume += copyDrop;
+ long copyEnergy = energyCosts.getCOPY_ENERGY() * ((copySize + 31) / 32);
+ energyCost += copyEnergy;
}
- return dropConsume;
+ return energyCost;
}
public void step(Program program)
- throws ContractExeException, OutOfResourceException {
- if (vmTrace) {
+ throws ContractValidateException {
+ if (config.vmTrace()) {
program.saveOpTrace();
}
@@ -132,84 +135,93 @@ public void step(Program program)
Stack stack = program.getStack();
String hint = "";
- long callGas = 0, memWords = 0; // parameters for logging
- long dropCost = op.getTier().asInt();
- long dropBefore = program.getDroplimitLong();
- int stepBefore = program.getPC();
- DropCost dropCosts = DropCost.getInstance();
- DataWord adjustedCallGas = null;
-
- // Calculate fees and spend drops
+ long callEnergy = 0, memWords = 0; // parameters for logging
+ long energyCost = op.getTier().asInt();
+ EnergyCost energyCosts = EnergyCost.getInstance();
+ DataWord adjustedCallEnergy = null;
+
+ // Calculate fees and spend energy
switch (op) {
case STOP:
- dropCost = dropCosts.getSTOP();
+ energyCost = energyCosts.getSTOP();
break;
case SUICIDE:
- dropCost = dropCosts.getSUICIDE();
+ energyCost = energyCosts.getSUICIDE();
+ DataWord suicideAddressWord = stack.get(stack.size() - 1);
+ if (isDeadAccount(program, suicideAddressWord) &&
+ !program.getBalance(program.getOwnerAddress()).isZero()) {
+ energyCost += energyCosts.getNEW_ACCT_SUICIDE();
+ }
break;
case SSTORE:
+ // todo: check the reset to 0, refund or not
DataWord newValue = stack.get(stack.size() - 2);
DataWord oldValue = program.storageLoad(stack.peek());
if (oldValue == null && !newValue.isZero()) {
- dropCost = dropCosts.getSET_SSTORE();
+ // set a new not-zero value
+ energyCost = energyCosts.getSET_SSTORE();
} else if (oldValue != null && newValue.isZero()) {
- // todo: GASREFUND counter policy
-
- // refund step cost policy.
- program.futureRefundGas(dropCosts.getREFUND_SSTORE());
- dropCost = dropCosts.getCLEAR_SSTORE();
+ // set zero to an old value
+ program.futureRefundEnergy(energyCosts.getREFUND_SSTORE());
+ energyCost = energyCosts.getCLEAR_SSTORE();
} else {
- dropCost = dropCosts.getRESET_SSTORE();
+ // include:
+ // [1] oldValue == null && newValue == 0
+ // [2] oldValue != null && newValue != 0
+ energyCost = energyCosts.getRESET_SSTORE();
}
break;
case SLOAD:
- dropCost = dropCosts.getSLOAD();
+ energyCost = energyCosts.getSLOAD();
break;
case BALANCE:
- dropCost = dropCosts.getBALANCE();
+ energyCost = energyCosts.getBALANCE();
break;
// These all operate on memory and therefore potentially expand it:
case MSTORE:
- dropCost += calcMemDrop(dropCosts, oldMemSize, memNeeded(stack.peek(), new DataWord(32)),
+ energyCost = calcMemEnergy(energyCosts, oldMemSize,
+ memNeeded(stack.peek(), new DataWord(32)),
0);
break;
case MSTORE8:
- dropCost += calcMemDrop(dropCosts, oldMemSize, memNeeded(stack.peek(), new DataWord(1)),
+ energyCost = calcMemEnergy(energyCosts, oldMemSize,
+ memNeeded(stack.peek(), new DataWord(1)),
0);
break;
case MLOAD:
- dropCost += calcMemDrop(dropCosts, oldMemSize, memNeeded(stack.peek(), new DataWord(32)),
+ energyCost = calcMemEnergy(energyCosts, oldMemSize,
+ memNeeded(stack.peek(), new DataWord(32)),
0);
break;
case RETURN:
case REVERT:
- dropCost = dropCosts.getSTOP() + calcMemDrop(dropCosts, oldMemSize,
+ energyCost = energyCosts.getSTOP() + calcMemEnergy(energyCosts, oldMemSize,
memNeeded(stack.peek(), stack.get(stack.size() - 2)), 0);
break;
case SHA3:
- dropCost = dropCosts.getSHA3() + calcMemDrop(dropCosts, oldMemSize,
+ energyCost = energyCosts.getSHA3() + calcMemEnergy(energyCosts, oldMemSize,
memNeeded(stack.peek(), stack.get(stack.size() - 2)), 0);
DataWord size = stack.get(stack.size() - 2);
long chunkUsed = (size.longValueSafe() + 31) / 32;
- dropCost += chunkUsed * dropCosts.getSHA3_WORD();
+ energyCost += chunkUsed * energyCosts.getSHA3_WORD();
break;
case CALLDATACOPY:
case RETURNDATACOPY:
- dropCost += calcMemDrop(dropCosts, oldMemSize,
+ energyCost = calcMemEnergy(energyCosts, oldMemSize,
memNeeded(stack.peek(), stack.get(stack.size() - 3)),
stack.get(stack.size() - 3).longValueSafe());
break;
case CODECOPY:
- dropCost += calcMemDrop(dropCosts, oldMemSize,
+ energyCost = calcMemEnergy(energyCosts, oldMemSize,
memNeeded(stack.peek(), stack.get(stack.size() - 3)),
stack.get(stack.size() - 3).longValueSafe());
break;
case EXTCODESIZE:
- dropCost = dropCosts.getEXT_CODE_SIZE();
+ energyCost = energyCosts.getEXT_CODE_SIZE();
break;
case EXTCODECOPY:
- dropCost = dropCosts.getEXT_CODE_COPY() + calcMemDrop(dropCosts, oldMemSize,
+ energyCost = energyCosts.getEXT_CODE_COPY() + calcMemEnergy(energyCosts, oldMemSize,
memNeeded(stack.get(stack.size() - 2), stack.get(stack.size() - 4)),
stack.get(stack.size() - 4).longValueSafe());
break;
@@ -217,23 +229,24 @@ public void step(Program program)
case CALLCODE:
case DELEGATECALL:
case STATICCALL:
-
- dropCost = dropCosts.getCALL();
- DataWord callGasWord = stack.get(stack.size() - 1);
-
+ // here, contract call an other contract, or a library, and so on
+ // todo: check the callvalue here
+ energyCost = energyCosts.getCALL();
+ DataWord callEnergyWord = stack.get(stack.size() - 1);
DataWord callAddressWord = stack.get(stack.size() - 2);
-
DataWord value = op.callHasValue() ?
stack.get(stack.size() - 3) : DataWord.ZERO;
//check to see if account does not exist and is not a precompiled contract
if (op == CALL) {
- dropCost = dropCosts.getNEW_ACCT_CALL();
+ if (isDeadAccount(program, callAddressWord) && !value.isZero()) {
+ energyCost += energyCosts.getNEW_ACCT_CALL();
+ }
}
- //TODO #POC9 Make sure this is converted to BigInteger (256num support)
+ // TODO #POC9 Make sure this is converted to BigInteger (256num support)
if (!value.isZero()) {
- dropCost += dropCosts.getVT_CALL();
+ energyCost += energyCosts.getVT_CALL();
}
int opOff = op.callHasValue() ? 4 : 3;
@@ -241,24 +254,23 @@ public void step(Program program)
stack.get(stack.size() - opOff - 1)); // in offset+size
BigInteger out = memNeeded(stack.get(stack.size() - opOff - 2),
stack.get(stack.size() - opOff - 3)); // out offset+size
- // dropCost += calcMemDrop(dropCosts, oldMemSize, in.max(out), 0);
+ energyCost += calcMemEnergy(energyCosts, oldMemSize, in.max(out), 0);
checkMemorySize(op, in.max(out));
- //TODO: recover this or give similar logic when tron cost mechanism is ready.
-// if (dropCost > program.getDroplimit().longValueSafe()) {
-// throw Program.Exception.notEnoughOpGas(op, callGasWord, program.getDroplimit());
-// }
-
- DataWord gasLeft = program.getDroplimit().clone();
- gasLeft.sub(new DataWord(dropCost));
- //adjustedCallGas = tronConfig.getCallGas(op, callGasWord, gasLeft);
- //adjustedCallGas = new DataWord(tronConfig.getDropCost().getCALL());
- //TODO: remove below and recover above statment when config is ready
- adjustedCallGas = new DataWord();
- dropCost += adjustedCallGas.longValueSafe();
+ if (energyCost > program.getEnergyLimitLeft().longValueSafe()) {
+ throw new OutOfEnergyException(
+ "Not enough energy for '%s' operation executing: opEnergy[%d], programEnergy[%d]",
+ op.name(),
+ energyCost, program.getEnergyLimitLeft().longValueSafe());
+ }
+ DataWord getEnergyLimitLeft = program.getEnergyLimitLeft().clone();
+ getEnergyLimitLeft.sub(new DataWord(energyCost));
+
+ adjustedCallEnergy = program.getCallEnergy(op, callEnergyWord, getEnergyLimitLeft);
+ energyCost += adjustedCallEnergy.longValueSafe();
break;
case CREATE:
- dropCost = dropCosts.getCREATE() + calcMemDrop(dropCosts, oldMemSize,
+ energyCost = energyCosts.getCREATE() + calcMemEnergy(energyCosts, oldMemSize,
memNeeded(stack.get(stack.size() - 2), stack.get(stack.size() - 3)), 0);
break;
case LOG0:
@@ -266,39 +278,39 @@ public void step(Program program)
case LOG2:
case LOG3:
case LOG4:
-
int nTopics = op.val() - OpCode.LOG0.val();
-
BigInteger dataSize = stack.get(stack.size() - 2).value();
BigInteger dataCost = dataSize
- .multiply(BigInteger.valueOf(dropCosts.getLOG_DATA_GAS()));
-// if (program.getDroplimit().value().compareTo(dataCost) < 0) {
-// throw Program.Exception.notEnoughOpGas(op, dataCost, program.getDroplimit().value());
-// }
-
- dropCost = dropCosts.getLOG_GAS() +
- dropCosts.getLOG_TOPIC_GAS() * nTopics +
- dropCosts.getLOG_DATA_GAS() * stack.get(stack.size() - 2).longValue() +
- calcMemDrop(dropCosts, oldMemSize,
- memNeeded(stack.peek(), stack.get(stack.size() - 2)), 0);
- checkMemorySize(op,
- memNeeded(stack.peek(), stack.get(stack.size() - 2)));
+ .multiply(BigInteger.valueOf(energyCosts.getLOG_DATA_ENERGY()));
+ if (program.getEnergyLimitLeft().value().compareTo(dataCost) < 0) {
+ throw new OutOfEnergyException(
+ "Not enough energy for '%s' operation executing: opEnergy[%d], programEnergy[%d]",
+ op.name(),
+ dataCost.longValue(), program.getEnergyLimitLeft().longValueSafe());
+ }
+ energyCost = energyCosts.getLOG_ENERGY() +
+ energyCosts.getLOG_TOPIC_ENERGY() * nTopics +
+ energyCosts.getLOG_DATA_ENERGY() * stack.get(stack.size() - 2).longValue() +
+ calcMemEnergy(energyCosts, oldMemSize,
+ memNeeded(stack.peek(), stack.get(stack.size() - 2)),
+ 0);
+
+ checkMemorySize(op, memNeeded(stack.peek(), stack.get(stack.size() - 2)));
break;
case EXP:
DataWord exp = stack.get(stack.size() - 2);
int bytesOccupied = exp.bytesOccupied();
- dropCost = dropCosts.getEXP_GAS() + dropCosts.getEXP_BYTE_GAS() * bytesOccupied;
+ energyCost =
+ energyCosts.getEXP_ENERGY() + energyCosts.getEXP_BYTE_ENERGY() * bytesOccupied;
break;
default:
break;
}
- // DEBUG System.out.println(" OP IS " + op.name() + " GASCOST IS " + gasCost + " NUM IS " + op.asInt());
- // program.spendDrop(dropCost, op.name());
-
- //TODO: recover this after it is ready.
- // program.checkCPULimit(op.name());
+ // DEBUG System.out.println(" OP IS " + op.name() + " ENERGYCOST IS " + energyCost + " NUM IS " + op.asInt());
+ program.spendEnergy(energyCost, op.name());
+ program.checkCPUTimeLimit(op.name());
// logger.info("after opName: {}, {}", op.name(), System.nanoTime() / 1000 - lastTime);
// Execute operation
@@ -848,13 +860,13 @@ public void step(Program program)
}
break;
case GASPRICE: {
- DataWord gasPrice = new DataWord(0);
+ DataWord energyPrice = new DataWord(0);
if (logger.isInfoEnabled()) {
- hint = "price: " + gasPrice.toString();
+ hint = "price: " + energyPrice.toString();
}
- program.stackPush(gasPrice);
+ program.stackPush(energyPrice);
program.step();
}
break;
@@ -921,13 +933,14 @@ public void step(Program program)
}
break;
case GASLIMIT: {
- DataWord droplimit = new DataWord(0);
+ // todo: this energylimit is the block's energy limit
+ DataWord energyLimit = new DataWord(0);
if (logger.isInfoEnabled()) {
- hint = "gaslimit: " + droplimit;
+ hint = "energylimit: " + energyLimit;
}
- program.stackPush(droplimit);
+ program.stackPush(energyLimit);
program.step();
}
break;
@@ -1137,13 +1150,12 @@ public void step(Program program)
}
break;
case GAS: {
- DataWord gas = new DataWord(0);
-
+ DataWord energy = program.getEnergyLimitLeft();
if (logger.isInfoEnabled()) {
- hint = "" + gas;
+ hint = "" + energy;
}
- program.stackPush(gas);
+ program.stackPush(energy);
program.step();
}
break;
@@ -1221,8 +1233,10 @@ public void step(Program program)
case CALLCODE:
case DELEGATECALL:
case STATICCALL: {
- program.stackPop(); // use adjustedCallGas instead of requested
+ program.stackPop(); // use adjustedCallEnergy instead of requested
DataWord codeAddress = program.stackPop();
+
+ // todo: check the callvalue >= 0
DataWord value = op.callHasValue() ?
program.stackPop() : DataWord.ZERO;
@@ -1231,7 +1245,7 @@ public void step(Program program)
}
if (!value.isZero()) {
- adjustedCallGas.add(new DataWord(dropCosts.getSTIPEND_CALL()));
+ adjustedCallEnergy.add(new DataWord(energyCosts.getSTIPEND_CALL()));
}
DataWord inDataOffs = program.stackPop();
@@ -1242,19 +1256,19 @@ public void step(Program program)
if (logger.isInfoEnabled()) {
hint = "addr: " + Hex.toHexString(codeAddress.getLast20Bytes())
- + " gas: " + adjustedCallGas.shortHex()
+ + " energy: " + adjustedCallEnergy.shortHex()
+ " inOff: " + inDataOffs.shortHex()
+ " inSize: " + inDataSize.shortHex();
logger.info(logString, String.format("%5s", "[" + program.getPC() + "]"),
String.format("%-12s", op.name()),
- program.getDroplimit().value(),
+ program.getEnergyLimitLeft().value(),
program.getCallDeep(), hint);
}
program.memoryExpand(outDataOffs, outDataSize);
MessageCall msg = new MessageCall(
- op, adjustedCallGas, codeAddress, value, inDataOffs, inDataSize,
+ op, adjustedCallEnergy, codeAddress, value, inDataOffs, inDataSize,
outDataOffs, outDataSize);
PrecompiledContracts.PrecompiledContract contract =
@@ -1325,8 +1339,8 @@ public void step(Program program)
*/
vmCounter++;
} catch (RuntimeException e) {
- logger.warn("VM halted: [{}]", e);
- program.spendAllGas();
+ logger.warn("VM halted: [{}]", e.getMessage());
+ program.spendAllEnergy();
program.resetFutureRefund();
program.stop();
throw e;
@@ -1335,8 +1349,7 @@ public void step(Program program)
}
}
- public void play(Program program)
- throws ContractExeException {
+ public void play(Program program) {
try {
if (program.byTestingSuite()) {
return;
@@ -1348,6 +1361,8 @@ public void play(Program program)
} catch (RuntimeException e) {
program.setRuntimeFailure(e);
+ } catch (ContractValidateException e) {
+ program.setRuntimeFailure(new RuntimeException(e.getMessage()));
} catch (StackOverflowError soe) {
logger
.error("\n !!! StackOverflowError: update your java run command with -Xss2M !!!\n", soe);
@@ -1357,6 +1372,10 @@ public void play(Program program)
}
}
+ private boolean isDeadAccount(Program program, DataWord address) {
+ return program.getContractState().getAccount(convertToTronAddress(address.getLast20Bytes()))
+ == null;
+ }
/**
* Utility to calculate new total memory size needed for an operation. Basically just offset
diff --git a/src/main/java/org/tron/common/runtime/vm/program/ContractState.java b/src/main/java/org/tron/common/runtime/vm/program/ContractState.java
new file mode 100644
index 00000000000..24b964fca45
--- /dev/null
+++ b/src/main/java/org/tron/common/runtime/vm/program/ContractState.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) [2016] [ ]
+ * This file is part of the ethereumJ library.
+ *
+ * The ethereumJ library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The ethereumJ library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ethereumJ library. If not, see .
+ */
+package org.tron.common.runtime.vm.program;
+
+import org.tron.common.runtime.vm.DataWord;
+import org.tron.common.runtime.vm.program.invoke.ProgramInvoke;
+import org.tron.common.runtime.vm.program.listener.ProgramListener;
+import org.tron.common.runtime.vm.program.listener.ProgramListenerAware;
+import org.tron.common.storage.Deposit;
+import org.tron.common.storage.Key;
+import org.tron.common.storage.Value;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.capsule.BlockCapsule;
+import org.tron.core.capsule.BytesCapsule;
+import org.tron.core.capsule.ContractCapsule;
+import org.tron.core.capsule.TransactionCapsule;
+import org.tron.core.db.Manager;
+import org.tron.protos.Protocol;
+import org.tron.protos.Protocol.AccountType;
+
+public class ContractState implements Deposit, ProgramListenerAware {
+
+ private Deposit deposit;
+ private final DataWord address; // contract address
+ private ProgramListener programListener;
+
+ public ContractState(ProgramInvoke programInvoke) {
+ this.address = programInvoke.getOwnerAddress(); // contract address
+ this.deposit = programInvoke.getDeposit();
+ }
+
+ @Override
+ public Manager getDbManager() {
+ return deposit.getDbManager();
+ }
+
+ @Override
+ public void setProgramListener(ProgramListener listener) {
+ this.programListener = listener;
+ }
+
+ @Override
+ public AccountCapsule createAccount(byte[] addr, Protocol.AccountType type) {
+ return deposit.createAccount(addr, type);
+ }
+
+ @Override
+ public AccountCapsule createAccount(byte[] address, String accountName, AccountType type) {
+ return deposit.createAccount(address, accountName, type);
+ }
+
+
+ @Override
+ public AccountCapsule getAccount(byte[] addr) {
+ return deposit.getAccount(addr);
+ }
+
+ @Override
+ public void createContract(byte[] codeHash, ContractCapsule contractCapsule) {
+ deposit.createContract(codeHash, contractCapsule);
+ }
+
+ @Override
+ public ContractCapsule getContract(byte[] codeHash) {
+ return deposit.getContract(codeHash);
+ }
+
+ @Override
+ public void saveCode(byte[] addr, byte[] code) {
+ deposit.saveCode(addr, code);
+ }
+
+ @Override
+ public byte[] getCode(byte[] addr) {
+ return deposit.getCode(addr);
+ }
+
+ /*
+ @Override
+ public byte[] getCodeHash(byte[] addr) {
+ return deposit.getCodeHash(addr);
+ }
+ */
+
+ @Override
+ public void putStorageValue(byte[] addr, DataWord key, DataWord value) {
+ if (canListenTrace(addr)) {
+ programListener.onStoragePut(key, value);
+ }
+ deposit.putStorageValue(addr, key, value);
+ }
+
+ private boolean canListenTrace(byte[] address) {
+ return (programListener != null) && this.address.equals(new DataWord(address));
+ }
+
+ @Override
+ public DataWord getStorageValue(byte[] addr, DataWord key) {
+ return deposit.getStorageValue(addr, key);
+ }
+
+ @Override
+ public long getBalance(byte[] addr) {
+ return deposit.getBalance(addr);
+ }
+
+ @Override
+ public long addBalance(byte[] addr, long value) {
+ return deposit.addBalance(addr, value);
+ }
+
+ @Override
+ public Deposit newDepositChild() {
+ return deposit.newDepositChild();
+ }
+
+ @Override
+ public Deposit newDepositNext() {
+ return deposit.newDepositNext();
+ }
+
+ @Override
+ public void flush() {
+ deposit.flush();
+ }
+
+ @Override
+ public void commit() {
+ deposit.commit();
+ }
+
+// @Override
+// public StorageCapsule getContractState(byte[] address) {
+// return deposit.getContractState(address);
+// }
+
+ @Override
+ public Storage getStorage(byte[] address) {
+ return deposit.getStorage(address);
+ }
+
+ @Override
+ public void putAccount(Key key, Value value) {
+ deposit.putAccount(key, value);
+ }
+
+ @Override
+ public void putTransaction(Key key, Value value) {
+ deposit.putTransaction(key, value);
+ }
+
+ @Override
+ public void putBlock(Key key, Value value) {
+ deposit.putBlock(key, value);
+ }
+
+ @Override
+ public void putWitness(Key key, Value value) {
+ deposit.putWitness(key, value);
+ }
+
+ @Override
+ public void putCode(Key key, Value value) {
+ deposit.putCode(key, value);
+ }
+
+ @Override
+ public void putContract(Key key, Value value) {
+ deposit.putContract(key, value);
+ }
+
+ @Override
+ public void putStorage(Key key, Storage cache) {
+ deposit.putStorage(key, cache);
+ }
+
+ @Override
+ public void putVotes(Key key, Value value) {
+ deposit.putVotes(key, value);
+ }
+
+ @Override
+ public void setParent(Deposit deposit) {
+ this.deposit.setParent(deposit);
+ }
+
+ @Override
+ public void setPrevDeposit(Deposit deposit) {
+ this.deposit.setPrevDeposit(deposit);
+ }
+
+ @Override
+ public void setNextDeposit(Deposit deposit) {
+ this.deposit.setNextDeposit(deposit);
+ }
+
+ @Override
+ public TransactionCapsule getTransaction(byte[] trxHash) {
+ return this.deposit.getTransaction(trxHash);
+ }
+
+ @Override
+ // Do nothing
+ public void syncCacheFromAccountStore(byte[] address) {
+ }
+
+ @Override
+ // Do nothing
+ public void syncCacheFromVotesStore(byte[] address) {
+ }
+
+ @Override
+ public BlockCapsule getBlock(byte[] blockHash) {
+ return this.deposit.getBlock(blockHash);
+ }
+
+ @Override
+ public long computeAfterRunStorageSize() {
+ return this.deposit.computeAfterRunStorageSize();
+ }
+
+ @Override
+ public long getBeforeRunStorageSize() {
+ return this.deposit.getBeforeRunStorageSize();
+ }
+}
diff --git a/src/main/java/org/tron/common/runtime/vm/program/InternalTransaction.java b/src/main/java/org/tron/common/runtime/vm/program/InternalTransaction.java
index 2264270ac85..05b0a79f157 100644
--- a/src/main/java/org/tron/common/runtime/vm/program/InternalTransaction.java
+++ b/src/main/java/org/tron/common/runtime/vm/program/InternalTransaction.java
@@ -21,22 +21,43 @@
import static org.apache.commons.lang3.ArrayUtils.nullToEmpty;
import static org.tron.common.utils.ByteUtil.toHexString;
+import com.google.common.primitives.Longs;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
+import java.util.Arrays;
import org.tron.common.crypto.ECKey;
+import org.tron.common.crypto.ECKey.ECDSASignature;
+import org.tron.common.crypto.Hash;
import org.tron.common.runtime.vm.DataWord;
import org.tron.common.utils.ByteUtil;
+import org.tron.core.capsule.TransactionCapsule;
import org.tron.protos.Protocol.Transaction;
-//import org.tron.common.utils.RLP;
-
-public class InternalTransaction extends VMTransaction {
+public class InternalTransaction {
+ private Transaction transaction;
+ private byte[] hash;
private byte[] parentHash;
+ /* the amount of trx to transfer (calculated as sun) */
+ private long value;
+
+ /* the address of the destination account
+ * In creation transaction the receive address is - 0 */
+ private byte[] receiveAddress;
+
+ /* An unlimited size byte array specifying
+ * input [data] of the message call or
+ * Initialization code for a new contract */
+ private byte[] data;
+
+ protected byte[] sendAddress;
private int deep;
private int index;
private boolean rejected = false;
private String note;
+ private boolean parsed;
+ private byte[] protoEncoded;
+
public enum TrxType {
TRX_PRECOMPILED_TYPE,
@@ -45,38 +66,47 @@ public enum TrxType {
TRX_UNKNOWN_TYPE,
}
- ;
-
- public enum ExecuterType {
+ public enum ExecutorType {
ET_PRE_TYPE,
ET_NORMAL_TYPE,
ET_CONSTANT_TYPE,
ET_UNKNOWN_TYPE,
}
- public InternalTransaction(byte[] rawData) {
- super(rawData);
- }
- public InternalTransaction(Transaction tx) {
- super(tx);
+ /**
+ * Construct an un-encoded InternalTransaction
+ */
+ public InternalTransaction(Transaction trx) {
+ this.transaction = trx;
+ this.protoEncoded = new TransactionCapsule(trx).getData();
+ this.parsed = false;
}
+ /**
+ * Construct an encoded InternalTransaction
+ */
+
public InternalTransaction(byte[] parentHash, int deep, int index,
byte[] sendAddress, byte[] receiveAddress, long value, byte[] data, String note) {
- super(receiveAddress, value, nullToEmpty(data));
-
this.parentHash = parentHash;
this.deep = deep;
this.index = index;
- this.sendAddress = nullToEmpty(sendAddress);
this.note = note;
+ this.sendAddress = nullToEmpty(sendAddress);
+ this.receiveAddress = nullToEmpty(receiveAddress);
+ this.value = value;
+ this.data = nullToEmpty(data);
this.parsed = true;
}
- private static byte[] getData(DataWord gasPrice) {
- return (gasPrice == null) ? ByteUtil.EMPTY_BYTE_ARRAY : gasPrice.getData();
+ public Transaction getTransaction() {
+ return transaction;
+ }
+
+ public void setTransaction(Transaction transaction) {
+ this.transaction = transaction;
}
public void reject() {
@@ -104,7 +134,6 @@ public String getNote() {
return note;
}
- @Override
public byte[] getSender() {
protoParse();
return sendAddress;
@@ -115,87 +144,67 @@ public byte[] getParentHash() {
return parentHash;
}
-// @Override
-// public byte[] getEncoded() {
-// if (protoEncoded == null) {
-// /*
-// this.protoEncoded = RLP.encodeList(
-// RLP.encodeElement(isEmptyNonce ? null : nonce),
-// RLP.encodeElement(this.parentHash),
-// RLP.encodeElement(getSender()),
-// RLP.encodeElement(getReceiveAddress()),
-// RLP.encodeElement(getValue()),
-// RLP.encodeElement(getGasPrice()),
-// RLP.encodeElement(getGasLimit()),
-// RLP.encodeElement(getData()),
-// RLP.encodeString(this.note),
-// encodeInt(this.deep),
-// encodeInt(this.index),
-// encodeInt(this.rejected ? 1 : 0)
-// );
-// */
-// }
-//
-// return protoEncoded;
-// }
+ public long getValue() {
+ protoParse();
+ return value;
+ }
- @Override
- public byte[] getEncodedRaw() {
- return getEncoded();
- }
-
-// @Override
-// public synchronized void protoParse() {
-// if (parsed) return;
-// /*
-// RLPList decodedTxList = RLP.decode2(rlpEncoded);
-// RLPList transaction = (RLPList) decodedTxList.get(0);
-//
-// this.parentHash = transaction.get(1).getRLPData();
-// this.sendAddress = transaction.get(2).getRLPData();
-// setReceiveAddress(transaction.get(3).getRLPData());
-// setValue(transaction.get(4).getRLPData());
-// setGasPrice(transaction.get(5).getRLPData());
-// setGasLimit(transaction.get(6).getRLPData());
-// setData(transaction.get(7).getRLPData());
-// this.note = new String(transaction.get(8).getRLPData());
-// this.deep = decodeInt(transaction.get(9).getRLPData());
-// this.index = decodeInt(transaction.get(10).getRLPData());
-// this.rejected = decodeInt(transaction.get(11).getRLPData()) == 1;
-// */
-// this.parsed = true;
-// }
-
-
- private static byte[] intToBytes(int value) {
- return ByteBuffer.allocate(Integer.SIZE / Byte.SIZE)
- .order(ByteOrder.LITTLE_ENDIAN)
- .putInt(value)
- .array();
- }
-
- private static int bytesToInt(byte[] bytes) {
- return isEmpty(bytes) ? 0 : ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).getInt();
- }
-
- /*
- private static byte[] encodeInt(int value) {
- return RLP.encodeElement(intToBytes(value));
- }
- */
+ public byte[] getData() {
+ protoParse();
+ return data.clone();
+ }
- private static int decodeInt(byte[] encoded) {
- return bytesToInt(encoded);
+ protected void setValue(long value) {
+ this.value = value;
+ parsed = true;
}
- @Override
- public ECKey getKey() {
- throw new UnsupportedOperationException("Cannot sign internal transaction.");
+ public byte[] getReceiveAddress() {
+ protoParse();
+ return receiveAddress.clone();
}
- @Override
- public void sign(byte[] privKeyBytes) throws ECKey.MissingPrivateKeyException {
- throw new UnsupportedOperationException("Cannot sign internal transaction.");
+ private void protoParse() {
+ if (parsed) {
+ return;
+ }
+ try {
+ this.hash = Hash.sha3(protoEncoded);
+ this.parsed = true;
+ } catch (Exception e) {
+ throw new RuntimeException("Error on parsing proto", e);
+ }
+ }
+
+ public byte[] getHash() {
+ if (!isEmpty(hash)) {
+ return Arrays.copyOf(hash, hash.length);
+ }
+
+ protoParse();
+ byte[] plainMsg = this.getEncoded();
+ return Hash.sha3(plainMsg);
+ }
+
+
+ public byte[] getEncoded() {
+
+ if (protoEncoded != null) {
+ if (null == this.hash) {
+ this.hash = Hash.sha3(protoEncoded);
+ }
+ return protoEncoded.clone();
+ }
+
+ byte[] valueByte = Longs.toByteArray(this.value);
+ byte[] raw = new byte[this.receiveAddress.length + this.data.length + valueByte.length];
+ System.arraycopy(this.receiveAddress, 0, raw, 0, this.receiveAddress.length);
+ System.arraycopy(this.data, 0, raw, this.receiveAddress.length, this.data.length);
+ System.arraycopy(valueByte, 0, raw, this.data.length, valueByte.length);
+ this.protoEncoded = raw;
+ this.hash = Hash.sha3(protoEncoded);
+
+ return protoEncoded.clone();
}
@Override
diff --git a/src/main/java/org/tron/common/runtime/vm/program/Memory.java b/src/main/java/org/tron/common/runtime/vm/program/Memory.java
index 21c880c48e0..486be28ec09 100644
--- a/src/main/java/org/tron/common/runtime/vm/program/Memory.java
+++ b/src/main/java/org/tron/common/runtime/vm/program/Memory.java
@@ -121,8 +121,7 @@ public void extend(int address, int size) {
return;
}
- final int newSize = address + size;
-
+ final int newSize = Math.addExact(address,size);
int toAllocate = newSize - internalSize();
if (toAllocate > 0) {
addChunks((int) ceil((double) toAllocate / CHUNK_SIZE));
@@ -131,7 +130,7 @@ public void extend(int address, int size) {
toAllocate = newSize - softSize;
if (toAllocate > 0) {
toAllocate = (int) ceil((double) toAllocate / WORD_SIZE) * WORD_SIZE;
- softSize += toAllocate;
+ softSize = Math.addExact(softSize , toAllocate );
if (programListener != null) {
programListener.onMemoryExtend(toAllocate);
diff --git a/src/main/java/org/tron/common/runtime/vm/program/Program.java b/src/main/java/org/tron/common/runtime/vm/program/Program.java
index 3952ea41946..7fb128a50be 100644
--- a/src/main/java/org/tron/common/runtime/vm/program/Program.java
+++ b/src/main/java/org/tron/common/runtime/vm/program/Program.java
@@ -29,6 +29,7 @@
import static org.tron.common.utils.BIUtil.isPositive;
import static org.tron.common.utils.BIUtil.toBI;
+import com.google.protobuf.ByteString;
import java.io.ByteArrayOutputStream;
import java.math.BigInteger;
import java.util.Arrays;
@@ -37,16 +38,13 @@
import java.util.Map;
import java.util.NavigableSet;
import java.util.TreeSet;
+import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.tuple.Pair;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
-import org.tron.common.crypto.ECKey;
-import org.tron.common.runtime.config.DefaultConfig;
import org.tron.common.runtime.config.SystemProperties;
import org.tron.common.runtime.vm.DataWord;
-import org.tron.common.runtime.vm.DropCost;
import org.tron.common.runtime.vm.MessageCall;
import org.tron.common.runtime.vm.OpCode;
import org.tron.common.runtime.vm.PrecompiledContracts;
@@ -65,23 +63,50 @@
import org.tron.common.utils.FastByteComparisons;
import org.tron.common.utils.Sha256Hash;
import org.tron.common.utils.Utils;
+import org.tron.core.Wallet;
+import org.tron.core.actuator.TransferActuator;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.BlockCapsule;
-import org.tron.core.exception.ContractExeException;
+import org.tron.core.capsule.ContractCapsule;
+import org.tron.core.config.args.Args;
+import org.tron.core.exception.ContractValidateException;
import org.tron.protos.Protocol;
+import org.tron.protos.Protocol.SmartContract;
/**
* @author Roman Mandeleil
* @since 01.06.2014
*/
+
+@Slf4j(topic = "Program")
+
public class Program {
- private static final Logger logger = LoggerFactory.getLogger("VM");
+ // private static final Logger logger = LoggerFactory.getLogger("VM");
private static final int MAX_DEPTH = 1024;
//Max size for stack checks
private static final int MAX_STACKSIZE = 1024;
+ public static byte[] getRootTransactionId() {
+ return rootTransactionId.clone();
+ }
+
+ public static void setRootTransactionId(byte[] rootTransactionId) {
+ Program.rootTransactionId = rootTransactionId.clone();
+ }
+
+ public static long getNonce() {
+ return nonce;
+ }
+
+ public static void setNonce(long nonceValue) {
+ nonce = nonceValue;
+ }
+
+ private static long nonce = 0;
+ private static byte[] rootTransactionId = null;
+
private InternalTransaction transaction;
private ProgramInvoke invoke;
@@ -94,7 +119,7 @@ public class Program {
private Stack stack;
private Memory memory;
- private Storage storage;
+ private ContractState contractState;
private byte[] returnDataBuffer;
private ProgramResult result = new ProgramResult();
@@ -112,12 +137,14 @@ public class Program {
private final SystemProperties config;
+ //private byte[] transactionHash;
+
public Program(byte[] ops, ProgramInvoke programInvoke) {
this(ops, programInvoke, null);
}
public Program(byte[] ops, ProgramInvoke programInvoke, InternalTransaction transaction) {
- this(ops, programInvoke, transaction, SystemProperties.getDefault());
+ this(ops, programInvoke, transaction, SystemProperties.getInstance());
}
public Program(byte[] ops, ProgramInvoke programInvoke, InternalTransaction transaction,
@@ -134,11 +161,13 @@ public Program(byte[] codeHash, byte[] ops, ProgramInvoke programInvoke,
//this.codeHash = codeHash;
this.ops = nullToEmpty(ops);
- //traceListener = new ProgramTraceListener(config.vmTrace());
+ traceListener = new ProgramTraceListener(config.vmTrace());
this.memory = setupProgramListener(new Memory());
this.stack = setupProgramListener(new Stack());
- this.storage = setupProgramListener(new Storage(programInvoke));
- //this.trace = new ProgramTrace(config, programInvoke);
+ this.contractState = setupProgramListener(new ContractState(programInvoke));
+ this.trace = new ProgramTrace(config, programInvoke);
+
+ //this.transactionHash = transaction.getHash();
}
public ProgramPrecompile getProgramPrecompile() {
@@ -166,15 +195,16 @@ public int getCallDeep() {
return invoke.getCallDeep();
}
- private InternalTransaction addInternalTx(DataWord dropLimit, byte[] senderAddress,
+ private InternalTransaction addInternalTx(DataWord energyLimit, byte[] senderAddress,
byte[] receiveAddress,
long value, byte[] data, String note) {
+ // todo: now, internal transaction needn't energylimit
InternalTransaction result = null;
if (transaction != null) {
//data = config.recordInternalTransactionsData() ? data : null;
//result = getResult().addInternalTransaction(transaction.getHash(), getCallDeep(),
- // getGasPrice(), gasLimit, senderAddress, receiveAddress, value.toByteArray(), data, note);
+ // getEnergyPrice(), energyLimit, senderAddress, receiveAddress, value.toByteArray(), data, note);
result = getResult().addInternalTransaction(transaction.getHash(), getCallDeep(),
senderAddress, receiveAddress, value, data, note);
}
@@ -184,7 +214,7 @@ private InternalTransaction addInternalTx(DataWord dropLimit, byte[] senderAddre
private T setupProgramListener(T programListenerAware) {
if (programListener.isEmpty()) {
- //programListener.addListener(traceListener);
+ programListener.addListener(traceListener);
programListener.addListener(storageDiffListener);
}
@@ -376,11 +406,11 @@ public void allocateMemory(int offset, int size) {
public void suicide(DataWord obtainerAddress)
- throws ContractExeException {
+ throws ContractValidateException {
byte[] owner = convertToTronAddress(getOwnerAddress().getLast20Bytes());
byte[] obtainer = convertToTronAddress(obtainerAddress.getLast20Bytes());
- long balance = getStorage().getBalance(owner);
+ long balance = getContractState().getBalance(owner);
if (logger.isInfoEnabled()) {
logger.info("Transfer to: [{}] heritage: [{}]",
@@ -392,21 +422,20 @@ public void suicide(DataWord obtainerAddress)
if (FastByteComparisons.compareTo(owner, 0, 20, obtainer, 0, 20) == 0) {
// if owner == obtainer just zeroing account according to Yellow Paper
- getStorage().addBalance(owner, -balance);
+ getContractState().addBalance(owner, -balance);
} else {
- transfer(getStorage(), owner, obtainer, balance);
+ transfer(getContractState(), owner, obtainer, balance);
}
-
getResult().addDeleteAccount(this.getOwnerAddress());
}
- public Deposit getStorage() {
- return this.storage;
+ public Deposit getContractState() {
+ return this.contractState;
}
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
public void createContract(DataWord value, DataWord memStart, DataWord memSize)
- throws ContractExeException {
+ throws ContractValidateException {
returnDataBuffer = null; // reset return buffer right before the call
if (getCallDeep() == MAX_DEPTH) {
@@ -415,9 +444,11 @@ public void createContract(DataWord value, DataWord memStart, DataWord memSize)
}
byte[] senderAddress = convertToTronAddress(this.getOwnerAddress().getLast20Bytes());
+ // todo: need check the value > 0?
long endowment = value.value().longValue();
- if (getStorage().getBalance(senderAddress) < endowment) {
+ if (getContractState().getBalance(senderAddress) < endowment) {
stackPushZero();
+ // todo: need inform to outside?
return;
}
@@ -429,19 +460,18 @@ public void createContract(DataWord value, DataWord memStart, DataWord memSize)
Hex.toHexString(senderAddress));
}
- //BlockchainConfig blockchainConfig = config.getBlockchainConfig().getConfigForBlock(getNumber().longValue());
- // actual gas subtract
- //DataWord gasLimit = blockchainConfig.getCreateGas(getGas());
- //spendGas(gasLimit.longValue(), "internal call");
- DataWord gasLimit = new DataWord(DropCost.getInstance().getCREATE());
-
// [2] CREATE THE CONTRACT ADDRESS
// byte[] newAddress = HashUtil.calcNewAddr(getOwnerAddress().getLast20Bytes() nonce);
- byte[] privKey = Sha256Hash.hash(getOwnerAddress().getData());
- ECKey ecKey = ECKey.fromPrivate(privKey);
- byte[] newAddress = ecKey.getAddress();
+ // todo: modify this contract generate way
+
+// byte[] privKey = Sha256Hash.hash(getOwnerAddress().getData());
+// ECKey ecKey = ECKey.fromPrivate(privKey);
+ this.increaseNonce();
+ //this.transactionHash = Sha256Hash.hash(transactionHash);
+ byte[] newAddress = Wallet
+ .generateContractAddress(rootTransactionId,nonce);
- AccountCapsule existingAddr = getStorage().getAccount(newAddress);
+ AccountCapsule existingAddr = getContractState().getAccount(newAddress);
//boolean contractAlreadyExists = existingAddr != null && existingAddr.isContractExist(blockchainConfig);
boolean contractAlreadyExists = existingAddr != null;
@@ -449,40 +479,50 @@ public void createContract(DataWord value, DataWord memStart, DataWord memSize)
if (byTestingSuite()) {
// This keeps track of the contracts created for a test
getResult().addCallCreate(programCode, EMPTY_BYTE_ARRAY,
- gasLimit.getNoLeadZeroesData(),
+ energyLimit.getNoLeadZeroesData(),
value.getNoLeadZeroesData());
}
*/
- Deposit deposit = getStorage();
+ Deposit deposit = getContractState();
//In case of hashing collisions, check for any balance before createAccount()
long oldBalance = deposit.getBalance(newAddress);
- deposit.createAccount(newAddress, Protocol.AccountType.Contract);
- deposit.addBalance(newAddress, oldBalance);
+ SmartContract newSmartContract = SmartContract.newBuilder()
+ .setContractAddress(ByteString.copyFrom(newAddress)).setConsumeUserResourcePercent(100)
+ .setOriginAddress(ByteString.copyFrom(senderAddress)).build();
+ deposit.createContract(newAddress, new ContractCapsule(newSmartContract));
+ deposit.createAccount(newAddress, "CreatedByContract",
+ Protocol.AccountType.Contract);
+ deposit.addBalance(newAddress, oldBalance);
// [4] TRANSFER THE BALANCE
long newBalance = 0L;
- if (!byTestingSuite()) {
+ if (!byTestingSuite() && endowment > 0) {
+ TransferActuator.validateForSmartContract(deposit, senderAddress, newAddress, endowment);
deposit.addBalance(senderAddress, -endowment);
newBalance = deposit.addBalance(newAddress, endowment);
}
- checkCPULimit("BEFORE CREATE");
+ // BlockchainConfig blockchainConfig = config.getBlockchainConfig().getConfigForBlock(getNumber().longValue());
+ // actual energy subtract
+ DataWord energyLimit = this.getCreateEnergy(getEnergyLimitLeft());
+ spendEnergy(energyLimit.longValue(), "internal call");
// [5] COOK THE INVOKE AND EXECUTE
- InternalTransaction internalTx = addInternalTx(getDroplimit(), senderAddress, null, endowment,
+ InternalTransaction internalTx = addInternalTx(null, senderAddress, null, endowment,
programCode, "create");
long vmStartInUs = System.nanoTime() / 1000;
ProgramInvoke programInvoke = programInvokeFactory.createProgramInvoke(
this, new DataWord(newAddress), getOwnerAddress(), value,
newBalance, null, deposit, false, byTestingSuite(), vmStartInUs,
- getVmShouldEndInUs());
+ getVmShouldEndInUs(), energyLimit.longValueSafe());
ProgramResult result = ProgramResult.createEmpty();
if (contractAlreadyExists) {
+ // todo: this exception must lead to rollback this function modification at least
result.setException(new BytecodeExecutionException(
"Trying to create a contract with existing contract address: 0x" + Hex
.toHexString(newAddress)));
@@ -492,23 +532,26 @@ this, new DataWord(newAddress), getOwnerAddress(), value,
vm.play(program);
result = program.getResult();
+ getTrace().merge(program.getTrace());
getResult().merge(result);
}
- checkCPULimit("AFTER CREATE");
// 4. CREATE THE CONTRACT OUT OF RETURN
byte[] code = result.getHReturn();
- //long storageCost = getLength(code) * getBlockchainConfig().getGasCost().getCREATE_DATA();
- long storageCost = getLength(code) * DropCost.getInstance().getCREATE_DATA();
- // todo storage cost?
- // long afterSpend = programInvoke.getDroplimit().longValue() - storageCost - result.getDropUsed();
- if (getLength(code) > DefaultConfig.getMaxCodeLength()) {
- result.setException(Exception
- .notEnoughSpendingGas("Contract size too large: " + getLength(result.getHReturn()),
- storageCost, this));
- } else if (!result.isRevert()) {
- result.spendDrop(storageCost);
+ //long storageCost = getLength(code) * getBlockchainConfig().getenergyCost().getCREATE_DATA();
+ // todo: delete this energy, because this is not relative to the cpu time, but need add to storage cost
+ // long storageCost = getLength(code) * EnergyCost.getInstance().getCREATE_DATA();
+ // // long afterSpend = programInvoke.getDroplimit().longValue() - storageCost - result.getDropUsed();
+ // if (getLength(code) > DefaultConfig.getMaxCodeLength()) {
+ // result.setException(Exception
+ // .notEnoughSpendingEnergy("Contract size too large: " + getLength(result.getHReturn()),
+ // storageCost, this));
+ // } else if (!result.isRevert()) {
+ // result.spendDrop(storageCost);
+ // deposit.saveCode(newAddress, code);
+ // }
+ if (!result.isRevert()) {
deposit.saveCode(newAddress, code);
}
@@ -524,6 +567,7 @@ this, new DataWord(newAddress), getOwnerAddress(), value,
stackPushZero();
if (result.getException() != null) {
+ refundEnergyAfterVM(energyLimit, result);
return;
} else {
returnDataBuffer = result.getHReturn();
@@ -537,14 +581,19 @@ this, new DataWord(newAddress), getOwnerAddress(), value,
stackPush(new DataWord(newAddress));
}
- // 5. REFUND THE REMAIN GAS
- long refundGas = gasLimit.longValue() - result.getDropUsed();
- if (refundGas > 0) {
- refundGas(refundGas, "remain gas from the internal call");
+ // 5. REFUND THE REMAIN Energy
+ refundEnergyAfterVM(energyLimit, result);
+ }
+
+ public void refundEnergyAfterVM(DataWord energyLimit, ProgramResult result) {
+
+ long refundEnergy = energyLimit.longValueSafe() - result.getEnergyUsed();
+ if (refundEnergy > 0) {
+ refundEnergy(refundEnergy, "remain energy from the internal call");
if (logger.isInfoEnabled()) {
- logger.info("The remaining gas is refunded, account: [{}], gas: [{}] ",
+ logger.info("The remaining energy is refunded, account: [{}], energy: [{}] ",
Hex.toHexString(convertToTronAddress(getOwnerAddress().getLast20Bytes())),
- refundGas);
+ refundEnergy);
}
}
}
@@ -558,12 +607,12 @@ this, new DataWord(newAddress), getOwnerAddress(), value,
* @param msg is the message call object
*/
public void callToAddress(MessageCall msg)
- throws ContractExeException, OutOfResourceException {
+ throws ContractValidateException {
returnDataBuffer = null; // reset return buffer right before the call
if (getCallDeep() == MAX_DEPTH) {
stackPushZero();
- refundGas(msg.getGas().longValue(), " call deep limit reach");
+ refundEnergy(msg.getEnergy().longValue(), " call deep limit reach");
return;
}
@@ -581,41 +630,42 @@ public void callToAddress(MessageCall msg)
msg.getOutDataSize().longValue());
}
- //Repository track = getStorage().startTracking();
- Deposit deposit = getStorage().newDepositChild();
+ //Repository track = getContractState().startTracking();
+ Deposit deposit = getContractState().newDepositChild();
// 2.1 PERFORM THE VALUE (endowment) PART
+ // todo: need to check value >= 0?
long endowment = msg.getEndowment().value().longValue();
long senderBalance = deposit.getBalance(senderAddress);
if (senderBalance < endowment) {
stackPushZero();
- refundGas(msg.getGas().longValue(), "refund gas from message call");
+ refundEnergy(msg.getEnergy().longValue(), "refund energy from message call");
return;
}
// FETCH THE CODE
- AccountCapsule accountCapsule = getStorage().getAccount(codeAddress);
+ AccountCapsule accountCapsule = getContractState().getAccount(codeAddress);
byte[] programCode =
- accountCapsule != null ? getStorage().getCode(codeAddress) : EMPTY_BYTE_ARRAY;
+ accountCapsule != null ? getContractState().getCode(codeAddress) : EMPTY_BYTE_ARRAY;
long contextBalance = 0L;
if (byTestingSuite()) {
// This keeps track of the calls created for a test
getResult().addCallCreate(data, contextAddress,
- msg.getGas().getNoLeadZeroesData(),
+ msg.getEnergy().getNoLeadZeroesData(),
msg.getEndowment().getNoLeadZeroesData());
- } else {
+ } else if (!ArrayUtils.isEmpty(senderAddress) && !ArrayUtils.isEmpty(contextAddress)
+ && senderAddress != contextAddress && endowment > 0) {
+ TransferActuator.validateForSmartContract(deposit, senderAddress, contextAddress, endowment);
deposit.addBalance(senderAddress, -endowment);
contextBalance = deposit.addBalance(contextAddress, endowment);
}
// CREATE CALL INTERNAL TRANSACTION
- InternalTransaction internalTx = addInternalTx(getDroplimit(), senderAddress, contextAddress,
+ InternalTransaction internalTx = addInternalTx(null, senderAddress, contextAddress,
endowment, data, "call");
- checkCPULimit("BEFORE CALL");
-
ProgramResult result = null;
if (isNotEmpty(programCode)) {
long vmStartInUs = System.nanoTime() / 1000;
@@ -624,7 +674,7 @@ this, new DataWord(contextAddress),
msg.getType().callIsDelegate() ? getCallerAddress() : getOwnerAddress(),
msg.getType().callIsDelegate() ? getCallValue() : msg.getEndowment(),
contextBalance, data, deposit, msg.getType().callIsStatic() || isStaticCall(),
- byTestingSuite(), vmStartInUs, getVmShouldEndInUs());
+ byTestingSuite(), vmStartInUs, getVmShouldEndInUs(), msg.getEnergy().longValueSafe());
VM vm = new VM(config);
Program program = new Program(null, programCode, programInvoke, internalTx, config);
@@ -646,6 +696,7 @@ this, new DataWord(contextAddress),
stackPushZero();
if (result.getException() != null) {
+ refundEnergyAfterVM(msg.getEnergy(), result);
return;
}
} else {
@@ -656,15 +707,15 @@ this, new DataWord(contextAddress),
if (byTestingSuite()) {
logger.info("Testing run, skipping storage diff listener");
- } else if (Arrays.equals(transaction.getReceiveAddress(), internalTx.getReceiveAddress())) {
- storageDiffListener.merge(program.getStorageDiff());
}
+// else if (Arrays.equals(transaction.getReceiveAddress(), internalTx.getReceiveAddress())) {
+// storageDiffListener.merge(program.getStorageDiff());
+// }
} else {
// 4. THE FLAG OF SUCCESS IS ONE PUSHED INTO THE STACK
deposit.commit();
stackPushOne();
}
- checkCPULimit("AFTER CALL");
// 3. APPLY RESULTS: result.getHReturn() into out_memory allocated
if (result != null) {
@@ -677,50 +728,60 @@ this, new DataWord(contextAddress),
returnDataBuffer = buffer;
}
- // 5. REFUND THE REMAIN GAS
+ // 5. REFUND THE REMAIN ENERGY
if (result != null) {
- BigInteger refundGas = msg.getGas().value().subtract(toBI(result.getDropUsed()));
- if (isPositive(refundGas)) {
- refundGas(refundGas.longValue(), "remaining gas from the internal call");
+ BigInteger refundEnergy = msg.getEnergy().value().subtract(toBI(result.getEnergyUsed()));
+ if (isPositive(refundEnergy)) {
+ refundEnergy(refundEnergy.longValue(), "remaining energy from the internal call");
if (logger.isInfoEnabled()) {
- logger.info("The remaining gas refunded, account: [{}], gas: [{}] ",
+ logger.info("The remaining energy refunded, account: [{}], energy: [{}] ",
Hex.toHexString(senderAddress),
- refundGas.toString());
+ refundEnergy.toString());
}
}
} else {
- refundGas(msg.getGas().longValue(), "remaining gas from the internal call");
+ refundEnergy(msg.getEnergy().longValue(), "remaining esnergy from the internal call");
}
+ }
+ public static void increaseNonce(){
+ nonce++;
}
- public void spendDrop(long dropValue, String cause) {
-// if (getDroplimitLong() < dropValue) {
-// throw Exception.notEnoughSpendingGas(cause, dropValue, this);
-// }
- getResult().spendDrop(dropValue);
+ public static void resetNonce(){
+ nonce=0;
}
- public void checkCPULimit(String opName) throws OutOfResourceException {
+ public void spendEnergy(long energyValue, String opName) {
+ if (getEnergylimitLeftLong() < energyValue) {
+ throw new OutOfEnergyException(
+ "Not enough energy for '%s' operation executing: curInvokeEnergyLimit[%d], curOpEnergy[%d], usedEnergy[%d]",
+ opName, invoke.getEnergyLimit(), energyValue, getResult().getEnergyUsed());
+ }
+ getResult().spendEnergy(energyValue);
+ }
- long vmNowInUs = System.nanoTime() / 1000;
- if (vmNowInUs > getVmShouldEndInUs()) {
- throw Exception.notEnoughCPU(opName);
+ public void checkCPUTimeLimit(String opName) {
+ if (!Args.getInstance().isDebug()) {
+ long vmNowInUs = System.nanoTime() / 1000;
+ if (vmNowInUs > getVmShouldEndInUs()) {
+ throw Exception.notEnoughTime(opName);
+ }
}
}
- public void spendAllGas() {
- spendDrop(getDroplimit().longValue(), "Spending all remaining");
+ public void spendAllEnergy() {
+ spendEnergy(getEnergyLimitLeft().longValue(), "Spending all remaining");
}
- public void refundGas(long gasValue, String cause) {
- logger.info("[{}] Refund for cause: [{}], gas: [{}]", invoke.hashCode(), cause, gasValue);
- getResult().refundGas(gasValue);
+ public void refundEnergy(long energyValue, String cause) {
+ logger.info("[{}] Refund for cause: [{}], energy: [{}]", invoke.hashCode(), cause, energyValue);
+ getResult().refundEnergy(energyValue);
}
- public void futureRefundGas(long gasValue) {
- logger.info("Future refund added: [{}]", gasValue);
- getResult().addFutureRefund(gasValue);
+ public void futureRefundEnergy(long energyValue) {
+ logger.info("Future refund added: [{}]", energyValue);
+ getResult().addFutureRefund(energyValue);
}
public void resetFutureRefund() {
@@ -728,21 +789,13 @@ public void resetFutureRefund() {
}
public void storageSave(DataWord word1, DataWord word2) {
- //storageSave(word1.getData(), word2.getData());
DataWord keyWord = word1.clone();
DataWord valWord = word2.clone();
- getStorage().addStorageValue(convertToTronAddress(getOwnerAddress().getLast20Bytes()), keyWord,
- valWord);
+ getContractState()
+ .putStorageValue(convertToTronAddress(getOwnerAddress().getLast20Bytes()), keyWord,
+ valWord);
}
- /*
- public void storageSave(byte[] key, byte[] val) {
- DataWord keyWord = new DataWord(key);
- DataWord valWord = new DataWord(val);
- getStorage().addStorageRow(getOwnerAddress().getLast20Bytes(), keyWord, valWord);
- }
- */
-
public byte[] getCode() {
return ops;
}
@@ -779,7 +832,7 @@ public DataWord getBlockHash(int index) {
}
public DataWord getBalance(DataWord address) {
- long balance = getStorage().getBalance(convertToTronAddress(address.getLast20Bytes()));
+ long balance = getContractState().getBalance(convertToTronAddress(address.getLast20Bytes()));
return new DataWord(balance);
}
@@ -795,12 +848,12 @@ public DataWord getDropPrice() {
return new DataWord(1);
}
- public long getDroplimitLong() {
- return invoke.getDroplimitLong() - getResult().getDropUsed();
+ public long getEnergylimitLeftLong() {
+ return invoke.getEnergyLimit() - getResult().getEnergyUsed();
}
- public DataWord getDroplimit() {
- return new DataWord(invoke.getDroplimitLong() - getResult().getDropUsed());
+ public DataWord getEnergyLimitLeft() {
+ return new DataWord(invoke.getEnergyLimit() - getResult().getEnergyUsed());
}
public long getVmShouldEndInUs() {
@@ -841,7 +894,7 @@ public byte[] getReturnDataBufferData(DataWord off, DataWord size) {
}
public DataWord storageLoad(DataWord key) {
- DataWord ret = getStorage()
+ DataWord ret = getContractState()
.getStorageValue(convertToTronAddress(getOwnerAddress().getLast20Bytes()), key.clone());
return ret == null ? null : ret.clone();
}
@@ -863,7 +916,7 @@ public DataWord getNumber() {
}
public DataWord getDifficulty() {
- return null; //invoke.getDifficulty().clone();
+ return new DataWord(0); //invoke.getDifficulty().clone();
}
public boolean isStaticCall() {
@@ -950,10 +1003,10 @@ public void fullTrace() {
logger.trace(" -- OPS -- {}", opsString);
logger.trace(" -- STACK -- {}", stackData);
logger.trace(" -- MEMORY -- {}", memoryData);
- logger.trace("\n Spent Drop: [{}]/[{}]\n Left Gas: [{}]\n",
- getResult().getDropUsed(),
- invoke.getDroplimit().longValue(),
- getDroplimit().longValue());
+ logger.trace("\n Spent Drop: [{}]/[{}]\n Left Energy: [{}]\n",
+ getResult().getEnergyUsed(),
+ invoke.getEnergyLimit(),
+ getEnergyLimitLeft().longValue());
StringBuilder globalOutput = new StringBuilder("\n");
if (stackData.length() > 0) {
@@ -979,7 +1032,7 @@ public void fullTrace() {
if (!Arrays.equals(txData, ops)) {
globalOutput.append("\n msg.data: ").append(Hex.toHexString(txData));
}
- globalOutput.append("\n\n Spent Gas: ").append(getResult().getDropUsed());
+ globalOutput.append("\n\n Spent Energy: ").append(getResult().getEnergyUsed());
if (listener != null) {
listener.output(globalOutput.toString());
@@ -989,7 +1042,7 @@ public void fullTrace() {
public void saveOpTrace() {
if (this.pc < ops.length) {
- trace.addOp(ops[pc], pc, getCallDeep(), getDroplimit(), traceListener.resetActions());
+ trace.addOp(ops[pc], pc, getCallDeep(), getEnergyLimitLeft(), traceListener.resetActions());
}
}
@@ -1195,27 +1248,28 @@ public int verifyJumpDest(DataWord nextPC) {
public void callToPrecompiledAddress(MessageCall msg,
PrecompiledContracts.PrecompiledContract contract)
- throws ContractExeException {
+ throws ContractValidateException {
returnDataBuffer = null; // reset return buffer right before the call
if (getCallDeep() == MAX_DEPTH) {
stackPushZero();
- this.refundGas(msg.getGas().longValue(), " call deep limit reach");
+ this.refundEnergy(msg.getEnergy().longValue(), " call deep limit reach");
return;
}
- // Repository track = getStorage().startTracking();
- Deposit deposit = getStorage();
+ // Repository track = getContractState().startTracking();
+ Deposit deposit = getContractState();
byte[] senderAddress = convertToTronAddress(this.getOwnerAddress().getLast20Bytes());
byte[] codeAddress = convertToTronAddress(msg.getCodeAddress().getLast20Bytes());
byte[] contextAddress = msg.getType().callIsStateless() ? senderAddress : codeAddress;
+ // todo: need check endowment > 0 and not exceed?? because of "senderBalance < endowment"
long endowment = msg.getEndowment().value().longValue();
long senderBalance = deposit.getBalance(senderAddress);
if (senderBalance < endowment) {
stackPushZero();
- this.refundGas(msg.getGas().longValue(), "refund gas from message call");
+ this.refundEnergy(msg.getEnergy().longValue(), "refund energy from message call");
return;
}
@@ -1223,31 +1277,35 @@ public void callToPrecompiledAddress(MessageCall msg,
msg.getInDataSize().intValue());
// Charge for endowment - is not reversible by rollback
- transfer(deposit, senderAddress, contextAddress, msg.getEndowment().value().longValue());
-
- long requiredGas = contract.getGasForData(data);
- if (requiredGas > msg.getGas().longValue()) {
+ if (!ArrayUtils.isEmpty(senderAddress) && !ArrayUtils.isEmpty(contextAddress)
+ && senderAddress != contextAddress && msg.getEndowment().value().longValue() > 0) {
+ transfer(deposit, senderAddress, contextAddress, msg.getEndowment().value().longValue());
+ }
- this.refundGas(0, "call pre-compiled"); //matches cpp logic
+ long requiredEnergy = contract.getEnergyForData(data);
+ if (requiredEnergy > msg.getEnergy().longValue()) {
+ // todo: new throw?? because it has done nothing, but outside don't know this
+ // regard as consumed the energy
+ this.refundEnergy(0, "call pre-compiled"); //matches cpp logic
this.stackPushZero();
// deposit.rollback();
} else {
// Delegate or not. if is delegated, we will use msg sender, otherwise use contract address
contract.setCallerAddress(convertToTronAddress(msg.getType().callIsDelegate() ?
getCallerAddress().getLast20Bytes() : getOwnerAddress().getLast20Bytes()));
- // this is the depositImpl, not storage as above
+ // this is the depositImpl, not contractState as above
contract.setDeposit(this.invoke.getDeposit());
contract.setResult(this.result);
Pair out = contract.execute(data);
if (out.getLeft()) { // success
- this.refundGas(msg.getGas().longValue() - requiredGas, "call pre-compiled");
+ this.refundEnergy(msg.getEnergy().longValue() - requiredEnergy, "call pre-compiled");
this.stackPushOne();
returnDataBuffer = out.getRight();
deposit.commit();
} else {
- // spend all gas on failure, push zero and revert state changes
- this.refundGas(0, "call pre-compiled");
+ // spend all energy on failure, push zero and revert state changes
+ this.refundEnergy(0, "call pre-compiled");
this.stackPushZero();
// deposit.rollback();
}
@@ -1279,9 +1337,9 @@ public BytecodeExecutionException(String message) {
}
@SuppressWarnings("serial")
- public static class OutOfGasException extends BytecodeExecutionException {
+ public static class OutOfEnergyException extends BytecodeExecutionException {
- public OutOfGasException(String message, Object... args) {
+ public OutOfEnergyException(String message, Object... args) {
super(format(message, args));
}
}
@@ -1356,48 +1414,38 @@ public StaticCallModificationException() {
public static class Exception {
- public static OutOfGasException notEnoughOpGas(OpCode op, long opGas, long programGas) {
- return new OutOfGasException(
- "Not enough gas for '%s' operation executing: opGas[%d], programGas[%d];", op, opGas,
- programGas);
+ public static OutOfEnergyException notEnoughOpEnergy(OpCode op, long opEnergy,
+ long programEnergy) {
+ return new OutOfEnergyException(
+ "Not enough energy for '%s' operation executing: opEnergy[%d], programEnergy[%d];", op,
+ opEnergy,
+ programEnergy);
}
- public static OutOfGasException notEnoughOpGas(OpCode op, DataWord opGas,
- DataWord programGas) {
- return notEnoughOpGas(op, opGas.longValue(), programGas.longValue());
+ public static OutOfEnergyException notEnoughOpEnergy(OpCode op, DataWord opEnergy,
+ DataWord programEnergy) {
+ return notEnoughOpEnergy(op, opEnergy.longValue(), programEnergy.longValue());
}
- public static OutOfResourceException notEnoughCPU(String op) {
+ public static OutOfResourceException notEnoughTime(String op) {
return new OutOfResourceException(
- "Not enough CPU resource when '%s' operation executing", op);
+ "CPU timeout for '%s' operation executing", op);
}
+
public static OutOfMemoryException memoryOverflow(OpCode op) {
return new OutOfMemoryException("Out of Memory when '%s' operation executing", op);
}
public static OutOfStorageException notEnoughStorage() {
- return new OutOfStorageException("Not enough Storage resource");
+ return new OutOfStorageException("Not enough ContractState resource");
}
-
- public static OutOfGasException notEnoughOpGas(OpCode op, BigInteger opGas,
- BigInteger programGas) {
- return notEnoughOpGas(op, opGas.longValue(), programGas.longValue());
- }
-
- public static OutOfGasException notEnoughSpendingGas(String cause, long gasValue,
- Program program) {
- return new OutOfGasException(
- "Not enough gas for '%s' cause spending: invokeGas[%d], gas[%d], usedGas[%d];",
- cause, program.invoke.getDroplimit().longValue(), gasValue,
- program.getResult().getDropUsed());
- }
-
- public static OutOfGasException gasOverflow(BigInteger actualGas, BigInteger gasLimit) {
- return new OutOfGasException("Gas value overflow: actualGas[%d], gasLimit[%d];",
- actualGas.longValue(), gasLimit.longValue());
+ public static OutOfEnergyException energyOverflow(BigInteger actualEnergy,
+ BigInteger energyLimit) {
+ return new OutOfEnergyException("Energy value overflow: actualEnergy[%d], energyLimit[%d];",
+ actualEnergy.longValue(), energyLimit.longValue());
}
public static IllegalOperationException invalidOpCode(byte... opCode) {
@@ -1423,6 +1471,22 @@ public StackTooLargeException(String message) {
}
}
+ public DataWord getCallEnergy(OpCode op, DataWord requestedEnergy, DataWord availableEnergy) {
+
+ // if (requestedEnergy.compareTo(availableEnergy) > 0) {
+ // throw new Program.OutOfEnergyException(
+ // "Not enough energy for '%s' operation executing: opEnergy[%d], programEnergy[%d]", op.name(),
+ // requestedEnergy, availableEnergy);
+ // }
+ //
+ // return requestedEnergy.clone();
+ return requestedEnergy.compareTo(availableEnergy) > 0 ? availableEnergy : requestedEnergy;
+ }
+
+ public DataWord getCreateEnergy(DataWord availableEnergy) {
+ return availableEnergy;
+ }
+
/**
* used mostly for testing reasons
*/
diff --git a/src/main/java/org/tron/common/runtime/vm/program/ProgramPrecompile.java b/src/main/java/org/tron/common/runtime/vm/program/ProgramPrecompile.java
index 8b73b0762e8..76f729ec4e8 100644
--- a/src/main/java/org/tron/common/runtime/vm/program/ProgramPrecompile.java
+++ b/src/main/java/org/tron/common/runtime/vm/program/ProgramPrecompile.java
@@ -19,16 +19,17 @@
import java.util.HashSet;
import java.util.Set;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import lombok.extern.slf4j.Slf4j;
import org.tron.common.runtime.vm.OpCode;
+
+@Slf4j(topic = "ProgramPrecompile")
/**
* Created by Anton Nashatyrev on 06.02.2017.
*/
public class ProgramPrecompile {
- private static final Logger logger = LoggerFactory.getLogger("PP");
+ // private static final Logger logger = LoggerFactory.getLogger("PP");
private static final int version = 1;
private Set jumpdest = new HashSet<>();
diff --git a/src/main/java/org/tron/common/runtime/vm/program/ProgramResult.java b/src/main/java/org/tron/common/runtime/vm/program/ProgramResult.java
index 0da96338fa6..09410c92e73 100644
--- a/src/main/java/org/tron/common/runtime/vm/program/ProgramResult.java
+++ b/src/main/java/org/tron/common/runtime/vm/program/ProgramResult.java
@@ -17,12 +17,8 @@
public class ProgramResult {
- private long ownerCpuUsed;
- private long senderCpuUsed;
- private long ownerStorageUsed;
- private long senderStorageUsed;
-
- private long dropUsed;
+ private long energyUsed = 0;
+ private long futureRefund = 0;
private byte[] hReturn = EMPTY_BYTE_ARRAY;
private byte[] contractAddress = EMPTY_BYTE_ARRAY;
@@ -33,7 +29,6 @@ public class ProgramResult {
private ByteArraySet touchedAccounts = new ByteArraySet();
private List internalTransactions;
private List logInfoList;
- private long futureRefund = 0;
private TransactionResultCapsule ret = new TransactionResultCapsule();
@@ -45,8 +40,8 @@ public class ProgramResult {
*/
private List callCreateList;
- public void spendDrop(long drops) {
- dropUsed += drops;
+ public void spendEnergy(long energy) {
+ energyUsed += energy;
}
public void setRevert() {
@@ -57,8 +52,8 @@ public boolean isRevert() {
return revert;
}
- public void refundGas(long drops) {
- dropUsed -= drops;
+ public void refundEnergy(long energy) {
+ energyUsed -= energy;
}
public void setContractAddress(byte[] contractAddress) {
@@ -82,12 +77,16 @@ public TransactionResultCapsule getRet() {
return ret;
}
+ public void setRet(TransactionResultCapsule ret) {
+ this.ret = ret;
+ }
+
public RuntimeException getException() {
return exception;
}
- public long getDropUsed() {
- return dropUsed;
+ public long getEnergyUsed() {
+ return energyUsed;
}
public void setException(RuntimeException exception) {
@@ -149,8 +148,8 @@ public List getCallCreateList() {
return callCreateList;
}
- public void addCallCreate(byte[] data, byte[] destination, byte[] gasLimit, byte[] value) {
- getCallCreateList().add(new CallCreate(data, destination, gasLimit, value));
+ public void addCallCreate(byte[] data, byte[] destination, byte[] energyLimit, byte[] value) {
+ getCallCreateList().add(new CallCreate(data, destination, energyLimit, value));
}
public List getInternalTransactions() {
@@ -178,8 +177,8 @@ public void rejectInternalTransactions() {
}
}
- public void addFutureRefund(long gasValue) {
- futureRefund += gasValue;
+ public void addFutureRefund(long energyValue) {
+ futureRefund += energyValue;
}
public long getFutureRefund() {
diff --git a/src/main/java/org/tron/common/runtime/vm/program/Storage.java b/src/main/java/org/tron/common/runtime/vm/program/Storage.java
index 043d47a5e9f..32664ce5b22 100644
--- a/src/main/java/org/tron/common/runtime/vm/program/Storage.java
+++ b/src/main/java/org/tron/common/runtime/vm/program/Storage.java
@@ -1,256 +1,96 @@
-/*
- * Copyright (c) [2016] [ ]
- * This file is part of the ethereumJ library.
- *
- * The ethereumJ library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * The ethereumJ library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the ethereumJ library. If not, see .
- */
package org.tron.common.runtime.vm.program;
-import com.google.protobuf.ByteString;
+import static java.lang.System.arraycopy;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
+import org.tron.common.crypto.Hash;
import org.tron.common.runtime.vm.DataWord;
-import org.tron.common.runtime.vm.program.invoke.ProgramInvoke;
-import org.tron.common.runtime.vm.program.listener.ProgramListener;
-import org.tron.common.runtime.vm.program.listener.ProgramListenerAware;
-import org.tron.common.storage.Deposit;
-import org.tron.common.storage.Key;
-import org.tron.common.storage.Value;
-import org.tron.core.capsule.AccountCapsule;
-import org.tron.core.capsule.BlockCapsule;
-import org.tron.core.capsule.BytesCapsule;
-import org.tron.core.capsule.ContractCapsule;
-import org.tron.core.capsule.StorageCapsule;
-import org.tron.core.capsule.TransactionCapsule;
+import org.tron.core.capsule.StorageRowCapsule;
import org.tron.core.db.Manager;
-import org.tron.core.exception.ContractExeException;
-import org.tron.protos.Protocol;
-
-public class Storage implements Deposit, ProgramListenerAware {
-
- private Deposit deposit;
- private final DataWord address; // contract address
- private ProgramListener programListener;
-
- public Storage(ProgramInvoke programInvoke) {
- this.address = programInvoke.getOwnerAddress(); // contract address
- this.deposit = programInvoke.getDeposit();
- }
-
- @Override
- public Manager getDbManager() {
- return deposit.getDbManager();
- }
-
- @Override
- public void setProgramListener(ProgramListener listener) {
- this.programListener = listener;
- }
-
- @Override
- public AccountCapsule createAccount(byte[] addr, Protocol.AccountType type) {
- return deposit.createAccount(addr, type);
- }
-
- @Override
- public AccountCapsule createAccount(byte[] address, ByteString accountName,
- Protocol.AccountType type) {
- return deposit.createAccount(address, accountName, type);
- }
-
-
- @Override
- public AccountCapsule getAccount(byte[] addr) {
- return deposit.getAccount(addr);
- }
-
- @Override
- public BytesCapsule getContractByNormalAccount(byte[] address) {
- return deposit.getContractByNormalAccount(address);
- }
-
- @Override
- public void createContractByNormalAccountIndex(byte[] address,
- BytesCapsule contractAddress) {
- deposit.createContractByNormalAccountIndex(address, contractAddress);
- }
-
- @Override
- public void createContract(byte[] codeHash, ContractCapsule contractCapsule) {
- deposit.createContract(codeHash, contractCapsule);
- }
-
- @Override
- public ContractCapsule getContract(byte[] codeHash) {
- return deposit.getContract(codeHash);
- }
-
- @Override
- public void saveCode(byte[] addr, byte[] code) {
- deposit.saveCode(addr, code);
- }
-
- @Override
- public byte[] getCode(byte[] addr) {
- return deposit.getCode(addr);
- }
-
- /*
- @Override
- public byte[] getCodeHash(byte[] addr) {
- return deposit.getCodeHash(addr);
+import org.tron.core.db.StorageRowStore;
+
+public class Storage {
+
+ private byte[] addrHash; // contract address
+ private Manager manager;
+ private final Map rowCache = new HashMap<>();
+ private long beforeUseSize = 0;
+
+ private static final int PREFIX_BYTES = 16;
+
+ public Storage(byte[] address, Manager manager) {
+ addrHash = addrHash(address);
+ this.manager = manager;
+ }
+
+ public DataWord getValue(DataWord key) {
+ if (rowCache.containsKey(key)) {
+ return rowCache.get(key).getValue();
+ } else {
+ StorageRowStore store = manager.getStorageRowStore();
+ StorageRowCapsule row = store.get(compose(key.getData(), addrHash));
+ if (row == null || row.getInstance() == null) {
+ return null;
+ } else {
+ beforeUseSize += row.getInstance().length;
+ }
+ rowCache.put(key, row);
+ return row.getValue();
}
- */
-
- @Override
- public void addStorageValue(byte[] addr, DataWord key, DataWord value) {
- if (canListenTrace(addr)) {
- programListener.onStoragePut(key, value);
- }
- deposit.addStorageValue(addr, key, value);
}
- private boolean canListenTrace(byte[] address) {
- return (programListener != null) && this.address.equals(new DataWord(address));
- }
-
- @Override
- public DataWord getStorageValue(byte[] addr, DataWord key) {
- return deposit.getStorageValue(addr, key);
- }
-
- @Override
- public long getBalance(byte[] addr) {
- return deposit.getBalance(addr);
+ public void put(DataWord key, DataWord value) {
+ if (rowCache.containsKey(key)) {
+ rowCache.get(key).setValue(value);
+ } else {
+ StorageRowStore store = manager.getStorageRowStore();
+ byte[] rowKey = compose(key.getData(), addrHash);
+ StorageRowCapsule row = store.get(rowKey);
+ if (row == null || row.getInstance() == null) {
+ row = new StorageRowCapsule(rowKey, value.getData());
+ } else {
+ beforeUseSize += row.getInstance().length;
+ }
+ rowCache.put(key, row);
+ }
}
- @Override
- public long addBalance(byte[] addr, long value)
- throws ContractExeException {
- return deposit.addBalance(addr, value);
+ private static byte[] compose(byte[] key, byte[] addrHash) {
+ byte[] result = new byte[key.length];
+ arraycopy(addrHash, 0, result, 0, PREFIX_BYTES);
+ arraycopy(key, PREFIX_BYTES, result, PREFIX_BYTES, PREFIX_BYTES);
+ return result;
}
- @Override
- public Deposit newDepositChild() {
- return deposit.newDepositChild();
+ // 32 bytes
+ private static byte[] addrHash(byte[] address) {
+ return Hash.sha3(address);
}
- @Override
- public Deposit newDepositNext() {
- return deposit.newDepositNext();
+ public long computeSize() {
+ AtomicLong size = new AtomicLong();
+ rowCache.forEach((key, value) -> {
+ if (!value.getValue().isZero()) {
+ size.getAndAdd(value.getInstance().length);
+ }
+ });
+ return size.get();
}
- @Override
- public void flush() {
- deposit.flush();
+ public long getBeforeUseSize() {
+ return this.beforeUseSize;
}
- @Override
public void commit() {
- deposit.commit();
- }
-
- @Override
- public StorageCapsule getStorage(byte[] address) {
- return deposit.getStorage(address);
- }
-
- @Override
- public void putAccount(Key key, Value value) {
- deposit.putAccount(key, value);
- }
-
- @Override
- public void putTransaction(Key key, Value value) {
- deposit.putTransaction(key, value);
- }
-
- @Override
- public void putBlock(Key key, Value value) {
- deposit.putBlock(key, value);
- }
-
- @Override
- public void putWitness(Key key, Value value) {
- deposit.putWitness(key, value);
- }
-
- @Override
- public void putCode(Key key, Value value) {
- deposit.putCode(key, value);
- }
-
- @Override
- public void putContract(Key key, Value value) {
- deposit.putContract(key, value);
- }
-
- @Override
- public void putContractByNormalAccountIndex(Key key, Value value) {
- deposit.putContractByNormalAccountIndex(key, value);
- }
-
- @Override
- public void putStorage(Key key, Value value) {
- deposit.putStorage(key, value);
- }
-
- @Override
- public void putVotes(Key key, Value value) {
- deposit.putVotes(key, value);
- }
-
- @Override
- public void setParent(Deposit deposit) {
- this.deposit.setParent(deposit);
- }
-
- @Override
- public void setPrevDeposit(Deposit deposit) {
- this.deposit.setPrevDeposit(deposit);
- }
-
- @Override
- public void setNextDeposit(Deposit deposit) {
- this.deposit.setNextDeposit(deposit);
- }
-
- @Override
- public TransactionCapsule getTransaction(byte[] trxHash) {
- return this.deposit.getTransaction(trxHash);
- }
-
- @Override
- // Do nothing
- public void syncCacheFromAccountStore(byte[] address) {
- }
-
- @Override
- // Do nothing
- public void syncCacheFromVotesStore(byte[] address) {
- }
-
- @Override
- public BlockCapsule getBlock(byte[] blockHash) {
- return this.deposit.getBlock(blockHash);
- }
-
- @Override
- public long computeAfterRunStorageSize() {
- return this.deposit.computeAfterRunStorageSize();
- }
-
- @Override
- public long getBeforeRunStorageSize() {
- return this.deposit.getBeforeRunStorageSize();
+ rowCache.forEach((key, value) -> {
+ if (value.isDirty()) {
+ if (value.getValue().isZero()) {
+ manager.getStorageRowStore().delete(value.getRowKey());
+ } else {
+ manager.getStorageRowStore().put(value.getRowKey(), value);
+ }
+ }
+ });
}
}
diff --git a/src/main/java/org/tron/common/runtime/vm/program/VMTransaction.java b/src/main/java/org/tron/common/runtime/vm/program/VMTransaction.java
deleted file mode 100644
index 7ebf4e6f7bc..00000000000
--- a/src/main/java/org/tron/common/runtime/vm/program/VMTransaction.java
+++ /dev/null
@@ -1,546 +0,0 @@
-/*
- * Copyright (c) [2016] [ ]
- * This file is part of the ethereumJ library.
- *
- * The ethereumJ library is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * The ethereumJ library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with the ethereumJ library. If not, see .
- */
-package org.tron.common.runtime.vm.program;
-
-import static org.apache.commons.lang3.ArrayUtils.isEmpty;
-
-import com.google.common.primitives.Longs;
-import java.math.BigInteger;
-import java.security.SignatureException;
-import java.util.Arrays;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.spongycastle.util.BigIntegers;
-import org.spongycastle.util.encoders.Hex;
-import org.tron.common.crypto.ECKey;
-import org.tron.common.crypto.ECKey.ECDSASignature;
-import org.tron.common.crypto.ECKey.MissingPrivateKeyException;
-import org.tron.common.crypto.Hash;
-import org.tron.common.runtime.vm.DataWord;
-import org.tron.common.utils.ByteUtil;
-import org.tron.common.utils.Sha256Hash;
-import org.tron.core.capsule.TransactionCapsule;
-import org.tron.protos.Protocol;
-
-public class VMTransaction {
-
- private static final Logger logger = LoggerFactory.getLogger("VMTransaction");
- private static final BigInteger DEFAULT_GAS_PRICE = new BigInteger("10000000000000");
- private static final BigInteger DEFAULT_BALANCE_GAS = new BigInteger("21000");
-
- public static final int HASH_LENGTH = 32;
- public static final int ADDRESS_LENGTH = 20;
-
- /* SHA3 hash of the RLP encoded transaction */
- private byte[] hash;
-
- /* the amount of ether to transfer (calculated as wei) */
- private long value;
-
- /* the address of the destination account
- * In creation transaction the receive address is - 0 */
- private byte[] receiveAddress;
-
- /* An unlimited size byte array specifying
- * input [data] of the message call or
- * Initialization code for a new contract */
- private byte[] data;
-
- /**
- * Since EIP-155, we could encode chainId in V
- */
- private static final int CHAIN_ID_INC = 35;
- private static final int LOWER_REAL_V = 27;
- private Integer chainId = null;
-
- /* the elliptic curve signature
- * (including public key recovery bits) */
- private ECDSASignature signature;
-
- protected byte[] sendAddress;
-
- /* Tx in encoded form */
- protected byte[] protoEncoded;
- private byte[] protoRaw;
- /* Indicates if this transaction has been parsed
- * from the RLP-encoded data */
- protected boolean parsed = false;
-
- /////////////////////////////
- Protocol.Transaction trx;
-
- public VMTransaction(byte[] rawData) {
- this.protoEncoded = rawData;
- parsed = false;
- }
-
- public VMTransaction(Protocol.Transaction tx) {
- this.trx = tx;
- TransactionCapsule trxCap = new TransactionCapsule(tx);
- this.protoEncoded = trxCap.getData();
- parsed = false;
- }
-
-
- public VMTransaction(byte[] receiveAddress, long value, byte[] data,
- Integer chainId) {
- this.receiveAddress = receiveAddress;
- if (value == 0L) {
- this.value = 0L;
- } else {
- this.value = value;
- }
- this.data = data;
- this.chainId = chainId;
-
- if (receiveAddress == null) {
- this.receiveAddress = ByteUtil.EMPTY_BYTE_ARRAY;
- }
-
- parsed = true;
- }
-
- public VMTransaction(byte[] receiveAddress, long value, byte[] data) {
- this(receiveAddress, value, data, null);
- }
-
- public VMTransaction(byte[] receiveAddress, long value, byte[] data,
- byte[] r, byte[] s, byte v, Integer chainId) {
- this(receiveAddress, value, data, chainId);
- this.signature = ECDSASignature.fromComponents(r, s, v);
- }
-
- public VMTransaction(byte[] receiveAddress, long value, byte[] data,
- byte[] r, byte[] s, byte v) {
- this(receiveAddress, value, data, r, s, v, null);
- }
-
-
- private Integer extractChainIdFromV(BigInteger bv) {
- if (bv.bitLength() > 31) {
- return Integer.MAX_VALUE; // chainId is limited to 31 bits, longer are not valid for now
- }
- long v = bv.longValue();
- if (v == LOWER_REAL_V || v == (LOWER_REAL_V + 1)) {
- return null;
- }
- return (int) ((v - CHAIN_ID_INC) / 2);
- }
-
- private byte getRealV(BigInteger bv) {
- if (bv.bitLength() > 31) {
- return 0; // chainId is limited to 31 bits, longer are not valid for now
- }
- long v = bv.longValue();
- if (v == LOWER_REAL_V || v == (LOWER_REAL_V + 1)) {
- return (byte) v;
- }
- byte realV = LOWER_REAL_V;
- int inc = 0;
- if ((int) v % 2 == 0) {
- inc = 1;
- }
- return (byte) (realV + inc);
- }
-
- public long transactionCost(Protocol.Block block) {
-
- protoParse();
-
- //return config.getConfigForBlock(block.getNumber()).
- // getTransactionCost(this);
- return 0;
- }
-
- public synchronized void verify() {
- protoParse();
- validate();
- }
-
- public synchronized void protoParse() {
- if (parsed) {
- return;
- }
- try {
- //RLPList decodedTxList = RLP.decode2(rlpEncoded);
- //RLPList transaction = (RLPList) decodedTxList.get(0);
-
- // Basic verification
- /*if (transaction.size() > 9 ) throw new RuntimeException("Too many RLP elements");
- for (RLPElement rlpElement : transaction) {
- if (!(rlpElement instanceof RLPItem))
- throw new RuntimeException("Transaction RLP elements shouldn't be lists");
- }
-
- this.gasPrice = transaction.get(1).getRLPData();
- this.gasLimit = transaction.get(2).getRLPData();
- this.receiveAddress = transaction.get(3).getRLPData();
- this.value = transaction.get(4).getRLPData();
- this.data = transaction.get(5).getRLPData();
- // only parse signature in case tx is signed
- if (transaction.get(6).getRLPData() != null) {
- byte[] vData = transaction.get(6).getRLPData();
- BigInteger v = ByteUtil.bytesToBigInteger(vData);
- this.chainId = extractChainIdFromV(v);
- byte[] r = transaction.get(7).getRLPData();
- byte[] s = transaction.get(8).getRLPData();
- this.signature = ECDSASignature.fromComponents(r, s, getRealV(v));
- } else {
- logger.debug("RLP encoded tx is not signed!");
- }
- this.parsed = true;
- this.hash = getHash();
- */
-
- ///
-
- //use protoEncoded directly and it should never be null
- this.hash = Hash.sha3(protoEncoded);
- this.parsed = true;
- TransactionCapsule transaction = new TransactionCapsule(protoEncoded);
- } catch (Exception e) {
- throw new RuntimeException("Error on parsing proto", e);
- }
- }
-
- private void validate() {
- if (receiveAddress != null && receiveAddress.length != 0
- && receiveAddress.length != ADDRESS_LENGTH) {
- throw new RuntimeException("Receive address is not valid");
- }
-
- if (getSignature() != null) {
- if (BigIntegers.asUnsignedByteArray(signature.r).length > HASH_LENGTH) {
- throw new RuntimeException("Signature R is not valid");
- }
- if (BigIntegers.asUnsignedByteArray(signature.s).length > HASH_LENGTH) {
- throw new RuntimeException("Signature S is not valid");
- }
- if (getSender() != null && getSender().length != ADDRESS_LENGTH) {
- throw new RuntimeException("Sender is not valid");
- }
- }
- }
-
- public boolean isParsed() {
- return parsed;
- }
-
- public byte[] getHash() {
- if (!isEmpty(hash)) {
- return Arrays.copyOf(hash, hash.length);
- }
-
- protoParse();
- byte[] plainMsg = this.getEncoded();
- return Hash.sha3(plainMsg);
- }
-
- public byte[] getRawHash() {
- protoParse();
- byte[] plainMsg = this.getEncodedRaw();
- return Hash.sha3(plainMsg);
- }
-
- public long getValue() {
- protoParse();
- return value;
- }
-
- protected void setValue(long value) {
- this.value = value;
- parsed = true;
- }
-
- public byte[] getReceiveAddress() {
- protoParse();
- return receiveAddress;
- }
-
- protected void setReceiveAddress(byte[] receiveAddress) {
- this.receiveAddress = receiveAddress;
- parsed = true;
- }
-
-
- public long nonZeroDataBytes() {
- if (data == null) {
- return 0;
- }
- int counter = 0;
- for (final byte aData : data) {
- if (aData != 0) {
- ++counter;
- }
- }
- return counter;
- }
-
- public long zeroDataBytes() {
- if (data == null) {
- return 0;
- }
- int counter = 0;
- for (final byte aData : data) {
- if (aData == 0) {
- ++counter;
- }
- }
- return counter;
- }
-
-
- public byte[] getData() {
- protoParse();
- return data;
- }
-
- protected void setData(byte[] data) {
- this.data = data;
- parsed = true;
- }
-
- public ECDSASignature getSignature() {
- protoParse();
- return signature;
- }
-
- public byte[] getContractAddress() {
- if (!isContractCreation()) {
- return null;
- }
- // return HashUtil.calcNewAddr(this.getSender(), this.getNonce());
- DataWord addr = new DataWord(this.getSender());
- byte[] privKey = Sha256Hash.hash(addr.getData());
- ECKey ecKey = ECKey.fromPrivate(privKey);
- byte[] newAddress = ecKey.getAddress();
- return newAddress;
- }
-
- public boolean isContractCreation() {
- protoParse();
- return this.receiveAddress == null || Arrays
- .equals(this.receiveAddress, ByteUtil.EMPTY_BYTE_ARRAY);
- }
-
- /*
- * Crypto
- */
-
- public ECKey getKey() {
- byte[] hash = getRawHash();
- return ECKey.recoverFromSignature(signature.v, signature, hash);
- }
-
- public synchronized byte[] getSender() {
- try {
- if (sendAddress == null && getSignature() != null) {
- sendAddress = ECKey.signatureToAddress(getRawHash(), getSignature());
- }
- return sendAddress;
- } catch (SignatureException e) {
- logger.error(e.getMessage(), e);
- }
- return null;
- }
-
- public Integer getChainId() {
- protoParse();
- return chainId == null ? null : (int) chainId;
- }
-
- /**
- * @deprecated should prefer #sign(ECKey) over this method
- */
- public void sign(byte[] privKeyBytes) throws MissingPrivateKeyException {
- sign(ECKey.fromPrivate(privKeyBytes));
- }
-
- public void sign(ECKey key) throws MissingPrivateKeyException {
- this.signature = key.sign(this.getRawHash());
- this.protoEncoded = null;
- }
-
- @Override
- public String toString() {
- return toString(Integer.MAX_VALUE);
- }
-
- public String toString(int maxDataSize) {
- protoParse();
- String dataS;
- if (data == null) {
- dataS = "";
- } else if (data.length < maxDataSize) {
- dataS = ByteUtil.toHexString(data);
- } else {
- dataS = ByteUtil.toHexString(Arrays.copyOfRange(data, 0, maxDataSize)) +
- "... (" + data.length + " bytes)";
- }
- return "TransactionData [" + "hash=" + ByteUtil.toHexString(hash) +
- ", receiveAddress=" + ByteUtil.toHexString(receiveAddress) +
- ", sendAddress=" + ByteUtil.toHexString(getSender()) +
- ", value=" + value +
- ", data=" + dataS +
- ", signatureV=" + (signature == null ? "" : signature.v) +
- ", signatureR=" + (signature == null ? ""
- : ByteUtil.toHexString(BigIntegers.asUnsignedByteArray(signature.r))) +
- ", signatureS=" + (signature == null ? ""
- : ByteUtil.toHexString(BigIntegers.asUnsignedByteArray(signature.s))) +
- "]";
- }
-
- /**
- * For signatures you have to keep also RLP of the transaction without any signature data
- */
- public byte[] getEncodedRaw() {
- protoParse();
- if (protoRaw != null) {
- return Arrays.copyOf(protoRaw, protoRaw.length);
- }
-
- return this.protoEncoded.clone();
- /*
- // parse null as 0 for nonce
- byte[] gasPrice = RLP.encodeElement(this.gasPrice);
- byte[] gasLimit = RLP.encodeElement(this.gasLimit);
- byte[] receiveAddress = RLP.encodeElement(this.receiveAddress);
- byte[] value = longToBytes(this.value);
- byte[] data = RLP.encodeElement(this.data);
-
- // Since EIP-155 use chainId for v
- if (chainId == null) {
- protoRaw = RLP.encodeList(nonce, gasPrice, gasLimit, receiveAddress,
- value, data);
- } else {
- byte[] v, r, s;
- v = RLP.encodeInt(chainId);
- r = RLP.encodeElement(EMPTY_BYTE_ARRAY);
- s = RLP.encodeElement(EMPTY_BYTE_ARRAY);
- rlpRaw = RLP.encodeList(nonce, gasPrice, gasLimit, receiveAddress,
- value, data, v, r, s);
- }
- return rlpRaw;
- */
- }
-
- public byte[] getEncoded() {
-
- if (protoEncoded != null) {
- if (null == this.hash) {
- this.hash = Hash.sha3(protoEncoded);
- }
- return protoEncoded;
- }
- /*
- byte[] gasPrice = RLP.encodeElement(this.gasPrice);
- byte[] gasLimit = RLP.encodeElement(this.gasLimit);
- byte[] receiveAddress = RLP.encodeElement(this.receiveAddress);
- byte[] value = RLP.encodeElement(this.value);
- byte[] data = RLP.encodeElement(this.data);
-
- byte[] v, r, s;
-
- if (signature != null) {
- int encodeV;
- if (chainId == null) {
- encodeV = signature.v;
- } else {
- encodeV = signature.v - LOWER_REAL_V;
- encodeV += chainId * 2 + CHAIN_ID_INC;
- }
- v = RLP.encodeInt(encodeV);
- r = RLP.encodeElement(BigIntegers.asUnsignedByteArray(signature.r));
- s = RLP.encodeElement(BigIntegers.asUnsignedByteArray(signature.s));
- } else {
- // Since EIP-155 use chainId for v
- v = chainId == null ? RLP.encodeElement(EMPTY_BYTE_ARRAY) : RLP.encodeInt(chainId);
- r = RLP.encodeElement(EMPTY_BYTE_ARRAY);
- s = RLP.encodeElement(EMPTY_BYTE_ARRAY);
- }
-
- this.rlpEncoded = RLP.encodeList(nonce, gasPrice, gasLimit,
- receiveAddress, value, data, v, r, s);
-
- this.hash = this.getHash();
- */
-
- byte[] value = Longs.toByteArray(this.value);
- byte[] raw = new byte[this.receiveAddress.length + this.data.length + value.length];
- System.arraycopy(this.receiveAddress, 0, raw, 0, this.receiveAddress.length);
- System.arraycopy(this.data, 0, raw, this.receiveAddress.length, this.data.length);
- System.arraycopy(value, 0, raw, this.data.length, value.length);
- this.protoEncoded = raw;
- this.hash = Hash.sha3(protoEncoded);
-
- return protoEncoded;
- }
-
- @Override
- public int hashCode() {
-
- byte[] hash = this.getHash();
- int hashCode = 0;
-
- for (int i = 0; i < hash.length; ++i) {
- hashCode += hash[i] * i;
- }
-
- return hashCode;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || !(o.getClass() == getClass())) {
- return false;
- }
- VMTransaction tx = (VMTransaction) o;
-
- return tx.hashCode() == this.hashCode();
- }
-
- /**
- * @deprecated Use {@link VMTransaction#createDefault(String, long)} instead
- */
- public static VMTransaction createDefault(String to, long amount) {
- return create(to, amount);
- }
-
- public static VMTransaction createDefault(String to, long amount, Integer chainId) {
- return create(to, amount, chainId);
- }
-
-
- public static VMTransaction create(String to, long amount) {
- return new VMTransaction(
- Hex.decode(to),
- amount,
- null);
- }
-
- public static VMTransaction create(String to, long amount, Integer chainId) {
- return new VMTransaction(
- Hex.decode(to),
- amount,
- null,
- chainId);
- }
-}
diff --git a/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvoke.java b/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvoke.java
index a929e62c7a1..ca715165422 100644
--- a/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvoke.java
+++ b/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvoke.java
@@ -53,10 +53,6 @@ public interface ProgramInvoke {
DataWord getDifficulty();
- DataWord getDroplimit();
-
- long getDroplimitLong();
-
boolean byTransaction();
boolean byTestingSuite();
@@ -72,4 +68,6 @@ public interface ProgramInvoke {
long getVmShouldEndInUs();
long getVmStartInUs();
+
+ long getEnergyLimit();
}
diff --git a/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeFactory.java b/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeFactory.java
index ad55c13200d..5b39c4c1342 100644
--- a/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeFactory.java
+++ b/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeFactory.java
@@ -19,6 +19,7 @@
import org.tron.common.runtime.vm.DataWord;
import org.tron.common.runtime.vm.program.InternalTransaction;
+import org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType;
import org.tron.common.runtime.vm.program.Program;
import org.tron.common.storage.Deposit;
import org.tron.protos.Protocol.Block;
@@ -30,14 +31,14 @@
*/
public interface ProgramInvokeFactory {
- ProgramInvoke createProgramInvoke(InternalTransaction.TrxType trxType,
- InternalTransaction.ExecuterType executerType,
- Transaction tx, Block block, Deposit deposit, long vmStartInUs, long vmShouldEndInUs);
+ ProgramInvoke createProgramInvoke(InternalTransaction.TrxType trxType, ExecutorType executorType,
+ Transaction tx, Block block, Deposit deposit, long vmStartInUs, long vmShouldEndInUs,
+ long energyLimit);
ProgramInvoke createProgramInvoke(Program program, DataWord toAddress, DataWord callerAddress,
DataWord inValue,
long balanceInt, byte[] dataIn, Deposit deposit, boolean staticCall, boolean byTestingSuite,
- long vmStartInUs, long vmShouldEndInUs);
+ long vmStartInUs, long vmShouldEndInUs, long energyLimit);
}
diff --git a/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeFactoryImpl.java b/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeFactoryImpl.java
index 769afa446bc..3b0655c4717 100644
--- a/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeFactoryImpl.java
+++ b/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeFactoryImpl.java
@@ -25,6 +25,7 @@
import org.springframework.stereotype.Component;
import org.tron.common.runtime.vm.DataWord;
import org.tron.common.runtime.vm.program.InternalTransaction;
+import org.tron.common.runtime.vm.program.InternalTransaction.ExecutorType;
import org.tron.common.runtime.vm.program.Program;
import org.tron.common.storage.Deposit;
import org.tron.common.utils.ByteUtil;
@@ -47,8 +48,8 @@ public class ProgramInvokeFactoryImpl implements ProgramInvokeFactory {
// Invocation by the wire tx
@Override
public ProgramInvoke createProgramInvoke(InternalTransaction.TrxType trxType,
- InternalTransaction.ExecuterType executerType,
- Transaction tx, Block block, Deposit deposit, long vmStartInUs, long vmShouldEndInUs) {
+ ExecutorType executorType, Transaction tx, Block block, Deposit deposit, long vmStartInUs,
+ long vmShouldEndInUs, long energyLimit) {
byte[] contractAddress;
byte[] ownerAddress;
long balance;
@@ -64,22 +65,26 @@ public ProgramInvoke createProgramInvoke(InternalTransaction.TrxType trxType,
ownerAddress = contract.getOwnerAddress().toByteArray();
balance = deposit.getBalance(ownerAddress);
data = ByteUtil.EMPTY_BYTE_ARRAY;
+ long callValue = contract.getNewContract().getCallValue();
- switch (executerType) {
+ switch (executorType) {
case ET_NORMAL_TYPE:
- lastHash = block.getBlockHeader().getRawDataOrBuilder().getParentHash().toByteArray();
- coinbase = block.getBlockHeader().getRawDataOrBuilder().getWitnessAddress().toByteArray();
- timestamp = block.getBlockHeader().getRawDataOrBuilder().getTimestamp();
- number = block.getBlockHeader().getRawDataOrBuilder().getNumber();
- break;
case ET_PRE_TYPE:
+ if (null != block) {
+ lastHash = block.getBlockHeader().getRawDataOrBuilder().getParentHash().toByteArray();
+ coinbase = block.getBlockHeader().getRawDataOrBuilder().getWitnessAddress().toByteArray();
+ timestamp = block.getBlockHeader().getRawDataOrBuilder().getTimestamp();
+ number = block.getBlockHeader().getRawDataOrBuilder().getNumber();
+ }
break;
default:
return null;
}
- return new ProgramInvokeImpl(contractAddress, ownerAddress, ownerAddress, balance, null, data,
- lastHash, coinbase, timestamp, number, deposit, vmStartInUs, vmShouldEndInUs);
+
+ return new ProgramInvokeImpl(contractAddress, ownerAddress, ownerAddress, balance, callValue, data,
+ lastHash, coinbase, timestamp, number, deposit, vmStartInUs, vmShouldEndInUs,
+ energyLimit);
} else if (trxType == TRX_CONTRACT_CALL_TYPE) {
Contract.TriggerSmartContract contract = ContractCapsule
@@ -105,7 +110,7 @@ public ProgramInvoke createProgramInvoke(InternalTransaction.TrxType trxType,
/*** CALLVALUE op ***/
// byte[] callValue = nullToEmpty(tx.getValue());
- byte[] callValue = contract.getCallValue().toByteArray();
+ long callValue = contract.getCallValue();
/*** CALLDATALOAD op ***/
/*** CALLDATACOPY op ***/
@@ -113,28 +118,30 @@ public ProgramInvoke createProgramInvoke(InternalTransaction.TrxType trxType,
// byte[] data = tx.isContractCreation() ? ByteUtil.EMPTY_BYTE_ARRAY : nullToEmpty(tx.getData());
data = contract.getData().toByteArray();
- // dropLimit = contract.getTrxCpuLimitInUs().toByteArray();
- switch (executerType) {
+ // dropLimit = contract.getTrxEnergyLimitInUs().toByteArray();
+ switch (executorType) {
case ET_CONSTANT_TYPE:
break;
case ET_PRE_TYPE:
- break;
case ET_NORMAL_TYPE:
- /*** PREVHASH op ***/
- lastHash = block.getBlockHeader().getRawDataOrBuilder().getParentHash().toByteArray();
- /*** COINBASE op ***/
- coinbase = block.getBlockHeader().getRawDataOrBuilder().getWitnessAddress().toByteArray();
- /*** TIMESTAMP op ***/
- timestamp = block.getBlockHeader().getRawDataOrBuilder().getTimestamp();
- /*** NUMBER op ***/
- number = block.getBlockHeader().getRawDataOrBuilder().getNumber();
+ if (null != block) {
+ /*** PREVHASH op ***/
+ lastHash = block.getBlockHeader().getRawDataOrBuilder().getParentHash().toByteArray();
+ /*** COINBASE op ***/
+ coinbase = block.getBlockHeader().getRawDataOrBuilder().getWitnessAddress().toByteArray();
+ /*** TIMESTAMP op ***/
+ timestamp = block.getBlockHeader().getRawDataOrBuilder().getTimestamp();
+ /*** NUMBER op ***/
+ number = block.getBlockHeader().getRawDataOrBuilder().getNumber();
+ }
break;
default:
break;
}
return new ProgramInvokeImpl(address, origin, caller, balance, callValue, data,
- lastHash, coinbase, timestamp, number, deposit, vmStartInUs, vmShouldEndInUs);
+ lastHash, coinbase, timestamp, number, deposit, vmStartInUs, vmShouldEndInUs,
+ energyLimit);
} else {
return null;
}
@@ -149,7 +156,7 @@ public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress,
DataWord callerAddress,
DataWord inValue, long balanceInt, byte[] dataIn,
Deposit deposit, boolean isStaticCall, boolean byTestingSuite, long vmStartInUs,
- long vmShouldEndInUs) {
+ long vmShouldEndInUs, long energyLimit) {
DataWord address = toAddress;
DataWord origin = program.getOriginAddress();
@@ -167,7 +174,7 @@ public ProgramInvoke createProgramInvoke(Program program, DataWord toAddress,
return new ProgramInvokeImpl(address, origin, caller, balance, callValue,
data, lastHash, coinbase, timestamp, number, difficulty,
deposit, program.getCallDeep() + 1, isStaticCall, byTestingSuite, vmStartInUs,
- vmShouldEndInUs);
+ vmShouldEndInUs, energyLimit);
}
}
diff --git a/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeImpl.java b/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeImpl.java
index 07bcd605bf0..6b5470001f1 100644
--- a/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeImpl.java
+++ b/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeImpl.java
@@ -19,13 +19,13 @@
import java.math.BigInteger;
import java.util.Arrays;
+import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
import org.tron.common.runtime.vm.DataWord;
import org.tron.common.storage.Deposit;
import org.tron.core.db.BlockStore;
@Slf4j
-
public class ProgramInvokeImpl implements ProgramInvoke {
// private BlockStore blockStore;
@@ -36,6 +36,7 @@ public class ProgramInvokeImpl implements ProgramInvoke {
private long vmStartInUs;
private long vmShouldEndInUs;
+ private long energyLimit;
/* BLOCK env **/
private final DataWord prevHash, coinbase, timestamp, number;
@@ -51,19 +52,22 @@ public ProgramInvokeImpl(DataWord address, DataWord origin, DataWord caller, Dat
DataWord lastHash, DataWord coinbase, DataWord timestamp, DataWord number,
DataWord difficulty,
Deposit deposit, int callDeep, boolean isStaticCall, boolean byTestingSuite,
- long vmStartInUs, long vmShouldEndInUs) {
+ long vmStartInUs, long vmShouldEndInUs, long energyLimit) {
this.address = address;
this.origin = origin;
this.caller = caller;
this.balance = balance;
this.callValue = callValue;
- this.msgData = Arrays.copyOf(msgData, msgData.length);
+ if (Objects.nonNull(msgData)) {
+ this.msgData = Arrays.copyOf(msgData, msgData.length);
+ }
// last Block env
this.prevHash = lastHash;
this.coinbase = coinbase;
this.timestamp = timestamp;
this.number = number;
+ this.callDeep = callDeep;
this.deposit = deposit;
this.byTransaction = false;
@@ -71,21 +75,22 @@ public ProgramInvokeImpl(DataWord address, DataWord origin, DataWord caller, Dat
this.byTestingSuite = byTestingSuite;
this.vmStartInUs = vmStartInUs;
this.vmShouldEndInUs = vmShouldEndInUs;
+ this.energyLimit = energyLimit;
}
public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, long balance,
- byte[] callValue, byte[] msgData,
+ long callValue, byte[] msgData,
byte[] lastHash, byte[] coinbase, long timestamp, long number, Deposit deposit,
- long vmStartInUs, long vmShouldEndInUs, boolean byTestingSuite) {
+ long vmStartInUs, long vmShouldEndInUs, boolean byTestingSuite, long energyLimit) {
this(address, origin, caller, balance, callValue, msgData, lastHash, coinbase,
- timestamp, number, deposit, vmStartInUs, vmShouldEndInUs);
+ timestamp, number, deposit, vmStartInUs, vmShouldEndInUs, energyLimit);
this.byTestingSuite = byTestingSuite;
}
public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, long balance,
- byte[] callValue, byte[] msgData, byte[] lastHash, byte[] coinbase, long timestamp,
- long number, Deposit deposit, long vmStartInUs, long vmShouldEndInUs) {
+ long callValue, byte[] msgData, byte[] lastHash, byte[] coinbase, long timestamp,
+ long number, Deposit deposit, long vmStartInUs, long vmShouldEndInUs, long energyLimit) {
// Transaction env
this.address = new DataWord(address);
@@ -105,6 +110,7 @@ public ProgramInvokeImpl(byte[] address, byte[] origin, byte[] caller, long bala
// calc should end time
this.vmStartInUs = vmStartInUs;
this.vmShouldEndInUs = vmShouldEndInUs;
+ this.energyLimit = energyLimit;
// logger.info("vmStartInUs: {}", vmStartInUs);
// logger.info("vmShouldEndInUs: {}", vmShouldEndInUs);
@@ -222,36 +228,17 @@ public DataWord getDifficulty() {
return null; //difficulty;
}
- /* GASLIMIT op */
- @Override
- public DataWord getDroplimit() {
- return DataWord.ZERO;
- }
-
- @Override
- public long getDroplimitLong() {
- return 0;
- }
-
public long getVmShouldEndInUs() {
return vmShouldEndInUs;
}
- /* Storage */
- /*
- public Map getStorage() {
- return storage;
- }
- */
-
public Deposit getDeposit() {
return deposit;
}
@Override
public BlockStore getBlockStore() {
- return null;
- //return deposit.getBlockStore();
+ return deposit.getDbManager().getBlockStore();
}
@Override
@@ -313,8 +300,8 @@ public boolean equals(Object o) {
return false;
}
//if (difficulty != null ? !difficulty.equals(that.difficulty) : that.difficulty != null) return false;
- //if (gas != null ? !gas.equals(that.gas) : that.gas != null) return false;
- //if (gasPrice != null ? !gasPrice.equals(that.gasPrice) : that.gasPrice != null) return false;
+ //if (energy != null ? !energy.equals(that.energy) : that.energy != null) return false;
+ //if (energyPrice != null ? !energyPrice.equals(that.energyPrice) : that.energyPrice != null) return false;
//if (dropLimit != null ? !dropLimit.equals(that.dropLimit) : that.dropLimit != null) {
// return false;
// }
@@ -377,4 +364,9 @@ public String toString() {
", callDeep=" + callDeep +
'}';
}
+
+ public long getEnergyLimit() {
+ return energyLimit;
+ }
+
}
diff --git a/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeMockImpl.java b/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeMockImpl.java
index 8503aadbec0..cef34074b2a 100644
--- a/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeMockImpl.java
+++ b/src/main/java/org/tron/common/runtime/vm/program/invoke/ProgramInvokeMockImpl.java
@@ -40,9 +40,6 @@ public class ProgramInvokeMockImpl implements ProgramInvoke {
private byte[] ownerAddress = Hex.decode("cd2a3d9f938e13cd947ec05abc7fe734df8dd826");
private final byte[] contractAddress = Hex.decode("471fd3ad3e9eeadeec4608b92d16ce6b500704cc");
- // default for most tests. This can be overwritten by the test
- private long dropLimit = 1000000;
-
public ProgramInvokeMockImpl(byte[] msgDataRaw) {
this();
this.msgData = msgDataRaw;
@@ -96,21 +93,11 @@ public DataWord getCallerAddress() {
return new DataWord(addr);
}
- /* GASPRICE op */
- public DataWord getMinGasPrice() {
-
- byte[] minGasPrice = Hex.decode("09184e72a000");
- return new DataWord(minGasPrice);
- }
-
- /* GAS op */
- public DataWord getGas() {
+ /* ENERGYPRICE op */
+ public DataWord getMinEnergyPrice() {
- return new DataWord(dropLimit);
- }
-
- public void setGas(long gasLimit) {
- this.dropLimit = gasLimit;
+ byte[] minEnergyPrice = Hex.decode("09184e72a000");
+ return new DataWord(minEnergyPrice);
}
/* CALLVALUE op */
@@ -119,14 +106,6 @@ public DataWord getCallValue() {
return new DataWord(balance);
}
- public DataWord getDroplimit() {
- return null;
- }
-
- public long getDroplimitLong() {
- return dropLimit;
- }
-
/*****************/
/*** msg data ***/
/**
@@ -239,6 +218,11 @@ public long getVmStartInUs() {
return 0;
}
+ @Override
+ public long getEnergyLimit() {
+ return 0;
+ }
+
@Override
public boolean byTestingSuite() {
return false;
diff --git a/src/main/java/org/tron/common/runtime/vm/trace/Op.java b/src/main/java/org/tron/common/runtime/vm/trace/Op.java
index bc96720f017..5e450628996 100644
--- a/src/main/java/org/tron/common/runtime/vm/trace/Op.java
+++ b/src/main/java/org/tron/common/runtime/vm/trace/Op.java
@@ -17,16 +17,15 @@
*/
package org.tron.common.runtime.vm.trace;
-import org.tron.common.runtime.vm.OpCode;
-
import java.math.BigInteger;
+import org.tron.common.runtime.vm.OpCode;
public class Op {
private OpCode code;
private int deep;
private int pc;
- private BigInteger gas;
+ private BigInteger energy;
private OpActions actions;
public OpCode getCode() {
@@ -53,12 +52,12 @@ public void setPc(int pc) {
this.pc = pc;
}
- public BigInteger getGas() {
- return gas;
+ public BigInteger getEnergy() {
+ return energy;
}
- public void setGas(BigInteger gas) {
- this.gas = gas;
+ public void setEnergy(BigInteger energy) {
+ this.energy = energy;
}
public OpActions getActions() {
diff --git a/src/main/java/org/tron/common/runtime/vm/trace/ProgramTrace.java b/src/main/java/org/tron/common/runtime/vm/trace/ProgramTrace.java
index 1f03d7bf08c..90938eb2fa7 100644
--- a/src/main/java/org/tron/common/runtime/vm/trace/ProgramTrace.java
+++ b/src/main/java/org/tron/common/runtime/vm/trace/ProgramTrace.java
@@ -17,19 +17,19 @@
*/
package org.tron.common.runtime.vm.trace;
+import static java.lang.String.format;
+import static org.tron.common.runtime.utils.MUtil.convertToTronAddress;
+import static org.tron.common.runtime.vm.trace.Serializers.serializeFieldsOnly;
+import static org.tron.common.utils.ByteUtil.toHexString;
+
+import java.util.ArrayList;
+import java.util.List;
import org.spongycastle.util.encoders.Hex;
import org.tron.common.runtime.config.SystemProperties;
import org.tron.common.runtime.vm.DataWord;
import org.tron.common.runtime.vm.OpCode;
import org.tron.common.runtime.vm.program.invoke.ProgramInvoke;
-import java.util.ArrayList;
-import java.util.List;
-
-import static java.lang.String.format;
-import static org.tron.common.runtime.vm.trace.Serializers.serializeFieldsOnly;
-import static org.tron.common.utils.ByteUtil.toHexString;
-
public class ProgramTrace {
private List ops = new ArrayList<>();
@@ -43,7 +43,7 @@ public ProgramTrace() {
public ProgramTrace(SystemProperties config, ProgramInvoke programInvoke) {
if (programInvoke != null && config.vmTrace()) {
- contractAddress = Hex.toHexString(programInvoke.getOwnerAddress().getLast20Bytes());
+ contractAddress = Hex.toHexString(convertToTronAddress(programInvoke.getOwnerAddress().getLast20Bytes()));
}
}
@@ -89,12 +89,12 @@ public ProgramTrace error(Exception error) {
return this;
}
- public Op addOp(byte code, int pc, int deep, DataWord gas, OpActions actions) {
+ public Op addOp(byte code, int pc, int deep, DataWord energy, OpActions actions) {
Op op = new Op();
op.setActions(actions);
op.setCode(OpCode.code(code));
op.setDeep(deep);
- op.setGas(gas.value());
+ op.setEnergy(energy.value());
op.setPc(pc);
ops.add(op);
diff --git a/src/main/java/org/tron/common/runtime/vm/trace/Serializers.java b/src/main/java/org/tron/common/runtime/vm/trace/Serializers.java
index 12f0a86da8f..5f1775c8912 100644
--- a/src/main/java/org/tron/common/runtime/vm/trace/Serializers.java
+++ b/src/main/java/org/tron/common/runtime/vm/trace/Serializers.java
@@ -25,14 +25,13 @@
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.SerializerProvider;
import com.fasterxml.jackson.databind.introspect.VisibilityChecker;
+import java.io.IOException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.spongycastle.util.encoders.Hex;
import org.tron.common.runtime.vm.DataWord;
import org.tron.common.runtime.vm.OpCode;
-import java.io.IOException;
-
public final class Serializers {
private static final Logger LOGGER = LoggerFactory.getLogger("vmtrace");
@@ -40,8 +39,9 @@ public final class Serializers {
public static class DataWordSerializer extends JsonSerializer {
@Override
- public void serialize(DataWord gas, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
- jgen.writeString(gas.value().toString());
+ public void serialize(DataWord energy, JsonGenerator jgen, SerializerProvider provider)
+ throws IOException, JsonProcessingException {
+ jgen.writeString(energy.value().toString());
}
}
diff --git a/src/main/java/org/tron/common/storage/Deposit.java b/src/main/java/org/tron/common/storage/Deposit.java
index b66059751b2..57397181e53 100644
--- a/src/main/java/org/tron/common/storage/Deposit.java
+++ b/src/main/java/org/tron/common/storage/Deposit.java
@@ -1,35 +1,27 @@
package org.tron.common.storage;
-import com.google.protobuf.ByteString;
import org.tron.common.runtime.vm.DataWord;
+import org.tron.common.runtime.vm.program.Storage;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.BlockCapsule;
import org.tron.core.capsule.BytesCapsule;
import org.tron.core.capsule.ContractCapsule;
-import org.tron.core.capsule.StorageCapsule;
import org.tron.core.capsule.TransactionCapsule;
import org.tron.core.db.Manager;
-import org.tron.core.exception.ContractExeException;
import org.tron.protos.Protocol;
-/**
- * @author Guo Yonggang
- * @since 2018.04
- */
public interface Deposit {
Manager getDbManager();
AccountCapsule createAccount(byte[] address, Protocol.AccountType type);
- AccountCapsule createAccount(byte[] address, ByteString accountName, Protocol.AccountType type);
+ AccountCapsule createAccount(byte[] address, String accountName, Protocol.AccountType type);
AccountCapsule getAccount(byte[] address);
void createContract(byte[] address, ContractCapsule contractCapsule);
- void createContractByNormalAccountIndex(byte[] address, BytesCapsule contractAddress);
-
ContractCapsule getContract(byte[] address);
void saveCode(byte[] codeHash, byte[] code);
@@ -38,15 +30,15 @@ public interface Deposit {
//byte[] getCodeHash(byte[] address);
- void addStorageValue(byte[] address, DataWord key, DataWord value);
+ void putStorageValue(byte[] address, DataWord key, DataWord value);
DataWord getStorageValue(byte[] address, DataWord key);
- StorageCapsule getStorage(byte[] address);
+ Storage getStorage(byte[] address);
long getBalance(byte[] address);
- long addBalance(byte[] address, long value) throws ContractExeException;
+ long addBalance(byte[] address, long value);
Deposit newDepositChild();
@@ -75,9 +67,7 @@ public interface Deposit {
void putContract(Key key, Value value);
- void putContractByNormalAccountIndex(Key key, Value value);
-
- void putStorage(Key key, Value value);
+ void putStorage(Key key, Storage cache);
void putVotes(Key key, Value value);
@@ -89,8 +79,6 @@ public interface Deposit {
BlockCapsule getBlock(byte[] blockHash);
- BytesCapsule getContractByNormalAccount(byte[] address);
-
long computeAfterRunStorageSize();
long getBeforeRunStorageSize();
diff --git a/src/main/java/org/tron/common/storage/DepositImpl.java b/src/main/java/org/tron/common/storage/DepositImpl.java
index e7e44c05c59..8f27f4a90e0 100644
--- a/src/main/java/org/tron/common/storage/DepositImpl.java
+++ b/src/main/java/org/tron/common/storage/DepositImpl.java
@@ -6,32 +6,27 @@
import java.util.HashMap;
import java.util.concurrent.atomic.AtomicLong;
import org.tron.common.runtime.vm.DataWord;
+import org.tron.common.runtime.vm.program.Storage;
import org.tron.common.utils.StringUtil;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.BlockCapsule;
import org.tron.core.capsule.BytesCapsule;
import org.tron.core.capsule.ContractCapsule;
-import org.tron.core.capsule.StorageCapsule;
import org.tron.core.capsule.TransactionCapsule;
-import org.tron.core.db.AccountContractIndexStore;
import org.tron.core.db.AccountStore;
import org.tron.core.db.AssetIssueStore;
import org.tron.core.db.BlockStore;
import org.tron.core.db.CodeStore;
import org.tron.core.db.ContractStore;
import org.tron.core.db.Manager;
-import org.tron.core.db.StorageStore;
+import org.tron.core.db.StorageRowStore;
import org.tron.core.db.TransactionStore;
import org.tron.core.db.VotesStore;
import org.tron.core.db.WitnessStore;
import org.tron.core.exception.BadItemException;
-import org.tron.core.exception.ContractExeException;
import org.tron.protos.Protocol;
+import org.tron.protos.Protocol.AccountType;
-/**
- * @author Guo Yonggang
- * @since 27.04.2018
- */
public class DepositImpl implements Deposit {
private Manager dbManager;
@@ -39,7 +34,6 @@ public class DepositImpl implements Deposit {
private Deposit prevDeposit = null;
private Deposit nextDeposit = null;
- private long beforeRunStorageSize = 0;
private HashMap accounCache = new HashMap<>();
private HashMap transactionCache = new HashMap<>();
private HashMap blockCache = new HashMap<>();
@@ -47,10 +41,10 @@ public class DepositImpl implements Deposit {
private HashMap blockIndexCache = new HashMap<>();
private HashMap codeCache = new HashMap<>();
private HashMap contractCache = new HashMap<>();
- private HashMap storageCache = new HashMap<>();
+
private HashMap votesCache = new HashMap<>();
- private HashMap assetIssueCache = new HashMap<>();
private HashMap accountContractIndexCache = new HashMap<>();
+ private HashMap storageCache = new HashMap<>();
private DepositImpl(Manager dbManager, DepositImpl parent, DepositImpl prev) {
init(dbManager, parent, prev);
@@ -96,18 +90,14 @@ private CodeStore getCodeStore() {
return dbManager.getCodeStore();
}
- private StorageStore getStorageStore() {
- return dbManager.getStorageStore();
+ private StorageRowStore getStorageRowStore() {
+ return dbManager.getStorageRowStore();
}
private AssetIssueStore getAssetIssueStore() {
return dbManager.getAssetIssueStore();
}
- private AccountContractIndexStore getAccountContractIndexStore() {
- return dbManager.getAccountContractIndexStore();
- }
-
@Override
public Deposit newDepositChild() {
return new DepositImpl(dbManager, this, null);
@@ -127,10 +117,10 @@ public synchronized AccountCapsule createAccount(byte[] address, Protocol.Accoun
}
@Override
- public synchronized AccountCapsule createAccount(byte[] address, ByteString accountName,
- Protocol.AccountType type) {
+ public AccountCapsule createAccount(byte[] address, String accountName, AccountType type) {
Key key = new Key(address);
- AccountCapsule account = new AccountCapsule(ByteString.copyFrom(address), accountName,
+ AccountCapsule account = new AccountCapsule(ByteString.copyFrom(address),
+ ByteString.copyFromUtf8(accountName),
type);
accounCache.put(key, new Value(account.getData(), Type.VALUE_TYPE_CREATE));
@@ -159,29 +149,6 @@ public synchronized AccountCapsule getAccount(byte[] address) {
return accountCapsule;
}
-
- public synchronized BytesCapsule getContractByNormalAccount(byte[] address) {
-
- Key key = new Key(address);
- if (accountContractIndexCache.containsKey(key)) {
- return accountContractIndexCache.get(key).getBytes();
- }
-
- BytesCapsule contract;
- if (parent != null) {
- contract = parent.getContractByNormalAccount(address);
- } else if (prevDeposit != null) {
- contract = prevDeposit.getContractByNormalAccount(address);
- } else {
- contract = getAccountContractIndexStore().get(address);
- }
-
- if (contract != null) {
- accountContractIndexCache.put(key, Value.create(contract.getData()));
- }
- return contract;
- }
-
@Override
public synchronized void createContract(byte[] address, ContractCapsule contractCapsule) {
Key key = Key.create(address);
@@ -189,14 +156,6 @@ public synchronized void createContract(byte[] address, ContractCapsule contract
contractCache.put(key, value);
}
- @Override
- public synchronized void createContractByNormalAccountIndex(byte[] address,
- BytesCapsule contractAddress) {
- Key key = new Key(address);
- accountContractIndexCache
- .put(key, Value.create(contractAddress.getData(), Type.VALUE_TYPE_CREATE));
- }
-
@Override
public synchronized ContractCapsule getContract(byte[] address) {
Key key = Key.create(address);
@@ -230,7 +189,7 @@ public synchronized void saveCode(byte[] codeHash, byte[] code) {
public synchronized byte[] getCode(byte[] codeHash) {
Key key = Key.create(codeHash);
if (codeCache.containsKey(key)) {
- codeCache.get(key).getCode().getData();
+ return codeCache.get(key).getCode().getData();
}
byte[] code;
@@ -245,78 +204,45 @@ public synchronized byte[] getCode(byte[] codeHash) {
code = getCodeStore().get(codeHash).getData();
}
}
-
if (code != null) {
codeCache.put(key, Value.create(code));
}
return code;
}
- /*
- @Override
- public byte[] getCodeHash(byte[] address) {
- AccountCapsule accountCapsule = getAccount(address);
- return accountCapsule != null ? accountCapsule.getCodeHash() : null;
- }
- */
-
@Override
- public synchronized StorageCapsule getStorage(byte[] address) {
+ public synchronized Storage getStorage(byte[] address) {
Key key = Key.create(address);
if (storageCache.containsKey(key)) {
- return storageCache.get(key).getStorage();
+ return storageCache.get(key);
}
- // first access the storageCapsule
- StorageCapsule storageCapsule;
+ Storage storage;
if (this.parent != null) {
- storageCapsule = parent.getStorage(address);
+ storage = parent.getStorage(address);
} else if (prevDeposit != null) {
- storageCapsule = prevDeposit.getStorage(address);
+ storage = prevDeposit.getStorage(address);
} else {
- storageCapsule = getStorageStore().get(address);
- }
-
- if (storageCapsule != null) {
- storageCache.put(key, Value.create(storageCapsule.getData(), Type.VALUE_TYPE_NORMAL));
- this.beforeRunStorageSize += storageCapsule.getInstance().getSerializedSize();
+ storage = new Storage(address, dbManager);
}
- return storageCapsule;
+ return storage;
}
@Override
- public synchronized void addStorageValue(byte[] address, DataWord key, DataWord value) {
+ public synchronized void putStorageValue(byte[] address, DataWord key, DataWord value) {
address = convertToTronAddress(address);
if (getAccount(address) == null) {
return;
}
Key addressKey = Key.create(address);
+ Storage storage;
if (storageCache.containsKey(addressKey)) {
- StorageCapsule storageCapsule = storageCache.get(addressKey).getStorage();
-
- if (storageCapsule != null) {
- storageCapsule.put(key, value);
- Value V = Value.create(storageCapsule.getData(),
- Type.VALUE_TYPE_DIRTY | storageCache.get(addressKey).getType().getType());
- storageCache.put(addressKey, V);
- }
+ storage = storageCache.get(addressKey);
} else {
- StorageCapsule storageCapsule = getStorage(address);
- if (storageCapsule == null) {
- Protocol.StorageItem.Builder builder = Protocol.StorageItem.newBuilder();
- builder.setContractAddress(ByteString.copyFrom(address));
- Protocol.StorageItem storageItem = builder.build();
- storageCapsule = new StorageCapsule(storageItem);
- storageCapsule.put(key, value);
- Value V = Value.create(storageCapsule.getData(), Type.VALUE_TYPE_CREATE);
- storageCache.put(addressKey, V);
- } else {
- storageCapsule.put(key, value);
- Value V = Value.create(storageCapsule.getData(),
- Type.VALUE_TYPE_DIRTY | storageCache.get(addressKey).getType().getType());
- storageCache.put(addressKey, V);
- }
+ storage = getStorage(address);
+ storageCache.put(addressKey, storage);
}
+ storage.put(key, value);
}
@Override
@@ -326,25 +252,14 @@ public synchronized DataWord getStorageValue(byte[] address, DataWord key) {
return null;
}
Key addressKey = Key.create(address);
+ Storage storage;
if (storageCache.containsKey(addressKey)) {
- StorageCapsule storageCapsule = storageCache.get(addressKey).getStorage();
- return storageCapsule.get(key);
- }
-
- StorageCapsule storageCapsule = getStorage(address);
- if (storageCapsule != null) {
- Value V = Value.create(storageCapsule.getData(), Type.VALUE_TYPE_NORMAL);
- storageCache.put(addressKey, V);
- return storageCapsule.get(key);
+ storage = storageCache.get(addressKey);
} else {
- Protocol.StorageItem.Builder builder = Protocol.StorageItem.newBuilder();
- builder.setContractAddress(ByteString.copyFrom(address));
- Protocol.StorageItem storageItem = builder.build();
- storageCapsule = new StorageCapsule(storageItem);
- Value V = Value.create(storageCapsule.getData(), Type.VALUE_TYPE_CREATE);
- storageCache.put(addressKey, V);
- return storageCapsule.get(key);
+ storage = getStorage(address);
+ storageCache.put(addressKey, storage);
}
+ return storage.getValue(key);
}
@Override
@@ -354,8 +269,7 @@ public synchronized long getBalance(byte[] address) {
}
@Override
- public synchronized long addBalance(byte[] address, long value)
- throws ContractExeException {
+ public synchronized long addBalance(byte[] address, long value) {
AccountCapsule accountCapsule = getAccount(address);
if (accountCapsule == null) {
accountCapsule = createAccount(address, Protocol.AccountType.Normal);
@@ -367,7 +281,7 @@ public synchronized long addBalance(byte[] address, long value)
}
if (value < 0 && balance < -value) {
- throw new ContractExeException(
+ throw new RuntimeException(
StringUtil.createReadableString(accountCapsule.createDbKey())
+ " insufficient balance");
}
@@ -434,15 +348,19 @@ public BlockCapsule getBlock(byte[] blockHash) {
@Override
public long computeAfterRunStorageSize() {
AtomicLong afterRunStorageSize = new AtomicLong();
- storageCache.forEach(((key, value) -> {
- afterRunStorageSize.addAndGet(value.getStorage().getInstance().getSerializedSize());
- }));
+ storageCache.forEach((key, value) -> {
+ afterRunStorageSize.getAndAdd(value.computeSize());
+ });
return afterRunStorageSize.get();
}
@Override
public long getBeforeRunStorageSize() {
- return beforeRunStorageSize;
+ AtomicLong beforeRunStorageSize = new AtomicLong();
+ storageCache.forEach((key, value) -> {
+ beforeRunStorageSize.getAndAdd(value.getBeforeUseSize());
+ });
+ return beforeRunStorageSize.get();
}
@@ -476,14 +394,14 @@ public void putContract(Key key, Value value) {
contractCache.put(key, value);
}
- @Override
- public void putContractByNormalAccountIndex(Key key, Value value) {
- accountContractIndexCache.put(key, value);
- }
+// @Override
+// public void putStorage(Key key, Value value) {
+// storageCache.put(key, value);
+// }
@Override
- public void putStorage(Key key, Value value) {
- storageCache.put(key, value);
+ public void putStorage(Key key, Storage cache) {
+ storageCache.put(key, cache);
}
@Override
@@ -564,15 +482,16 @@ private void commitContractCache(Deposit deposit) {
}
private void commitStorageCache(Deposit deposit) {
- storageCache.forEach(((key, value) -> {
- if (value.getType().isDirty() || value.getType().isCreate()) {
- if (deposit != null) {
- deposit.putStorage(key, value);
- } else {
- getStorageStore().put(key.getData(), value.getStorage());
- }
+ storageCache.forEach((key, value) -> {
+ if (deposit != null) {
+ // write to parent cache
+ deposit.putStorage(key, value);
+ } else {
+ // persistence
+ value.commit();
}
- }));
+ });
+
}
private void commitVoteCache(Deposit deposit) {
@@ -587,18 +506,6 @@ private void commitVoteCache(Deposit deposit) {
}));
}
- private void commitAccountContractIndex(Deposit deposit) {
- accountContractIndexCache.forEach(((key, value) -> {
- if (value.getType().isDirty() || value.getType().isCreate()) {
- if (deposit != null) {
- deposit.putContractByNormalAccountIndex(key, value);
- } else {
- getAccountContractIndexStore().put(key.getData(), value.getBytes());
- }
- }
- }));
- }
-
@Override
public void syncCacheFromAccountStore(byte[] address) {
Key key = Key.create(address);
@@ -642,7 +549,7 @@ public synchronized void commit() {
commitContractCache(deposit);
commitStorageCache(deposit);
commitVoteCache(deposit);
-
+ // commitAccountContractIndex(deposit);
}
@Override
diff --git a/src/main/java/org/tron/common/storage/DepositQueue.java b/src/main/java/org/tron/common/storage/DepositQueue.java
deleted file mode 100644
index 4d4c07abfad..00000000000
--- a/src/main/java/org/tron/common/storage/DepositQueue.java
+++ /dev/null
@@ -1,87 +0,0 @@
-package org.tron.common.storage;
-
-import java.util.LinkedList;
-
-/**
- * Deposit Queue (FIFO) based on LinkedList
- *
- * @author Guo Yonggang
- * @since 28.04.2018
- */
-public class DepositQueue {
-
- public static int MAX_DEPOSIT_SIZE = 100;
- public static int DEFAULT_DEPOSIT_SIZE = 20;
-
- private int maxDepositSize = 0;
- private LinkedList list = new LinkedList<>();
-
- public DepositQueue(int maxSize) {
- if (maxSize <= 0 || maxSize > MAX_DEPOSIT_SIZE) {
- maxDepositSize = DEFAULT_DEPOSIT_SIZE;
- } else {
- maxDepositSize = maxSize;
- }
- }
-
- /**
- *
- * @param obj
- */
- public void put(E obj) {
- list.addLast(obj);
- }
-
- /**
- *
- * @return
- */
- public E get() {
- if (list.isEmpty()) return null;
-
- return list.removeFirst();
- }
-
- /**
- *
- * @return
- */
- public E peek() {
- if (list.isEmpty()) return null;
- return list.getFirst();
- }
-
- /**
- *
- * @return
- */
- public E last() {
- if (list.isEmpty()) return null;
- return list.getLast();
- }
-
- /**
- *
- * @return
- */
- public boolean isEmpty() {
- return list.isEmpty();
- }
-
- /**
- *
- * @return
- */
- public int size() {
- return list.size();
- }
-
- /**
- *
- */
- public E removeLast() {
- if (list.isEmpty()) return null;
- return list.removeLast();
- }
-
-}
diff --git a/src/main/java/org/tron/common/storage/Key.java b/src/main/java/org/tron/common/storage/Key.java
index 3859b2fdeaf..fe2f2343dd4 100644
--- a/src/main/java/org/tron/common/storage/Key.java
+++ b/src/main/java/org/tron/common/storage/Key.java
@@ -4,10 +4,6 @@
import java.util.Arrays;
-/**
- * @author Guo Yongang
- * @since 27.04.2018
- */
public class Key {
private static int MAX_KEY_LENGTH = 32;
diff --git a/src/main/java/org/tron/common/storage/Type.java b/src/main/java/org/tron/common/storage/Type.java
index ab76627dd24..af745b25767 100644
--- a/src/main/java/org/tron/common/storage/Type.java
+++ b/src/main/java/org/tron/common/storage/Type.java
@@ -1,9 +1,5 @@
package org.tron.common.storage;
-/**
- * @author Guo Yonggang
- * @since 27.04.2018
- */
public class Type {
/**
* Default Mode : VALUE_TYPE_NORMAL
diff --git a/src/main/java/org/tron/common/storage/Value.java b/src/main/java/org/tron/common/storage/Value.java
index f6112f102ee..7e029ea1c72 100644
--- a/src/main/java/org/tron/common/storage/Value.java
+++ b/src/main/java/org/tron/common/storage/Value.java
@@ -8,16 +8,11 @@
import org.tron.core.capsule.BytesCapsule;
import org.tron.core.capsule.CodeCapsule;
import org.tron.core.capsule.ContractCapsule;
-import org.tron.core.capsule.StorageCapsule;
import org.tron.core.capsule.TransactionCapsule;
import org.tron.core.capsule.VotesCapsule;
import org.tron.core.capsule.WitnessCapsule;
import org.tron.core.exception.BadItemException;
-/**
- * @author Guo Yonggang
- * @since 27.04.2018
- */
public class Value {
private Type type;
@@ -179,13 +174,6 @@ public ContractCapsule getContract() {
return new ContractCapsule(any);
}
- /**
- * @return
- */
- public StorageCapsule getStorage() {
- if (ArrayUtils.isEmpty(any)) return null;
- return new StorageCapsule(any);
- }
public AssetIssueCapsule getAssetIssue() {
if (ArrayUtils.isEmpty(any)) return null;
diff --git a/src/main/java/org/tron/common/utils/BIUtil.java b/src/main/java/org/tron/common/utils/BIUtil.java
index 886ac519993..6b72a169f74 100644
--- a/src/main/java/org/tron/common/utils/BIUtil.java
+++ b/src/main/java/org/tron/common/utils/BIUtil.java
@@ -98,25 +98,10 @@ public static boolean isPositive(BigInteger value){
return value.signum() > 0;
}
- public static boolean isCovers(BigInteger covers, BigInteger value){
- return !isNotCovers(covers, value);
- }
-
public static boolean isNotCovers(BigInteger covers, BigInteger value){
return covers.compareTo(value) < 0;
}
- public static boolean exitLong(BigInteger value){
-
- return (value.compareTo(new BigInteger(Long.MAX_VALUE + ""))) > -1;
- }
-
- public static boolean isIn20PercentRange(BigInteger first, BigInteger second) {
- BigInteger five = BigInteger.valueOf(5);
- BigInteger limit = first.add(first.divide(five));
- return !isMoreThan(second, limit);
- }
-
public static BigInteger max(BigInteger first, BigInteger second) {
return first.compareTo(second) < 0 ? second : first;
}
diff --git a/src/main/java/org/tron/common/utils/ByteUtil.java b/src/main/java/org/tron/common/utils/ByteUtil.java
index f8ec18d1b5f..d50cd9cceec 100644
--- a/src/main/java/org/tron/common/utils/ByteUtil.java
+++ b/src/main/java/org/tron/common/utils/ByteUtil.java
@@ -214,18 +214,6 @@ public static byte[] intToBytes(int val) {
return ByteBuffer.allocate(4).putInt(val).array();
}
- public static byte[] bigIntegerToBytesSigned(BigInteger b, int numBytes) {
- if (b == null)
- return null;
- byte[] bytes = new byte[numBytes];
- Arrays.fill(bytes, b.signum() < 0 ? (byte) 0xFF : 0x00);
- byte[] biBytes = b.toByteArray();
- int start = (biBytes.length == numBytes + 1) ? 1 : 0;
- int length = Math.min(biBytes.length, numBytes);
- System.arraycopy(biBytes, start, bytes, numBytes - length, length);
- return bytes;
- }
-
/**
* Cast hex encoded value from byte[] to BigInteger
* null is parsed like byte[0]
@@ -237,66 +225,6 @@ public static BigInteger bytesToBigInteger(byte[] bb) {
return (bb == null || bb.length == 0) ? BigInteger.ZERO : new BigInteger(1, bb);
}
- /**
- * Returns the amount of nibbles that match each other from 0 ...
- * amount will never be larger than smallest input
- *
- * @param a - first input
- * @param b - second input
- * @return Number of bytes that match
- */
- public static int matchingNibbleLength(byte[] a, byte[] b) {
- int i = 0;
- int length = a.length < b.length ? a.length : b.length;
- while (i < length) {
- if (a[i] != b[i])
- return i;
- i++;
- }
- return i;
- }
-
- /**
- * Converts a long value into a byte array.
- *
- * @param val - long value to convert
- * @return byte[]
of length 8, representing the long value
- */
- public static byte[] longToBytes(long val) {
- return ByteBuffer.allocate(Long.BYTES).putLong(val).array();
- }
-
- /**
- * Converts a long value into a byte array.
- *
- * @param val - long value to convert
- * @return decimal value with leading byte that are zeroes striped
- */
- public static byte[] longToBytesNoLeadZeroes(long val) {
-
- // todo: improve performance by while strip numbers until (long >> 8 == 0)
- if (val == 0) return EMPTY_BYTE_ARRAY;
-
- byte[] data = ByteBuffer.allocate(Long.BYTES).putLong(val).array();
-
- return stripLeadingZeroes(data);
- }
-
- /**
- * Calculate packet length
- *
- * @param msg byte[]
- * @return byte-array with 4 elements
- */
- public static byte[] calcPacketLength(byte[] msg) {
- int msgLen = msg.length;
- return new byte[]{
- (byte) ((msgLen >> 24) & 0xFF),
- (byte) ((msgLen >> 16) & 0xFF),
- (byte) ((msgLen >> 8) & 0xFF),
- (byte) ((msgLen) & 0xFF)};
- }
-
/**
* Cast hex encoded value from byte[] to long
* null is parsed like byte[0]
@@ -312,76 +240,6 @@ public static long byteArrayToLong(byte[] b) {
return new BigInteger(1, b).longValue();
}
- /**
- * Calculate the number of bytes need
- * to encode the number
- *
- * @param val - number
- * @return number of min bytes used to encode the number
- */
- public static int numBytes(String val) {
-
- BigInteger bInt = new BigInteger(val);
- int bytes = 0;
-
- while (!bInt.equals(BigInteger.ZERO)) {
- bInt = bInt.shiftRight(8);
- ++bytes;
- }
- if (bytes == 0) ++bytes;
- return bytes;
- }
-
- /**
- * @param arg - not more that 32 bits
- * @return - bytes of the value pad with complete to 32 zeroes
- */
- public static byte[] encodeValFor32Bits(Object arg) {
-
- byte[] data;
-
- // check if the string is numeric
- if (arg.toString().trim().matches("-?\\d+(\\.\\d+)?"))
- data = new BigInteger(arg.toString().trim()).toByteArray();
- // check if it's hex number
- else if (arg.toString().trim().matches("0[xX][0-9a-fA-F]+"))
- data = new BigInteger(arg.toString().trim().substring(2), 16).toByteArray();
- else
- data = arg.toString().trim().getBytes();
-
-
- if (data.length > 32)
- throw new RuntimeException("values can't be more than 32 byte");
-
- byte[] val = new byte[32];
-
- int j = 0;
- for (int i = data.length; i > 0; --i) {
- val[31 - j] = data[i - 1];
- ++j;
- }
- return val;
- }
-
- /**
- * encode the values and concatenate together
- *
- * @param args Object
- * @return byte[]
- */
- public static byte[] encodeDataList(Object... args) {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- for (Object arg : args) {
- byte[] val = encodeValFor32Bits(arg);
- try {
- baos.write(val);
- } catch (IOException e) {
- throw new Error("Happen something that should never happen ", e);
- }
- }
- return baos.toByteArray();
- }
-
public static int firstNonZeroByte(byte[] data) {
for (int i = 0; i < data.length; ++i) {
if (data[i] != 0) {
@@ -412,24 +270,6 @@ public static byte[] stripLeadingZeroes(byte[] data) {
}
}
- /**
- * increment byte array as a number until max is reached
- *
- * @param bytes byte[]
- * @return boolean
- */
- public static boolean increment(byte[] bytes) {
- final int startIndex = 0;
- int i;
- for (i = bytes.length - 1; i >= startIndex; i--) {
- bytes[i]++;
- if (bytes[i] != 0)
- break;
- }
- // we return false when all bytes are 0 again
- return (i >= startIndex || bytes[startIndex] != 0);
- }
-
/**
* Utility function to copy a byte array into a new byte array with given size.
* If the src length is smaller than the given size, the result will be left-padded
@@ -447,230 +287,6 @@ public static byte[] copyToArray(BigInteger value) {
return dest;
}
-
- public static ByteArrayWrapper wrap(byte[] data) {
- return new ByteArrayWrapper(data);
- }
-
- public static byte[] setBit(byte[] data, int pos, int val) {
-
- if ((data.length * 8) - 1 < pos)
- throw new Error("outside byte array limit, pos: " + pos);
-
- int posByte = data.length - 1 - (pos) / 8;
- int posBit = (pos) % 8;
- byte setter = (byte) (1 << (posBit));
- byte toBeSet = data[posByte];
- byte result;
- if (val == 1)
- result = (byte) (toBeSet | setter);
- else
- result = (byte) (toBeSet & ~setter);
-
- data[posByte] = result;
- return data;
- }
-
- public static int getBit(byte[] data, int pos) {
-
- if ((data.length * 8) - 1 < pos)
- throw new Error("outside byte array limit, pos: " + pos);
-
- int posByte = data.length - 1 - pos / 8;
- int posBit = pos % 8;
- byte dataByte = data[posByte];
- return Math.min(1, ((dataByte & 0xff) & (1 << (posBit))));
- }
-
- public static byte[] and(byte[] b1, byte[] b2) {
- if (b1.length != b2.length) throw new RuntimeException("Array sizes differ");
- byte[] ret = new byte[b1.length];
- for (int i = 0; i < ret.length; i++) {
- ret[i] = (byte) (b1[i] & b2[i]);
- }
- return ret;
- }
-
- public static byte[] or(byte[] b1, byte[] b2) {
- if (b1.length != b2.length) throw new RuntimeException("Array sizes differ");
- byte[] ret = new byte[b1.length];
- for (int i = 0; i < ret.length; i++) {
- ret[i] = (byte) (b1[i] | b2[i]);
- }
- return ret;
- }
-
- public static byte[] xor(byte[] b1, byte[] b2) {
- if (b1.length != b2.length) throw new RuntimeException("Array sizes differ");
- byte[] ret = new byte[b1.length];
- for (int i = 0; i < ret.length; i++) {
- ret[i] = (byte) (b1[i] ^ b2[i]);
- }
- return ret;
- }
-
- /**
- * XORs byte arrays of different lengths by aligning length of the shortest via adding zeros at beginning
- */
- public static byte[] xorAlignRight(byte[] b1, byte[] b2) {
- if (b1.length > b2.length) {
- byte[] b2_ = new byte[b1.length];
- System.arraycopy(b2, 0, b2_, b1.length - b2.length, b2.length);
- b2 = b2_;
- } else if (b2.length > b1.length) {
- byte[] b1_ = new byte[b2.length];
- System.arraycopy(b1, 0, b1_, b2.length - b1.length, b1.length);
- b1 = b1_;
- }
-
- return xor(b1, b2);
- }
-
- public static Set difference(Set setA, Set setB){
-
- Set result = new HashSet<>();
-
- for (byte[] elementA : setA){
- boolean found = false;
- for (byte[] elementB : setB){
-
- if (Arrays.equals(elementA, elementB)){
- found = true;
- break;
- }
- }
- if (!found) result.add(elementA);
- }
-
- return result;
- }
-
- public static int length(byte[]... bytes) {
- int result = 0;
- for (byte[] array : bytes) {
- result += (array == null) ? 0 : array.length;
- }
- return result;
- }
-
- public static byte[] intsToBytes(int[] arr, boolean bigEndian) {
- byte[] ret = new byte[arr.length * 4];
- intsToBytes(arr, ret, bigEndian);
- return ret;
- }
-
- public static int[] bytesToInts(byte[] arr, boolean bigEndian) {
- int[] ret = new int[arr.length / 4];
- bytesToInts(arr, ret, bigEndian);
- return ret;
- }
-
- public static void bytesToInts(byte[] b, int[] arr, boolean bigEndian) {
- if (!bigEndian) {
- int off = 0;
- for (int i = 0; i < arr.length; i++) {
- int ii = b[off++] & 0x000000FF;
- ii |= (b[off++] << 8) & 0x0000FF00;
- ii |= (b[off++] << 16) & 0x00FF0000;
- ii |= (b[off++] << 24);
- arr[i] = ii;
- }
- } else {
- int off = 0;
- for (int i = 0; i < arr.length; i++) {
- int ii = b[off++] << 24;
- ii |= (b[off++] << 16) & 0x00FF0000;
- ii |= (b[off++] << 8) & 0x0000FF00;
- ii |= b[off++] & 0x000000FF;
- arr[i] = ii;
- }
- }
- }
-
- public static void intsToBytes(int[] arr, byte[] b, boolean bigEndian) {
- if (!bigEndian) {
- int off = 0;
- for (int i = 0; i < arr.length; i++) {
- int ii = arr[i];
- b[off++] = (byte) (ii & 0xFF);
- b[off++] = (byte) ((ii >> 8) & 0xFF);
- b[off++] = (byte) ((ii >> 16) & 0xFF);
- b[off++] = (byte) ((ii >> 24) & 0xFF);
- }
- } else {
- int off = 0;
- for (int i = 0; i < arr.length; i++) {
- int ii = arr[i];
- b[off++] = (byte) ((ii >> 24) & 0xFF);
- b[off++] = (byte) ((ii >> 16) & 0xFF);
- b[off++] = (byte) ((ii >> 8) & 0xFF);
- b[off++] = (byte) (ii & 0xFF);
- }
- }
- }
-
- public static short bigEndianToShort(byte[] bs) {
- return bigEndianToShort(bs, 0);
- }
-
- public static short bigEndianToShort(byte[] bs, int off) {
- int n = bs[off] << 8;
- ++off;
- n |= bs[off] & 0xFF;
- return (short) n;
- }
-
- public static byte[] shortToBytes(short n) {
- return ByteBuffer.allocate(2).putShort(n).array();
- }
-
- /**
- * Converts string hex representation to data bytes
- * Accepts following hex:
- * - with or without 0x prefix
- * - with no leading 0, like 0xabc -> 0x0abc
- * @param data String like '0xa5e..' or just 'a5e..'
- * @return decoded bytes array
- */
- public static byte[] hexStringToBytes(String data) {
- if (data == null) return EMPTY_BYTE_ARRAY;
- if (data.startsWith("0x")) data = data.substring(2);
- if (data.length() % 2 == 1) data = "0" + data;
- return Hex.decode(data);
- }
-
- /**
- * Converts string representation of host/ip to 4-bytes byte[] IPv4
- */
- public static byte[] hostToBytes(String ip) {
- byte[] bytesIp;
- try {
- bytesIp = InetAddress.getByName(ip).getAddress();
- } catch (UnknownHostException e) {
- bytesIp = new byte[4]; // fall back to invalid 0.0.0.0 address
- }
-
- return bytesIp;
- }
-
- /**
- * Converts 4 bytes IPv4 IP to String representation
- */
- public static String bytesToIp(byte[] bytesIp) {
-
- StringBuilder sb = new StringBuilder();
- sb.append(bytesIp[0] & 0xFF);
- sb.append(".");
- sb.append(bytesIp[1] & 0xFF);
- sb.append(".");
- sb.append(bytesIp[2] & 0xFF);
- sb.append(".");
- sb.append(bytesIp[3] & 0xFF);
-
- String ip = sb.toString();
- return ip;
- }
-
/**
* Returns a number of zero bits preceding the highest-order ("leftmost") one-bit
* interpreting input array as a big-endian integer value
diff --git a/src/main/java/org/tron/common/utils/CollectionUtils.java b/src/main/java/org/tron/common/utils/CollectionUtils.java
index 6191e637bb7..cae99905f0f 100644
--- a/src/main/java/org/tron/common/utils/CollectionUtils.java
+++ b/src/main/java/org/tron/common/utils/CollectionUtils.java
@@ -1,6 +1,11 @@
package org.tron.common.utils;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -36,6 +41,31 @@ public static List truncate(List items, int limit) {
return truncated;
}
+ public static List truncateRandom(List items, int limit, int confirm) {
+ if (limit > items.size()) {
+ return new ArrayList<>(items);
+ }
+ List truncated = new ArrayList<>(limit);
+ if (confirm >= limit) {
+ for (T item : items) {
+ truncated.add(item);
+ if (truncated.size() == limit) {
+ break;
+ }
+ }
+ } else {
+ if (confirm > 0) {
+ truncated.addAll(items.subList(0, confirm));
+ }
+ List endList = items.subList(confirm, items.size());
+ Collections.shuffle(endList);
+ for (int i = 0; i < limit - confirm; i++) {
+ truncated.add(endList.get(i));
+ }
+ }
+ return truncated;
+ }
+
public static List selectList(Collection items, Predicate predicate) {
List selected = new ArrayList<>();
for(T item : items) {
diff --git a/src/main/java/org/tron/common/utils/ForkController.java b/src/main/java/org/tron/common/utils/ForkController.java
new file mode 100644
index 00000000000..333b181c507
--- /dev/null
+++ b/src/main/java/org/tron/common/utils/ForkController.java
@@ -0,0 +1,90 @@
+package org.tron.common.utils;
+
+import com.google.protobuf.ByteString;
+import java.util.Arrays;
+import java.util.List;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.tron.core.capsule.BlockCapsule;
+import org.tron.core.capsule.TransactionCapsule;
+import org.tron.core.config.Parameter.ChainConstant;
+import org.tron.core.db.Manager;
+import org.tron.protos.Protocol.Transaction.Contract.ContractType;
+
+@Slf4j
+@Component
+public class ForkController {
+
+ public static final int DISCARD_SCOPE = ContractType.UpdateAssetContract.getNumber();
+
+ @Getter
+ private Manager manager;
+ private volatile int[] slots = new int[0];
+ private boolean forked;
+
+ public void init(Manager manager) {
+ this.manager = manager;
+ forked = manager.getDynamicPropertiesStore().getForked();
+ }
+
+ public synchronized boolean shouldBeForked() {
+ if (forked) {
+ logger.info("*****shouldBeForked:" + true);
+ return true;
+ }
+
+ for (int version : slots) {
+ if (version != ChainConstant.version) {
+ logger.info("*****shouldBeForked:" + false);
+ return false;
+ }
+ }
+
+ // todo add Maintenance or block number
+ forked = true;
+ manager.getDynamicPropertiesStore().forked();
+ logger.info("*****shouldBeForked:" + true);
+ return true;
+ }
+
+ public synchronized boolean forkOrNot(TransactionCapsule capsule) {
+ logger.info("*****forkOrNot:" + (shouldBeForked()
+ || capsule.getInstance().getRawData().getContractList().get(0).getType().getNumber()
+ <= DISCARD_SCOPE));
+ return shouldBeForked()
+ || capsule.getInstance().getRawData().getContractList().get(0).getType().getNumber()
+ <= DISCARD_SCOPE;
+ }
+
+ public synchronized void update(BlockCapsule blockCapsule) {
+ if (forked) {
+ return;
+ }
+
+ List witnesses = manager.getWitnessController().getActiveWitnesses();
+ if (witnesses.size() != slots.length) {
+ slots = new int[witnesses.size()];
+ }
+
+ ByteString witness = blockCapsule.getWitnessAddress();
+ int slot = witnesses.indexOf(witness);
+ if (slot < 0) {
+ return;
+ }
+ slots[slot] = blockCapsule.getInstance().getBlockHeader().getRawData().getVersion();
+
+ logger.info(
+ "*******update:" + Arrays.toString(slots)
+ + ",witness size:" + witnesses.size()
+ + "," + slots
+ + ",slot:" + slot
+ + ",version:" + blockCapsule.getInstance().getBlockHeader().getRawData().getVersion()
+ );
+ }
+
+ public void reset() {
+ Arrays.fill(slots, 0);
+ }
+
+}
diff --git a/src/main/java/org/tron/common/utils/Utils.java b/src/main/java/org/tron/common/utils/Utils.java
index 587f5666246..b273b48fe23 100755
--- a/src/main/java/org/tron/common/utils/Utils.java
+++ b/src/main/java/org/tron/common/utils/Utils.java
@@ -40,7 +40,7 @@ static byte[] getBytes(char[] chars) {
return bb.array();
}
- public static String getIdShort(String Id) {
+ static String getIdShort(String Id) {
return Id == null ? "" : Id.substring(0, 8);
}
@@ -67,14 +67,14 @@ static String sizeToStr(long size) {
return String.format("%dGb", size / (1L << 30));
}
- public static String align(String s, char fillChar, int targetLen, boolean alignRight) {
+ static String align(String s, char fillChar, int targetLen, boolean alignRight) {
if (targetLen <= s.length()) return s;
String alignString = repeat("" + fillChar, targetLen - s.length());
return alignRight ? alignString + s : s + alignString;
}
- public static String repeat(String s, int n) {
+ static String repeat(String s, int n) {
if (s.length() == 1) {
byte[] bb = new byte[n];
Arrays.fill(bb, s.getBytes()[0]);
diff --git a/src/main/java/org/tron/core/Constant.java b/src/main/java/org/tron/core/Constant.java
index 94659c1a9fc..7020256d3bc 100644
--- a/src/main/java/org/tron/core/Constant.java
+++ b/src/main/java/org/tron/core/Constant.java
@@ -48,7 +48,13 @@ public class Constant {
// config for smart contract
public static final long MEM_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT = 32 * 1024 * 1024L; // 32MB
- public static final long CPU_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT = 100000; // 100 ms = 100000 us
+ public static final long MAX_CPU_TIME_OF_ONE_TX_WHEN_VERIFY_BLOCK = 500000; // 500 ms = 500000 us
+ public static final long MAX_CPU_TIME_OF_ONE_TX = 100000; // 100 ms = 100000 us
public static final long STORAGE_LIMIT_IN_ONE_TX_OF_SMART_CONTRACT = 32 * 1024 * 1024L; // 32MB
- public static final long CPU_IN_US_PER_TRX = 1000000 / 30; // 1 us <-> 30 SUN <-> 30 * 10^-6 TRX
+ public static final long SUN_PER_ENERGY = 100; // 1 us = 100 DROP = 100 * 10^-6 TRX
+ public static final long MAX_ENERGY_IN_TX = 3000000; // ref: 1 us = 1 energy
+ public static final long MAX_CONSUME_USER_RESOURCE_PERCENT = 100L;
+ public static final long MIN_CONSUME_USER_RESOURCE_PERCENT = 0L;
+ public static final long ACCORD_RANGE_PERCENT = 0L;
+
}
diff --git a/src/main/java/org/tron/core/SpendableOutputs.java b/src/main/java/org/tron/core/SpendableOutputs.java
deleted file mode 100644
index a8c83194c6d..00000000000
--- a/src/main/java/org/tron/core/SpendableOutputs.java
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * java-tron is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * java-tron is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.tron.core;
-
-import java.util.HashMap;
-
-public class SpendableOutputs {
- private long amount;
- private HashMap unspentOutputs = null;
-
- public HashMap getUnspentOutputs() {
- return unspentOutputs;
- }
-
- public void setUnspentOutputs(HashMap unspentOutputs) {
- this.unspentOutputs = unspentOutputs;
- }
-
- public long getAmount() {
- return amount;
- }
-
- public void setAmount(long amount) {
- this.amount = amount;
- }
-}
diff --git a/src/main/java/org/tron/core/Wallet.java b/src/main/java/org/tron/core/Wallet.java
index 56db2c0c244..3bb2ecd3a3c 100755
--- a/src/main/java/org/tron/core/Wallet.java
+++ b/src/main/java/org/tron/core/Wallet.java
@@ -18,6 +18,7 @@
package org.tron.core;
+import com.google.common.primitives.Longs;
import com.google.protobuf.ByteString;
import java.util.Arrays;
import java.util.HashMap;
@@ -37,11 +38,14 @@
import org.tron.api.GrpcAPI.Address;
import org.tron.api.GrpcAPI.AssetIssueList;
import org.tron.api.GrpcAPI.BlockList;
+import org.tron.api.GrpcAPI.ExchangeList;
import org.tron.api.GrpcAPI.Node;
import org.tron.api.GrpcAPI.NodeList;
import org.tron.api.GrpcAPI.NumberMessage;
import org.tron.api.GrpcAPI.ProposalList;
+import org.tron.api.GrpcAPI.Return;
import org.tron.api.GrpcAPI.Return.response_code;
+import org.tron.api.GrpcAPI.TransactionExtention.Builder;
import org.tron.api.GrpcAPI.WitnessList;
import org.tron.common.crypto.ECKey;
import org.tron.common.crypto.Hash;
@@ -62,6 +66,7 @@
import org.tron.core.capsule.AssetIssueCapsule;
import org.tron.core.capsule.BlockCapsule;
import org.tron.core.capsule.ContractCapsule;
+import org.tron.core.capsule.ExchangeCapsule;
import org.tron.core.capsule.ProposalCapsule;
import org.tron.core.capsule.TransactionCapsule;
import org.tron.core.capsule.TransactionResultCapsule;
@@ -71,8 +76,8 @@
import org.tron.core.db.AccountStore;
import org.tron.core.db.BandwidthProcessor;
import org.tron.core.db.ContractStore;
-import org.tron.core.db.CpuProcessor;
import org.tron.core.db.DynamicPropertiesStore;
+import org.tron.core.db.EnergyProcessor;
import org.tron.core.db.Manager;
import org.tron.core.db.PendingManager;
import org.tron.core.exception.AccountResourceInsufficientException;
@@ -94,6 +99,7 @@
import org.tron.protos.Protocol;
import org.tron.protos.Protocol.Account;
import org.tron.protos.Protocol.Block;
+import org.tron.protos.Protocol.Exchange;
import org.tron.protos.Protocol.Proposal;
import org.tron.protos.Protocol.SmartContract;
import org.tron.protos.Protocol.SmartContract.ABI;
@@ -223,6 +229,25 @@ public static byte[] generateContractAddress(Transaction trx) {
}
+ public static byte[] generateContractAddress(byte[] ownerAddress, byte[] txRawDataHash) {
+
+ byte[] combined = new byte[txRawDataHash.length + ownerAddress.length];
+ System.arraycopy(txRawDataHash, 0, combined, 0, txRawDataHash.length);
+ System.arraycopy(ownerAddress, 0, combined, txRawDataHash.length, ownerAddress.length);
+
+ return Hash.sha3omit12(combined);
+
+ }
+
+ public static byte[] generateContractAddress(byte[] transactionRootId, long nonce) {
+ byte[] nonceBytes = Longs.toByteArray(nonce);
+ byte[] combined = new byte[transactionRootId.length + nonceBytes.length];
+ System.arraycopy(transactionRootId, 0, combined, 0, transactionRootId.length);
+ System.arraycopy(nonceBytes, 0, combined, transactionRootId.length, nonceBytes.length);
+
+ return Hash.sha3omit12(combined);
+ }
+
public static byte[] decodeFromBase58Check(String addressBase58) {
if (StringUtils.isEmpty(addressBase58)) {
logger.warn("Warning: Address is empty !!");
@@ -249,6 +274,10 @@ public Account getAccount(Account account) {
}
BandwidthProcessor processor = new BandwidthProcessor(dbManager);
processor.updateUsage(accountCapsule);
+
+ EnergyProcessor energyProcessor = new EnergyProcessor(dbManager);
+ energyProcessor.updateUsage(accountCapsule);
+
return accountCapsule.getInstance();
}
@@ -265,6 +294,10 @@ public Account getAccountById(Account account) {
}
BandwidthProcessor processor = new BandwidthProcessor(dbManager);
processor.updateUsage(accountCapsule);
+
+ EnergyProcessor energyProcessor = new EnergyProcessor(dbManager);
+ energyProcessor.updateUsage(accountCapsule);
+
return accountCapsule.getInstance();
}
@@ -289,10 +322,24 @@ public Transaction createTransaction(TransferContract contract) {
public TransactionCapsule createTransactionCapsule(com.google.protobuf.Message message,
ContractType contractType) throws ContractValidateException {
TransactionCapsule trx = new TransactionCapsule(message, contractType);
- List actList = ActuatorFactory.createActuator(trx, dbManager);
- for (Actuator act : actList) {
- act.validate();
+ if (contractType != ContractType.CreateSmartContract
+ && contractType != ContractType.TriggerSmartContract) {
+ List actList = ActuatorFactory.createActuator(trx, dbManager);
+ for (Actuator act : actList) {
+ act.validate();
+ }
}
+
+ if (contractType == ContractType.CreateSmartContract) {
+
+ CreateSmartContract contract = ContractCapsule
+ .getSmartContractFromTransaction(trx.getInstance());
+ long percent = contract.getNewContract().getConsumeUserResourcePercent();
+ if (percent < 0 || percent > 100) {
+ throw new ContractValidateException("percent must be >= 0 and <= 100");
+ }
+ }
+
try {
BlockCapsule headBlock = null;
List blockList = dbManager.getBlockStore().getBlockByLatestNum(1);
@@ -341,8 +388,11 @@ public GrpcAPI.Return broadcastTransaction(Transaction signaturedTransaction) {
dbManager.getTransactionIdCache().put(trx.getTransactionId(), true);
}
- dbManager.pushTransactions(trx);
- p2pNode.broadcast(message);
+ if (dbManager.getForkController().forkOrNot(trx)) {
+ dbManager.pushTransaction(trx);
+ p2pNode.broadcast(message);
+ }
+
return builder.setResult(true).setCode(response_code.SUCCESS).build();
} catch (ValidateSignatureException e) {
logger.info(e.getMessage());
@@ -443,6 +493,14 @@ public ProposalList getProposalList() {
return builder.build();
}
+ public ExchangeList getExchangeList() {
+ ExchangeList.Builder builder = ExchangeList.newBuilder();
+ List exchangeCapsuleList = dbManager.getExchangeStore().getAllExchanges();
+ exchangeCapsuleList
+ .forEach(exchangeCapsule -> builder.addExchanges(exchangeCapsule.getInstance()));
+ return builder.build();
+ }
+
public Protocol.ChainParameters getChainParameters() {
Protocol.ChainParameters.Builder builder = Protocol.ChainParameters.newBuilder();
DynamicPropertiesStore dynamicPropertiesStore = dbManager.getDynamicPropertiesStore();
@@ -496,8 +554,15 @@ public Protocol.ChainParameters getChainParameters() {
dynamicPropertiesStore.getCreateNewAccountBandwidthRate())
.build());
+ builder.addChainParameter(builder1
+ .setKey(ChainParameters.ALLOW_CREATION_OF_CONTRACTS.name())
+ .setValue(
+ dynamicPropertiesStore.getAllowCreationOfContracts())
+ .build());
+
return builder.build();
}
+
public AssetIssueList getAssetIssueList() {
AssetIssueList.Builder builder = AssetIssueList.newBuilder();
dbManager.getAssetIssueStore().getAllAssetIssues()
@@ -582,16 +647,17 @@ public AccountResourceMessage getAccountResource(ByteString accountAddress) {
BandwidthProcessor processor = new BandwidthProcessor(dbManager);
processor.updateUsage(accountCapsule);
- CpuProcessor cpuProcessor = new CpuProcessor(dbManager);
- cpuProcessor.updateUsage(accountCapsule);
+ EnergyProcessor energyProcessor = new EnergyProcessor(dbManager);
+ energyProcessor.updateUsage(accountCapsule);
long netLimit = processor.calculateGlobalNetLimit(accountCapsule.getFrozenBalance());
long freeNetLimit = dbManager.getDynamicPropertiesStore().getFreeNetLimit();
long totalNetLimit = dbManager.getDynamicPropertiesStore().getTotalNetLimit();
long totalNetWeight = dbManager.getDynamicPropertiesStore().getTotalNetWeight();
- long cpuLimit = cpuProcessor.calculateGlobalCpuLimit(accountCapsule.getCpuFrozenBalance());
- long totalCpuLimit = dbManager.getDynamicPropertiesStore().getTotalCpuLimit();
- long totalCpuWeight = dbManager.getDynamicPropertiesStore().getTotalCpuWeight();
+ long energyLimit = energyProcessor
+ .calculateGlobalEnergyLimit(accountCapsule.getEnergyFrozenBalance());
+ long totalEnergyLimit = dbManager.getDynamicPropertiesStore().getTotalEnergyLimit();
+ long totalEnergyWeight = dbManager.getDynamicPropertiesStore().getTotalEnergyWeight();
long storageLimit = accountCapsule.getAccountResource().getStorageLimit();
long storageUsage = accountCapsule.getAccountResource().getStorageUsage();
@@ -608,10 +674,10 @@ public AccountResourceMessage getAccountResource(ByteString accountAddress) {
.setNetLimit(netLimit)
.setTotalNetLimit(totalNetLimit)
.setTotalNetWeight(totalNetWeight)
- .setCpuLimit(cpuLimit)
- .setCpuUsed(accountCapsule.getAccountResource().getCpuUsage())
- .setTotalCpuLimit(totalCpuLimit)
- .setTotalCpuWeight(totalCpuWeight)
+ .setEnergyLimit(energyLimit)
+ .setEnergyUsed(accountCapsule.getAccountResource().getEnergyUsage())
+ .setTotalEnergyLimit(totalEnergyLimit)
+ .setTotalEnergyWeight(totalEnergyWeight)
.setStorageLimit(storageLimit)
.setStorageUsed(storageUsage)
.putAllAssetNetUsed(accountCapsule.getAllFreeAssetNetUsage())
@@ -701,6 +767,22 @@ public Proposal getProposalById(ByteString proposalId) {
return null;
}
+ public Exchange getExchangeById(ByteString exchangeId) {
+ if (Objects.isNull(exchangeId)) {
+ return null;
+ }
+ ExchangeCapsule exchangeCapsule = null;
+ try {
+ exchangeCapsule = dbManager.getExchangeStore()
+ .get(exchangeId.toByteArray());
+ } catch (StoreException e) {
+ }
+ if (exchangeCapsule != null) {
+ return exchangeCapsule.getInstance();
+ }
+ return null;
+ }
+
public NodeList listNodes() {
List handlerList = nodeManager.dumpActiveNodes();
@@ -733,18 +815,21 @@ public Transaction deployContract(CreateSmartContract createSmartContract,
}
public Transaction triggerContract(TriggerSmartContract triggerSmartContract,
- TransactionCapsule trxCap) {
+ TransactionCapsule trxCap, Builder builder,
+ Return.Builder retBuilder) {
ContractStore contractStore = dbManager.getContractStore();
byte[] contractAddress = triggerSmartContract.getContractAddress().toByteArray();
SmartContract.ABI abi = contractStore.getABI(contractAddress);
if (abi == null) {
+ // FIXME
return null;
}
try {
byte[] selector = getSelector(triggerSmartContract.getData().toByteArray());
if (selector == null) {
+ // FIXME
return null;
}
@@ -752,19 +837,36 @@ public Transaction triggerContract(TriggerSmartContract triggerSmartContract,
return trxCap.getInstance();
} else {
DepositImpl deposit = DepositImpl.createRoot(dbManager);
- Runtime runtime = new Runtime(trxCap.getInstance(), deposit,
+
+ Block headBlock;
+ List blockCapsuleList = dbManager.getBlockStore().getBlockByLatestNum(1);
+ if (CollectionUtils.isEmpty(blockCapsuleList)) {
+ throw new HeaderNotFound("latest block not found");
+ } else {
+ headBlock = blockCapsuleList.get(0).getInstance();
+ }
+
+ Runtime runtime = new Runtime(trxCap.getInstance(), headBlock, deposit,
new ProgramInvokeFactoryImpl());
runtime.init();
runtime.execute();
runtime.go();
+ runtime.finalization();
+ // TODO exception
if (runtime.getResult().getException() != null) {
+// runtime.getResult().getException().printStackTrace();
throw new RuntimeException("Runtime exe failed!");
}
ProgramResult result = runtime.getResult();
TransactionResultCapsule ret = new TransactionResultCapsule();
- ret.setConstantResult(result.getHReturn());
+
+ builder.addConstantResult(ByteString.copyFrom(result.getHReturn()));
ret.setStatus(0, code.SUCESS);
+ if (StringUtils.isNoneEmpty(runtime.getRuntimeError())) {
+ ret.setStatus(0, code.FAILED);
+ retBuilder.setMessage(ByteString.copyFromUtf8(runtime.getRuntimeError())).build();
+ }
trxCap.setResult(ret);
return trxCap.getInstance();
}
@@ -785,7 +887,10 @@ public SmartContract getContract(GrpcAPI.BytesMessage bytesMessage) {
ContractCapsule contractCapsule = dbManager.getContractStore()
.get(bytesMessage.getValue().toByteArray());
- return contractCapsule.getInstance();
+ if (Objects.nonNull(contractCapsule)) {
+ return contractCapsule.getInstance();
+ }
+ return null;
}
private static byte[] getSelector(byte[] data) {
@@ -800,6 +905,10 @@ private static byte[] getSelector(byte[] data) {
}
private static boolean isConstant(SmartContract.ABI abi, byte[] selector) throws Exception {
+
+ if (abi.getEntrysList().size() == 0) {
+ return false;
+ }
if (selector == null || selector.length != 4) {
throw new Exception("Selector's length or selector itself is invalid");
}
@@ -812,11 +921,11 @@ private static boolean isConstant(SmartContract.ABI abi, byte[] selector) throws
int inputCount = entry.getInputsCount();
StringBuffer sb = new StringBuffer();
- sb.append(entry.getName().toStringUtf8());
+ sb.append(entry.getName());
sb.append("(");
for (int k = 0; k < inputCount; k++) {
ABI.Entry.Param param = entry.getInputs(k);
- sb.append(param.getType().toStringUtf8());
+ sb.append(param.getType());
if (k + 1 < inputCount) {
sb.append(",");
}
diff --git a/src/main/java/org/tron/core/actuator/ActuatorFactory.java b/src/main/java/org/tron/core/actuator/ActuatorFactory.java
index b0280e87f78..f545e8efd86 100644
--- a/src/main/java/org/tron/core/actuator/ActuatorFactory.java
+++ b/src/main/java/org/tron/core/actuator/ActuatorFactory.java
@@ -59,8 +59,6 @@ private static Actuator getActuatorByContract(Contract contract, Manager manager
return new AssetIssueActuator(contract.getParameter(), manager);
case UnfreezeAssetContract:
return new UnfreezeAssetActuator(contract.getParameter(), manager);
- case CreateSmartContract:
- break;
case WitnessUpdateContract:
return new WitnessUpdateActuator(contract.getParameter(), manager);
case ParticipateAssetIssueContract:
@@ -81,11 +79,24 @@ private static Actuator getActuatorByContract(Contract contract, Manager manager
return new ProposalDeleteActuator(contract.getParameter(), manager);
case SetAccountIdContract:
return new SetAccountIdActuator(contract.getParameter(), manager);
- case BuyStorageContract:
- return new BuyStorageActuator(contract.getParameter(), manager);
- case SellStorageContract:
- return new SellStorageActuator(contract.getParameter(), manager);
+// case BuyStorageContract:
+// return new BuyStorageActuator(contract.getParameter(), manager);
+// case BuyStorageBytesContract:
+// return new BuyStorageBytesActuator(contract.getParameter(), manager);
+// case SellStorageContract:
+// return new SellStorageActuator(contract.getParameter(), manager);
+ case UpdateSettingContract:
+ return new UpdateSettingContractActuator(contract.getParameter(), manager);
+ case ExchangeCreateContract:
+ return new ExchangeCreateActuator(contract.getParameter(), manager);
+ case ExchangeInjectContract:
+ return new ExchangeInjectActuator(contract.getParameter(), manager);
+ case ExchangeWithdrawContract:
+ return new ExchangeWithdrawActuator(contract.getParameter(), manager);
+ case ExchangeTransactionContract:
+ return new ExchangeTransactionActuator(contract.getParameter(), manager);
default:
+ break;
}
return null;
diff --git a/src/main/java/org/tron/core/actuator/BuyStorageActuator.java b/src/main/java/org/tron/core/actuator/BuyStorageActuator.java
index c8815bc11c2..9a14364b20c 100755
--- a/src/main/java/org/tron/core/actuator/BuyStorageActuator.java
+++ b/src/main/java/org/tron/core/actuator/BuyStorageActuator.java
@@ -94,6 +94,11 @@ public boolean validate() throws ContractValidateException {
if (quant > accountCapsule.getBalance()) {
throw new ContractValidateException("quantity must be less than accountBalance");
}
+ long storage_bytes = storageMarket.tryBuyStorage(quant);
+ if (storage_bytes < 1L) {
+ throw new ContractValidateException(
+ "storage_bytes must be larger than 1,current storage_bytes[" + storage_bytes + "]");
+ }
// long storageBytes = storageMarket.exchange(quant, true);
// if (storageBytes > dbManager.getDynamicPropertiesStore().getTotalStorageReserved()) {
diff --git a/src/main/java/org/tron/core/actuator/BuyStorageBytesActuator.java b/src/main/java/org/tron/core/actuator/BuyStorageBytesActuator.java
new file mode 100755
index 00000000000..ccff0b9dc62
--- /dev/null
+++ b/src/main/java/org/tron/core/actuator/BuyStorageBytesActuator.java
@@ -0,0 +1,123 @@
+package org.tron.core.actuator;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import lombok.extern.slf4j.Slf4j;
+import org.tron.common.utils.StringUtil;
+import org.tron.core.Wallet;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.capsule.TransactionResultCapsule;
+import org.tron.core.db.Manager;
+import org.tron.core.db.StorageMarket;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.protos.Contract.BuyStorageBytesContract;
+import org.tron.protos.Protocol.Transaction.Result.code;
+
+@Slf4j
+public class BuyStorageBytesActuator extends AbstractActuator {
+
+ private StorageMarket storageMarket;
+
+ BuyStorageBytesActuator(Any contract, Manager dbManager) {
+ super(contract, dbManager);
+ storageMarket = new StorageMarket(dbManager);
+ }
+
+ @Override
+ public boolean execute(TransactionResultCapsule ret) throws ContractExeException {
+ long fee = calcFee();
+ final BuyStorageBytesContract BuyStorageBytesContract;
+ try {
+ BuyStorageBytesContract = contract.unpack(BuyStorageBytesContract.class);
+ } catch (InvalidProtocolBufferException e) {
+ logger.debug(e.getMessage(), e);
+ ret.setStatus(fee, code.FAILED);
+ throw new ContractExeException(e.getMessage());
+ }
+
+ AccountCapsule accountCapsule = dbManager.getAccountStore()
+ .get(BuyStorageBytesContract.getOwnerAddress().toByteArray());
+ long bytes = BuyStorageBytesContract.getBytes();
+
+ storageMarket.buyStorageBytes(accountCapsule, bytes);
+
+ ret.setStatus(fee, code.SUCESS);
+
+ return true;
+ }
+
+
+ @Override
+ public boolean validate() throws ContractValidateException {
+ if (this.contract == null) {
+ throw new ContractValidateException("No contract!");
+ }
+ if (this.dbManager == null) {
+ throw new ContractValidateException("No dbManager!");
+ }
+ if (!contract.is(BuyStorageBytesContract.class)) {
+ throw new ContractValidateException(
+ "contract type error,expected type [BuyStorageBytesContract],real type[" + contract
+ .getClass() + "]");
+ }
+
+ final BuyStorageBytesContract BuyStorageBytesContract;
+ try {
+ BuyStorageBytesContract = this.contract.unpack(BuyStorageBytesContract.class);
+ } catch (InvalidProtocolBufferException e) {
+ logger.debug(e.getMessage(), e);
+ throw new ContractValidateException(e.getMessage());
+ }
+ byte[] ownerAddress = BuyStorageBytesContract.getOwnerAddress().toByteArray();
+ if (!Wallet.addressValid(ownerAddress)) {
+ throw new ContractValidateException("Invalid address");
+ }
+
+ AccountCapsule accountCapsule = dbManager.getAccountStore().get(ownerAddress);
+ if (accountCapsule == null) {
+ String readableOwnerAddress = StringUtil.createReadableString(ownerAddress);
+ throw new ContractValidateException(
+ "Account[" + readableOwnerAddress + "] not exists");
+ }
+
+ long bytes = BuyStorageBytesContract.getBytes();
+ if (bytes < 0) {
+ throw new ContractValidateException("bytes must be positive");
+ }
+
+ if (bytes < 1L) {
+ throw new ContractValidateException(
+ "bytes must be larger than 1, current storage_bytes[" + bytes + "]");
+ }
+
+ long quant = storageMarket.tryBuyStorageBytes(bytes);
+
+ if (quant < 1_000_000L) {
+ throw new ContractValidateException("quantity must be larger than 1TRX");
+ }
+
+ if (quant > accountCapsule.getBalance()) {
+ throw new ContractValidateException("quantity must be less than accountBalance");
+ }
+
+// long storageBytes = storageMarket.exchange(quant, true);
+// if (storageBytes > dbManager.getDynamicPropertiesStore().getTotalStorageReserved()) {
+// throw new ContractValidateException("storage is not enough");
+// }
+
+ return true;
+ }
+
+ @Override
+ public ByteString getOwnerAddress() throws InvalidProtocolBufferException {
+ return contract.unpack(BuyStorageBytesContract.class).getOwnerAddress();
+ }
+
+ @Override
+ public long calcFee() {
+ return 0;
+ }
+
+}
diff --git a/src/main/java/org/tron/core/actuator/CreateAccountActuator.java b/src/main/java/org/tron/core/actuator/CreateAccountActuator.java
index 48dbf0385a0..06958ac51b5 100755
--- a/src/main/java/org/tron/core/actuator/CreateAccountActuator.java
+++ b/src/main/java/org/tron/core/actuator/CreateAccountActuator.java
@@ -39,7 +39,7 @@ public boolean execute(TransactionResultCapsule ret)
logger.debug(e.getMessage(), e);
ret.setStatus(fee, code.FAILED);
throw new ContractExeException(e.getMessage());
- }catch (InvalidProtocolBufferException e) {
+ } catch (InvalidProtocolBufferException e) {
logger.debug(e.getMessage(), e);
ret.setStatus(fee, code.FAILED);
throw new ContractExeException(e.getMessage());
diff --git a/src/main/java/org/tron/core/actuator/ExchangeCreateActuator.java b/src/main/java/org/tron/core/actuator/ExchangeCreateActuator.java
new file mode 100755
index 00000000000..7f31961519c
--- /dev/null
+++ b/src/main/java/org/tron/core/actuator/ExchangeCreateActuator.java
@@ -0,0 +1,173 @@
+package org.tron.core.actuator;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import lombok.extern.slf4j.Slf4j;
+import org.tron.common.utils.StringUtil;
+import org.tron.core.Wallet;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.capsule.ExchangeCapsule;
+import org.tron.core.capsule.TransactionResultCapsule;
+import org.tron.core.config.Parameter.ChainParameters;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.protos.Contract.ExchangeCreateContract;
+import org.tron.protos.Protocol.Transaction.Result.code;
+
+@Slf4j
+public class ExchangeCreateActuator extends AbstractActuator {
+
+ ExchangeCreateActuator(final Any contract, final Manager dbManager) {
+ super(contract, dbManager);
+ }
+
+ @Override
+ public boolean execute(TransactionResultCapsule ret) throws ContractExeException {
+ long fee = calcFee();
+ try {
+ final ExchangeCreateContract exchangeCreateContract = this.contract
+ .unpack(ExchangeCreateContract.class);
+ AccountCapsule accountCapsule = dbManager.getAccountStore()
+ .get(exchangeCreateContract.getOwnerAddress().toByteArray());
+
+ byte[] firstTokenID = exchangeCreateContract.getFirstTokenId().toByteArray();
+ byte[] secondTokenID = exchangeCreateContract.getSecondTokenId().toByteArray();
+ long firstTokenBalance = exchangeCreateContract.getFirstTokenBalance();
+ long secondTokenBalance = exchangeCreateContract.getSecondTokenBalance();
+
+ long newBalance = accountCapsule.getBalance() - calcFee();
+
+ if (firstTokenID == "_".getBytes()) {
+ accountCapsule.setBalance(newBalance - firstTokenBalance);
+ } else {
+ accountCapsule.reduceAssetAmount(firstTokenID, firstTokenBalance);
+ }
+
+ if (secondTokenID == "_".getBytes()) {
+ accountCapsule.setBalance(newBalance - secondTokenBalance);
+ } else {
+ accountCapsule.reduceAssetAmount(secondTokenID, secondTokenBalance);
+ }
+
+ long id = dbManager.getDynamicPropertiesStore().getLatestExchangeNum() + 1;
+ long now = dbManager.getHeadBlockTimeStamp();
+ ExchangeCapsule exchangeCapsule =
+ new ExchangeCapsule(
+ exchangeCreateContract.getOwnerAddress(),
+ id,
+ now,
+ firstTokenID,
+ secondTokenID
+ );
+
+ exchangeCapsule.setBalance(firstTokenBalance, secondTokenBalance);
+
+ dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule);
+ dbManager.getExchangeStore().put(exchangeCapsule.createDbKey(), exchangeCapsule);
+ dbManager.getDynamicPropertiesStore().saveLatestExchangeNum(id);
+
+ ret.setStatus(fee, code.SUCESS);
+ } catch (InvalidProtocolBufferException e) {
+ logger.debug(e.getMessage(), e);
+ ret.setStatus(fee, code.FAILED);
+ throw new ContractExeException(e.getMessage());
+ }
+ return true;
+ }
+
+ @Override
+ public boolean validate() throws ContractValidateException {
+ if (this.contract == null) {
+ throw new ContractValidateException("No contract!");
+ }
+ if (this.dbManager == null) {
+ throw new ContractValidateException("No dbManager!");
+ }
+ if (!this.contract.is(ExchangeCreateContract.class)) {
+ throw new ContractValidateException(
+ "contract type error,expected type [ExchangeCreateContract],real type[" + contract
+ .getClass() + "]");
+ }
+ final ExchangeCreateContract contract;
+ try {
+ contract = this.contract.unpack(ExchangeCreateContract.class);
+ } catch (InvalidProtocolBufferException e) {
+ throw new ContractValidateException(e.getMessage());
+ }
+
+ byte[] ownerAddress = contract.getOwnerAddress().toByteArray();
+ String readableOwnerAddress = StringUtil.createReadableString(ownerAddress);
+
+ if (!Wallet.addressValid(ownerAddress)) {
+ throw new ContractValidateException("Invalid address");
+ }
+
+ if (!this.dbManager.getAccountStore().has(ownerAddress)) {
+ throw new ContractValidateException("account[" + readableOwnerAddress + "] not exists");
+ }
+
+ AccountCapsule accountCapsule = this.dbManager.getAccountStore().get(ownerAddress);
+
+ if (accountCapsule.getBalance() < calcFee()) {
+ throw new ContractValidateException("No enough balance for exchange create fee!");
+ }
+
+ byte[] firstTokenID = contract.getFirstTokenId().toByteArray();
+ byte[] secondTokenID = contract.getSecondTokenId().toByteArray();
+ long firstTokenBalance = contract.getFirstTokenBalance();
+ long secondTokenBalance = contract.getSecondTokenBalance();
+
+ if (firstTokenID == secondTokenID) {
+ throw new ContractValidateException("cannot exchange same tokens");
+ }
+
+ if (firstTokenBalance <= 0 || secondTokenBalance <= 0) {
+ throw new ContractValidateException("token balance must greater than zero");
+ }
+
+ long balanceLimit = dbManager.getDynamicPropertiesStore().getExchangeBalanceLimit();
+ if (firstTokenBalance > balanceLimit || secondTokenBalance > balanceLimit) {
+ throw new ContractValidateException("token balance must less than " + balanceLimit);
+ }
+
+ if (firstTokenID == "_".getBytes()) {
+ if (accountCapsule.getBalance() < (firstTokenBalance + calcFee())) {
+ throw new ContractValidateException("balance is not enough");
+ }
+ } else {
+ if (!accountCapsule.assetBalanceEnough(firstTokenID, firstTokenBalance)) {
+ throw new ContractValidateException("first token balance is not enough");
+ }
+ }
+
+ if (secondTokenID == "_".getBytes()) {
+ if (accountCapsule.getBalance() < (secondTokenBalance + calcFee())) {
+ throw new ContractValidateException("balance is not enough");
+ }
+ } else {
+ if (!accountCapsule.assetBalanceEnough(secondTokenID, secondTokenBalance)) {
+ throw new ContractValidateException("second token balance is not enough");
+ }
+ }
+
+ return true;
+ }
+
+
+ @Override
+ public ByteString getOwnerAddress() throws InvalidProtocolBufferException {
+ return contract.unpack(ExchangeCreateContract.class).getOwnerAddress();
+ }
+
+ @Override
+ public long calcFee() {
+ return dbManager.getDynamicPropertiesStore().getExchangeCreateFee();
+ }
+
+ private boolean validKey(long idx) {
+ return idx >= 0 && idx < ChainParameters.values().length;
+ }
+
+}
diff --git a/src/main/java/org/tron/core/actuator/ExchangeInjectActuator.java b/src/main/java/org/tron/core/actuator/ExchangeInjectActuator.java
new file mode 100755
index 00000000000..24b97b11e3b
--- /dev/null
+++ b/src/main/java/org/tron/core/actuator/ExchangeInjectActuator.java
@@ -0,0 +1,232 @@
+package org.tron.core.actuator;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import java.util.Arrays;
+import lombok.extern.slf4j.Slf4j;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.StringUtil;
+import org.tron.core.Wallet;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.capsule.ExchangeCapsule;
+import org.tron.core.capsule.TransactionResultCapsule;
+import org.tron.core.config.Parameter.ChainParameters;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.ItemNotFoundException;
+import org.tron.protos.Contract.ExchangeInjectContract;
+import org.tron.protos.Protocol.Transaction.Result.code;
+
+@Slf4j
+public class ExchangeInjectActuator extends AbstractActuator {
+
+ ExchangeInjectActuator(final Any contract, final Manager dbManager) {
+ super(contract, dbManager);
+ }
+
+ @Override
+ public boolean execute(TransactionResultCapsule ret) throws ContractExeException {
+ long fee = calcFee();
+ try {
+ final ExchangeInjectContract exchangeInjectContract = this.contract
+ .unpack(ExchangeInjectContract.class);
+ AccountCapsule accountCapsule = dbManager.getAccountStore()
+ .get(exchangeInjectContract.getOwnerAddress().toByteArray());
+
+ ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore().
+ get(ByteArray.fromLong(exchangeInjectContract.getExchangeId()));
+
+ byte[] firstTokenID = exchangeCapsule.getFirstTokenId();
+ byte[] secondTokenID = exchangeCapsule.getSecondTokenId();
+ long firstTokenBalance = exchangeCapsule.getFirstTokenBalance();
+ long secondTokenBalance = exchangeCapsule.getSecondTokenBalance();
+
+ byte[] tokenID = exchangeInjectContract.getTokenId().toByteArray();
+ long tokenQuant = exchangeInjectContract.getQuant();
+
+ byte[] anotherTokenID;
+ long anotherTokenQuant;
+
+ if (Arrays.equals(tokenID, firstTokenID)) {
+ anotherTokenID = secondTokenID;
+ anotherTokenQuant = Math
+ .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance);
+ exchangeCapsule.setBalance(firstTokenBalance + tokenQuant,
+ secondTokenBalance + anotherTokenQuant);
+ } else {
+ anotherTokenID = firstTokenID;
+ anotherTokenQuant = Math
+ .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance);
+ exchangeCapsule.setBalance(firstTokenBalance + anotherTokenQuant,
+ secondTokenBalance + tokenQuant);
+ }
+
+ long newBalance = accountCapsule.getBalance() - calcFee();
+
+ if (tokenID == "_".getBytes()) {
+ accountCapsule.setBalance(newBalance - tokenQuant);
+ } else {
+ accountCapsule.reduceAssetAmount(tokenID, tokenQuant);
+ }
+
+ if (anotherTokenID == "_".getBytes()) {
+ accountCapsule.setBalance(newBalance - anotherTokenQuant);
+ } else {
+ accountCapsule.reduceAssetAmount(anotherTokenID, anotherTokenQuant);
+ }
+
+ dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule);
+ dbManager.getExchangeStore().put(exchangeCapsule.createDbKey(), exchangeCapsule);
+
+ ret.setStatus(fee, code.SUCESS);
+ } catch (ItemNotFoundException e) {
+ logger.debug(e.getMessage(), e);
+ ret.setStatus(fee, code.FAILED);
+ throw new ContractExeException(e.getMessage());
+ } catch (InvalidProtocolBufferException e) {
+ logger.debug(e.getMessage(), e);
+ ret.setStatus(fee, code.FAILED);
+ throw new ContractExeException(e.getMessage());
+ }
+ return true;
+ }
+
+
+ @Override
+ public boolean validate() throws ContractValidateException {
+ if (this.contract == null) {
+ throw new ContractValidateException("No contract!");
+ }
+ if (this.dbManager == null) {
+ throw new ContractValidateException("No dbManager!");
+ }
+ if (!this.contract.is(ExchangeInjectContract.class)) {
+ throw new ContractValidateException(
+ "contract type error,expected type [ExchangeInjectContract],real type[" + contract
+ .getClass() + "]");
+ }
+ final ExchangeInjectContract contract;
+ try {
+ contract = this.contract.unpack(ExchangeInjectContract.class);
+ } catch (InvalidProtocolBufferException e) {
+ throw new ContractValidateException(e.getMessage());
+ }
+
+ byte[] ownerAddress = contract.getOwnerAddress().toByteArray();
+ String readableOwnerAddress = StringUtil.createReadableString(ownerAddress);
+
+ if (!Wallet.addressValid(ownerAddress)) {
+ throw new ContractValidateException("Invalid address");
+ }
+
+ if (!this.dbManager.getAccountStore().has(ownerAddress)) {
+ throw new ContractValidateException("account[" + readableOwnerAddress + "] not exists");
+ }
+
+ AccountCapsule accountCapsule = this.dbManager.getAccountStore().get(ownerAddress);
+
+ if (accountCapsule.getBalance() < calcFee()) {
+ throw new ContractValidateException("No enough balance for exchange inject fee!");
+ }
+
+ ExchangeCapsule exchangeCapsule;
+ try {
+ exchangeCapsule = dbManager.getExchangeStore().
+ get(ByteArray.fromLong(contract.getExchangeId()));
+ } catch (ItemNotFoundException ex) {
+ throw new ContractValidateException("Exchange[" + contract.getExchangeId() + "] not exists");
+ }
+
+ if (!accountCapsule.getAddress().equals(exchangeCapsule.getCreatorAddress())) {
+ throw new ContractValidateException("account[" + readableOwnerAddress + "] is not creator");
+ }
+
+ byte[] firstTokenID = exchangeCapsule.getFirstTokenId();
+ byte[] secondTokenID = exchangeCapsule.getSecondTokenId();
+ long firstTokenBalance = exchangeCapsule.getFirstTokenBalance();
+ long secondTokenBalance = exchangeCapsule.getSecondTokenBalance();
+
+ byte[] tokenID = contract.getTokenId().toByteArray();
+ long tokenQuant = contract.getQuant();
+
+ byte[] anotherTokenID;
+ long anotherTokenQuant;
+
+ if (!Arrays.equals(tokenID, firstTokenID) && !Arrays.equals(tokenID, secondTokenID)) {
+ throw new ContractValidateException("token is not in exchange");
+ }
+
+ if (firstTokenBalance == 0 || secondTokenBalance == 0) {
+ throw new ContractValidateException("Token balance in exchange is equal with 0,"
+ + "the exchange has been closed");
+ }
+
+ if (tokenQuant <= 0) {
+ throw new ContractValidateException("injected token balance must greater than zero");
+ }
+
+ long newTokenBalance, newAnotherTokenBalance;
+ if (Arrays.equals(tokenID, firstTokenID)) {
+ anotherTokenID = secondTokenID;
+ anotherTokenQuant = Math
+ .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance);
+ newTokenBalance = firstTokenBalance + tokenQuant;
+ newAnotherTokenBalance = secondTokenBalance + anotherTokenQuant;
+ } else {
+ anotherTokenID = firstTokenID;
+ anotherTokenQuant = Math
+ .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance);
+ newTokenBalance = secondTokenBalance + tokenQuant;
+ newAnotherTokenBalance = firstTokenBalance + anotherTokenQuant;
+ }
+
+ if (anotherTokenQuant <= 0) {
+ throw new ContractValidateException(" The calculated Token Quant must be larger than 0");
+ }
+
+ long balanceLimit = dbManager.getDynamicPropertiesStore().getExchangeBalanceLimit();
+ if (newTokenBalance > balanceLimit || newAnotherTokenBalance > balanceLimit) {
+ throw new ContractValidateException("token balance must less than " + balanceLimit);
+ }
+
+ if (tokenID == "_".getBytes()) {
+ if (accountCapsule.getBalance() < (tokenQuant + calcFee())) {
+ throw new ContractValidateException("balance is not enough");
+ }
+ } else {
+ if (!accountCapsule.assetBalanceEnough(tokenID, tokenQuant)) {
+ throw new ContractValidateException("token balance is not enough");
+ }
+ }
+
+ if (anotherTokenID == "_".getBytes()) {
+ if (accountCapsule.getBalance() < (anotherTokenQuant + calcFee())) {
+ throw new ContractValidateException("balance is not enough");
+ }
+ } else {
+ if (!accountCapsule.assetBalanceEnough(anotherTokenID, anotherTokenQuant)) {
+ throw new ContractValidateException("another token balance is not enough");
+ }
+ }
+
+ return true;
+ }
+
+
+ @Override
+ public ByteString getOwnerAddress() throws InvalidProtocolBufferException {
+ return contract.unpack(ExchangeInjectContract.class).getOwnerAddress();
+ }
+
+ @Override
+ public long calcFee() {
+ return 0;
+ }
+
+ private boolean validKey(long idx) {
+ return idx >= 0 && idx < ChainParameters.values().length;
+ }
+
+}
diff --git a/src/main/java/org/tron/core/actuator/ExchangeTransactionActuator.java b/src/main/java/org/tron/core/actuator/ExchangeTransactionActuator.java
new file mode 100755
index 00000000000..3361ca973d3
--- /dev/null
+++ b/src/main/java/org/tron/core/actuator/ExchangeTransactionActuator.java
@@ -0,0 +1,188 @@
+package org.tron.core.actuator;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import java.util.Arrays;
+import lombok.extern.slf4j.Slf4j;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.StringUtil;
+import org.tron.core.Wallet;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.capsule.ExchangeCapsule;
+import org.tron.core.capsule.TransactionResultCapsule;
+import org.tron.core.config.Parameter.ChainParameters;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.ItemNotFoundException;
+import org.tron.protos.Contract.ExchangeTransactionContract;
+import org.tron.protos.Protocol.Transaction.Result.code;
+
+@Slf4j
+public class ExchangeTransactionActuator extends AbstractActuator {
+
+ ExchangeTransactionActuator(final Any contract, final Manager dbManager) {
+ super(contract, dbManager);
+ }
+
+ @Override
+ public boolean execute(TransactionResultCapsule ret) throws ContractExeException {
+ long fee = calcFee();
+ try {
+ final ExchangeTransactionContract exchangeTransactionContract = this.contract
+ .unpack(ExchangeTransactionContract.class);
+ AccountCapsule accountCapsule = dbManager.getAccountStore()
+ .get(exchangeTransactionContract.getOwnerAddress().toByteArray());
+
+ ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore().
+ get(ByteArray.fromLong(exchangeTransactionContract.getExchangeId()));
+
+ byte[] firstTokenID = exchangeCapsule.getFirstTokenId();
+ byte[] secondTokenID = exchangeCapsule.getSecondTokenId();
+
+ byte[] tokenID = exchangeTransactionContract.getTokenId().toByteArray();
+ long tokenQuant = exchangeTransactionContract.getQuant();
+
+ byte[] anotherTokenID;
+ long anotherTokenQuant = exchangeCapsule.transaction(tokenID, tokenQuant);
+
+ if (Arrays.equals(tokenID, firstTokenID)) {
+ anotherTokenID = secondTokenID;
+ } else {
+ anotherTokenID = firstTokenID;
+ }
+
+ long newBalance = accountCapsule.getBalance() - calcFee();
+
+ if (tokenID == "_".getBytes()) {
+ accountCapsule.setBalance(newBalance - tokenQuant);
+ } else {
+ accountCapsule.reduceAssetAmount(tokenID, tokenQuant);
+ }
+
+ if (anotherTokenID == "_".getBytes()) {
+ accountCapsule.setBalance(newBalance + anotherTokenQuant);
+ } else {
+ accountCapsule.addAssetAmount(anotherTokenID, anotherTokenQuant);
+ }
+
+ dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule);
+ dbManager.getExchangeStore().put(exchangeCapsule.createDbKey(), exchangeCapsule);
+
+ ret.setStatus(fee, code.SUCESS);
+ } catch (ItemNotFoundException e) {
+ logger.debug(e.getMessage(), e);
+ ret.setStatus(fee, code.FAILED);
+ throw new ContractExeException(e.getMessage());
+ } catch (InvalidProtocolBufferException e) {
+ logger.debug(e.getMessage(), e);
+ ret.setStatus(fee, code.FAILED);
+ throw new ContractExeException(e.getMessage());
+ }
+ return true;
+ }
+
+
+ @Override
+ public boolean validate() throws ContractValidateException {
+ if (this.contract == null) {
+ throw new ContractValidateException("No contract!");
+ }
+ if (this.dbManager == null) {
+ throw new ContractValidateException("No dbManager!");
+ }
+ if (!this.contract.is(ExchangeTransactionContract.class)) {
+ throw new ContractValidateException(
+ "contract type error,expected type [ExchangeTransactionContract],real type[" + contract
+ .getClass() + "]");
+ }
+ final ExchangeTransactionContract contract;
+ try {
+ contract = this.contract.unpack(ExchangeTransactionContract.class);
+ } catch (InvalidProtocolBufferException e) {
+ throw new ContractValidateException(e.getMessage());
+ }
+
+ byte[] ownerAddress = contract.getOwnerAddress().toByteArray();
+ String readableOwnerAddress = StringUtil.createReadableString(ownerAddress);
+
+ if (!Wallet.addressValid(ownerAddress)) {
+ throw new ContractValidateException("Invalid address");
+ }
+
+ if (!this.dbManager.getAccountStore().has(ownerAddress)) {
+ throw new ContractValidateException("account[" + readableOwnerAddress + "] not exists");
+ }
+
+ AccountCapsule accountCapsule = this.dbManager.getAccountStore().get(ownerAddress);
+
+ if (accountCapsule.getBalance() < calcFee()) {
+ throw new ContractValidateException("No enough balance for exchange transaction fee!");
+ }
+
+ ExchangeCapsule exchangeCapsule;
+ try {
+ exchangeCapsule = dbManager.getExchangeStore().
+ get(ByteArray.fromLong(contract.getExchangeId()));
+ } catch (ItemNotFoundException ex) {
+ throw new ContractValidateException("Exchange[" + contract.getExchangeId() + "] not exists");
+ }
+
+ byte[] firstTokenID = exchangeCapsule.getFirstTokenId();
+ byte[] secondTokenID = exchangeCapsule.getSecondTokenId();
+ long firstTokenBalance = exchangeCapsule.getFirstTokenBalance();
+ long secondTokenBalance = exchangeCapsule.getSecondTokenBalance();
+
+ byte[] tokenID = contract.getTokenId().toByteArray();
+ long tokenQuant = contract.getQuant();
+
+ if (!Arrays.equals(tokenID, firstTokenID) && !Arrays.equals(tokenID, secondTokenID)) {
+ throw new ContractValidateException("token is not in exchange");
+ }
+
+ if (tokenQuant <= 0) {
+ throw new ContractValidateException("transaction token balance must greater than zero");
+ }
+
+ long balanceLimit = dbManager.getDynamicPropertiesStore().getExchangeBalanceLimit();
+ long tokenBalance = (tokenID == firstTokenID ? firstTokenBalance : secondTokenBalance);
+ tokenBalance += tokenQuant;
+ if (tokenBalance > balanceLimit) {
+ throw new ContractValidateException("token balance must less than " + balanceLimit);
+ }
+
+ if (tokenID == "_".getBytes()) {
+ if (accountCapsule.getBalance() < (tokenQuant + calcFee())) {
+ throw new ContractValidateException("balance is not enough");
+ }
+ } else {
+ if (!accountCapsule.assetBalanceEnough(tokenID, tokenQuant)) {
+ throw new ContractValidateException("token balance is not enough");
+ }
+ }
+
+ long anotherTokenQuant = exchangeCapsule.transaction(tokenID, tokenQuant);
+ if (anotherTokenQuant < 1) {
+ throw new ContractValidateException("token quant is not enough to buy 1 another token");
+ }
+
+ return true;
+ }
+
+
+ @Override
+ public ByteString getOwnerAddress() throws InvalidProtocolBufferException {
+ return contract.unpack(ExchangeTransactionContract.class).getOwnerAddress();
+ }
+
+ @Override
+ public long calcFee() {
+ return 0;
+ }
+
+ private boolean validKey(long idx) {
+ return idx >= 0 && idx < ChainParameters.values().length;
+ }
+
+}
diff --git a/src/main/java/org/tron/core/actuator/ExchangeWithdrawActuator.java b/src/main/java/org/tron/core/actuator/ExchangeWithdrawActuator.java
new file mode 100755
index 00000000000..301931445cd
--- /dev/null
+++ b/src/main/java/org/tron/core/actuator/ExchangeWithdrawActuator.java
@@ -0,0 +1,200 @@
+package org.tron.core.actuator;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import java.util.Arrays;
+import lombok.extern.slf4j.Slf4j;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.StringUtil;
+import org.tron.core.Wallet;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.capsule.ExchangeCapsule;
+import org.tron.core.capsule.TransactionResultCapsule;
+import org.tron.core.config.Parameter.ChainParameters;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.ItemNotFoundException;
+import org.tron.protos.Contract.ExchangeWithdrawContract;
+import org.tron.protos.Protocol.Transaction.Result.code;
+
+@Slf4j
+public class ExchangeWithdrawActuator extends AbstractActuator {
+
+ ExchangeWithdrawActuator(final Any contract, final Manager dbManager) {
+ super(contract, dbManager);
+ }
+
+ @Override
+ public boolean execute(TransactionResultCapsule ret) throws ContractExeException {
+ long fee = calcFee();
+ try {
+ final ExchangeWithdrawContract exchangeWithdrawContract = this.contract
+ .unpack(ExchangeWithdrawContract.class);
+ AccountCapsule accountCapsule = dbManager.getAccountStore()
+ .get(exchangeWithdrawContract.getOwnerAddress().toByteArray());
+
+ ExchangeCapsule exchangeCapsule = dbManager.getExchangeStore().
+ get(ByteArray.fromLong(exchangeWithdrawContract.getExchangeId()));
+
+ byte[] firstTokenID = exchangeCapsule.getFirstTokenId();
+ byte[] secondTokenID = exchangeCapsule.getSecondTokenId();
+ long firstTokenBalance = exchangeCapsule.getFirstTokenBalance();
+ long secondTokenBalance = exchangeCapsule.getSecondTokenBalance();
+
+ byte[] tokenID = exchangeWithdrawContract.getTokenId().toByteArray();
+ long tokenQuant = exchangeWithdrawContract.getQuant();
+
+ byte[] anotherTokenID;
+ long anotherTokenQuant;
+
+ if (Arrays.equals(tokenID, firstTokenID)) {
+ anotherTokenID = secondTokenID;
+ anotherTokenQuant = Math
+ .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance);
+ exchangeCapsule.setBalance(firstTokenBalance - tokenQuant,
+ secondTokenBalance - anotherTokenQuant);
+ } else {
+ anotherTokenID = firstTokenID;
+ anotherTokenQuant = Math
+ .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance);
+ exchangeCapsule.setBalance(firstTokenBalance - anotherTokenQuant,
+ secondTokenBalance - tokenQuant);
+ }
+
+ long newBalance = accountCapsule.getBalance() - calcFee();
+
+ if (tokenID == "_".getBytes()) {
+ accountCapsule.setBalance(newBalance + tokenQuant);
+ } else {
+ accountCapsule.addAssetAmount(tokenID, tokenQuant);
+ }
+
+ if (anotherTokenID == "_".getBytes()) {
+ accountCapsule.setBalance(newBalance + anotherTokenQuant);
+ } else {
+ accountCapsule.addAssetAmount(anotherTokenID, anotherTokenQuant);
+ }
+
+ dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule);
+ dbManager.getExchangeStore().put(exchangeCapsule.createDbKey(), exchangeCapsule);
+
+ ret.setStatus(fee, code.SUCESS);
+ } catch (ItemNotFoundException e) {
+ logger.debug(e.getMessage(), e);
+ ret.setStatus(fee, code.FAILED);
+ throw new ContractExeException(e.getMessage());
+ } catch (InvalidProtocolBufferException e) {
+ logger.debug(e.getMessage(), e);
+ ret.setStatus(fee, code.FAILED);
+ throw new ContractExeException(e.getMessage());
+ }
+ return true;
+ }
+
+
+ @Override
+ public boolean validate() throws ContractValidateException {
+ if (this.contract == null) {
+ throw new ContractValidateException("No contract!");
+ }
+ if (this.dbManager == null) {
+ throw new ContractValidateException("No dbManager!");
+ }
+ if (!this.contract.is(ExchangeWithdrawContract.class)) {
+ throw new ContractValidateException(
+ "contract type error,expected type [ExchangeWithdrawContract],real type[" + contract
+ .getClass() + "]");
+ }
+ final ExchangeWithdrawContract contract;
+ try {
+ contract = this.contract.unpack(ExchangeWithdrawContract.class);
+ } catch (InvalidProtocolBufferException e) {
+ throw new ContractValidateException(e.getMessage());
+ }
+
+ byte[] ownerAddress = contract.getOwnerAddress().toByteArray();
+ String readableOwnerAddress = StringUtil.createReadableString(ownerAddress);
+
+ if (!Wallet.addressValid(ownerAddress)) {
+ throw new ContractValidateException("Invalid address");
+ }
+
+ if (!this.dbManager.getAccountStore().has(ownerAddress)) {
+ throw new ContractValidateException("account[" + readableOwnerAddress + "] not exists");
+ }
+
+ AccountCapsule accountCapsule = this.dbManager.getAccountStore().get(ownerAddress);
+
+ if (accountCapsule.getBalance() < calcFee()) {
+ throw new ContractValidateException("No enough balance for exchange withdraw fee!");
+ }
+
+ ExchangeCapsule exchangeCapsule;
+ try {
+ exchangeCapsule = dbManager.getExchangeStore().
+ get(ByteArray.fromLong(contract.getExchangeId()));
+ } catch (ItemNotFoundException ex) {
+ throw new ContractValidateException("Exchange[" + contract.getExchangeId() + "] not exists");
+ }
+
+ if (!accountCapsule.getAddress().equals(exchangeCapsule.getCreatorAddress())) {
+ throw new ContractValidateException("account[" + readableOwnerAddress + "] is not creator");
+ }
+
+ byte[] firstTokenID = exchangeCapsule.getFirstTokenId();
+ byte[] secondTokenID = exchangeCapsule.getSecondTokenId();
+ long firstTokenBalance = exchangeCapsule.getFirstTokenBalance();
+ long secondTokenBalance = exchangeCapsule.getSecondTokenBalance();
+
+ byte[] tokenID = contract.getTokenId().toByteArray();
+ long tokenQuant = contract.getQuant();
+
+ long anotherTokenQuant;
+
+ if (!Arrays.equals(tokenID, firstTokenID) && !Arrays.equals(tokenID, secondTokenID)) {
+ throw new ContractValidateException("token is not in exchange");
+ }
+
+ if (tokenQuant <= 0) {
+ throw new ContractValidateException("withdraw token balance must greater than zero");
+ }
+
+ if (firstTokenBalance == 0 || secondTokenBalance == 0) {
+ throw new ContractValidateException("Token balance in exchange is equal with 0,the exchange has been closed");
+ }
+
+ if (Arrays.equals(tokenID, firstTokenID)) {
+ anotherTokenQuant = Math
+ .floorDiv(Math.multiplyExact(secondTokenBalance, tokenQuant), firstTokenBalance);
+ if (firstTokenBalance < tokenQuant || secondTokenBalance < anotherTokenQuant) {
+ throw new ContractValidateException("exchange balance is not enough");
+ }
+ } else {
+ anotherTokenQuant = Math
+ .floorDiv(Math.multiplyExact(firstTokenBalance, tokenQuant), secondTokenBalance);
+ if (secondTokenBalance < tokenQuant || firstTokenBalance < anotherTokenQuant) {
+ throw new ContractValidateException("exchange balance is not enough");
+ }
+ }
+
+ return true;
+ }
+
+
+ @Override
+ public ByteString getOwnerAddress() throws InvalidProtocolBufferException {
+ return contract.unpack(ExchangeWithdrawContract.class).getOwnerAddress();
+ }
+
+ @Override
+ public long calcFee() {
+ return 0;
+ }
+
+ private boolean validKey(long idx) {
+ return idx >= 0 && idx < ChainParameters.values().length;
+ }
+
+}
diff --git a/src/main/java/org/tron/core/actuator/FreezeBalanceActuator.java b/src/main/java/org/tron/core/actuator/FreezeBalanceActuator.java
index 82e02da2e3f..fd54ac1df3c 100755
--- a/src/main/java/org/tron/core/actuator/FreezeBalanceActuator.java
+++ b/src/main/java/org/tron/core/actuator/FreezeBalanceActuator.java
@@ -12,7 +12,6 @@
import org.tron.core.exception.ContractExeException;
import org.tron.core.exception.ContractValidateException;
import org.tron.protos.Contract.FreezeBalanceContract;
-import org.tron.protos.Contract.ResourceCode;
import org.tron.protos.Protocol.Account.AccountResource;
import org.tron.protos.Protocol.Account.Frozen;
import org.tron.protos.Protocol.Transaction.Result.code;
@@ -69,31 +68,32 @@ public boolean execute(TransactionResultCapsule ret) throws ContractExeException
dbManager.getDynamicPropertiesStore()
.addTotalNetWeight(freezeBalanceContract.getFrozenBalance() / 1000_000L);
break;
- case CPU:
- long currentFrozenBalanceForCpu = accountCapsule.getAccountResource().getFrozenBalanceForCpu()
+ case ENERGY:
+ long currentFrozenBalanceForEnergy = accountCapsule.getAccountResource()
+ .getFrozenBalanceForEnergy()
.getFrozenBalance();
- long newFrozenBalanceForCpu = freezeBalanceContract.getFrozenBalance() + currentFrozenBalanceForCpu;
+ long newFrozenBalanceForEnergy =
+ freezeBalanceContract.getFrozenBalance() + currentFrozenBalanceForEnergy;
- Frozen newFrozenForCpu = Frozen.newBuilder()
- .setFrozenBalance(newFrozenBalanceForCpu)
+ Frozen newFrozenForEnergy = Frozen.newBuilder()
+ .setFrozenBalance(newFrozenBalanceForEnergy)
.setExpireTime(now + duration)
.build();
AccountResource newAccountResource = accountCapsule.getAccountResource().toBuilder()
- .setFrozenBalanceForCpu(newFrozenForCpu).build();
+ .setFrozenBalanceForEnergy(newFrozenForEnergy).build();
accountCapsule.setInstance(accountCapsule.getInstance().toBuilder()
.setAccountResource(newAccountResource)
.setBalance(newBalance)
.build());
dbManager.getDynamicPropertiesStore()
- .addTotalCpuWeight(freezeBalanceContract.getFrozenBalance() / 1000_000L);
+ .addTotalEnergyWeight(freezeBalanceContract.getFrozenBalance() / 1000_000L);
break;
}
dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule);
-
ret.setStatus(fee, code.SUCESS);
return true;
@@ -164,14 +164,14 @@ public boolean validate() throws ContractValidateException {
+ "and more than " + minFrozenTime + " days");
}
-
switch (freezeBalanceContract.getResource()) {
case BANDWIDTH:
break;
- case CPU:
+ case ENERGY:
break;
- default: throw new ContractValidateException(
- "ResourceCode error,valid ResourceCode[BANDWIDTH、CPU]");
+ default:
+ throw new ContractValidateException(
+ "ResourceCode error,valid ResourceCode[BANDWIDTH、ENERGY]");
}
return true;
diff --git a/src/main/java/org/tron/core/actuator/ParticipateAssetIssueActuator.java b/src/main/java/org/tron/core/actuator/ParticipateAssetIssueActuator.java
index 4a3f76da25e..58a796099e3 100755
--- a/src/main/java/org/tron/core/actuator/ParticipateAssetIssueActuator.java
+++ b/src/main/java/org/tron/core/actuator/ParticipateAssetIssueActuator.java
@@ -25,7 +25,6 @@
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.AssetIssueCapsule;
import org.tron.core.capsule.TransactionResultCapsule;
-import org.tron.core.capsule.utils.TransactionUtil;
import org.tron.core.db.Manager;
import org.tron.core.exception.ContractExeException;
import org.tron.core.exception.ContractValidateException;
diff --git a/src/main/java/org/tron/core/actuator/ProposalCreateActuator.java b/src/main/java/org/tron/core/actuator/ProposalCreateActuator.java
index 5663fe8a490..46f1da38ccb 100755
--- a/src/main/java/org/tron/core/actuator/ProposalCreateActuator.java
+++ b/src/main/java/org/tron/core/actuator/ProposalCreateActuator.java
@@ -129,6 +129,17 @@ private void validateValue(Map.Entry entry) throws ContractValidateE
}
return;
}
+ case (10):{
+ if(dbManager.getDynamicPropertiesStore().getRemoveThePowerOfTheGr() == -1){
+ throw new ContractValidateException(
+ "This proposal has been executed before and is only allowed to be executed once");
+ }
+
+ if(entry.getValue() != 1){
+ throw new ContractValidateException(
+ "This value[REMOVE_THE_POWER_OF_THE_GR] is only allowed to be 1");
+ }
+ }
default:
break;
}
diff --git a/src/main/java/org/tron/core/actuator/ProposalDeleteActuator.java b/src/main/java/org/tron/core/actuator/ProposalDeleteActuator.java
index 7f710c36e2c..b65537afd4b 100755
--- a/src/main/java/org/tron/core/actuator/ProposalDeleteActuator.java
+++ b/src/main/java/org/tron/core/actuator/ProposalDeleteActuator.java
@@ -92,7 +92,7 @@ public boolean validate() throws ContractValidateException {
}
long now = dbManager.getHeadBlockTimeStamp();
- if (!proposalCapsule.getProposalAddress().equals(contract.getOwnerAddress()) ) {
+ if (!proposalCapsule.getProposalAddress().equals(contract.getOwnerAddress())) {
throw new ContractValidateException("Proposal[" + contract.getProposalId() + "] "
+ "is not proposed by " + readableOwnerAddress);
}
diff --git a/src/main/java/org/tron/core/actuator/SellStorageActuator.java b/src/main/java/org/tron/core/actuator/SellStorageActuator.java
index 1d0e53fab53..57c72e3e9e2 100755
--- a/src/main/java/org/tron/core/actuator/SellStorageActuator.java
+++ b/src/main/java/org/tron/core/actuator/SellStorageActuator.java
@@ -40,7 +40,6 @@ public boolean execute(TransactionResultCapsule ret) throws ContractExeException
AccountCapsule accountCapsule = dbManager.getAccountStore()
.get(sellStorageContract.getOwnerAddress().toByteArray());
-
long bytes = sellStorageContract.getStorageBytes();
storageMarket.sellStorage(accountCapsule, bytes);
@@ -89,17 +88,18 @@ public boolean validate() throws ContractValidateException {
throw new ContractValidateException("bytes must be positive");
}
- long now = dbManager.getHeadBlockTimeStamp();
-
- long latestExchangeStorageTime = accountCapsule.getLatestExchangeStorageTime();
long currentStorageLimit = accountCapsule.getStorageLimit();
long currentUnusedStorage = currentStorageLimit - accountCapsule.getStorageUsage();
- long duration = now - latestExchangeStorageTime;
- long storageTax = storageMarket.calculateTax(duration, currentStorageLimit);
+ if (bytes > currentUnusedStorage) {
+ throw new ContractValidateException(
+ "bytes must be less than currentUnusedStorage[" + currentUnusedStorage + "]");
+ }
- if (bytes > (currentUnusedStorage - storageTax)) {
- throw new ContractValidateException("bytes must be less than currentUnusedStorage minus tax");
+ long quantity = storageMarket.trySellStorage(bytes);
+ if (quantity <= 1_000_000L) {
+ throw new ContractValidateException(
+ "quantity must be larger than 1TRX,current quantity[" + quantity + "]");
}
return true;
diff --git a/src/main/java/org/tron/core/actuator/TransferActuator.java b/src/main/java/org/tron/core/actuator/TransferActuator.java
index 7845f561bbc..eb5f87451c2 100755
--- a/src/main/java/org/tron/core/actuator/TransferActuator.java
+++ b/src/main/java/org/tron/core/actuator/TransferActuator.java
@@ -5,6 +5,7 @@
import com.google.protobuf.InvalidProtocolBufferException;
import java.util.Arrays;
import lombok.extern.slf4j.Slf4j;
+import org.tron.common.storage.Deposit;
import org.tron.core.Wallet;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.TransactionResultCapsule;
@@ -118,7 +119,8 @@ public boolean validate() throws ContractValidateException {
}
if (balance < Math.addExact(amount, fee)) {
- throw new ContractValidateException("Validate TransferContract error, balance is not sufficient.");
+ throw new ContractValidateException(
+ "Validate TransferContract error, balance is not sufficient.");
}
if (toAccount != null) {
@@ -129,7 +131,52 @@ public boolean validate() throws ContractValidateException {
throw new ContractValidateException(e.getMessage());
}
+ return true;
+ }
+
+ public static boolean validateForSmartContract(Deposit deposit, byte[] ownerAddress,
+ byte[] toAddress, long amount) throws ContractValidateException {
+ if (!Wallet.addressValid(ownerAddress)) {
+ throw new ContractValidateException("Invalid ownerAddress");
+ }
+ if (!Wallet.addressValid(toAddress)) {
+ throw new ContractValidateException("Invalid toAddress");
+ }
+
+ if (Arrays.equals(toAddress, ownerAddress)) {
+ throw new ContractValidateException("Cannot transfer trx to yourself.");
+ }
+
+ AccountCapsule ownerAccount = deposit.getAccount(ownerAddress);
+ if (ownerAccount == null) {
+ throw new ContractValidateException("Validate InternalTransfer error, no OwnerAccount.");
+ }
+
+ AccountCapsule toAccount = deposit.getAccount(toAddress);
+ if (toAccount == null) {
+ throw new ContractValidateException(
+ "Validate InternalTransfer error, no ToAccount. And not allowed to create account in smart contract.");
+ }
+ long balance = ownerAccount.getBalance();
+
+ if (amount < 0) {
+ throw new ContractValidateException("Amount must greater than or equals 0.");
+ }
+
+ try {
+ if (balance < amount) {
+ throw new ContractValidateException(
+ "Validate InternalTransfer error, balance is not sufficient.");
+ }
+
+ if (toAccount != null) {
+ long toAddressBalance = Math.addExact(toAccount.getBalance(), amount);
+ }
+ } catch (ArithmeticException e) {
+ logger.debug(e.getMessage(), e);
+ throw new ContractValidateException(e.getMessage());
+ }
return true;
}
@@ -143,4 +190,5 @@ public ByteString getOwnerAddress() throws InvalidProtocolBufferException {
public long calcFee() {
return ChainConstant.TRANSFER_FEE;
}
+
}
\ No newline at end of file
diff --git a/src/main/java/org/tron/core/actuator/UnfreezeBalanceActuator.java b/src/main/java/org/tron/core/actuator/UnfreezeBalanceActuator.java
index 4bfc5388d49..208edbe1792 100755
--- a/src/main/java/org/tron/core/actuator/UnfreezeBalanceActuator.java
+++ b/src/main/java/org/tron/core/actuator/UnfreezeBalanceActuator.java
@@ -1,7 +1,5 @@
package org.tron.core.actuator;
-import static org.tron.protos.Contract.ResourceCode.BANDWIDTH;
-
import com.google.common.collect.Lists;
import com.google.protobuf.Any;
import com.google.protobuf.ByteString;
@@ -66,17 +64,17 @@ public boolean execute(TransactionResultCapsule ret) throws ContractExeException
dbManager.getDynamicPropertiesStore().addTotalNetWeight(-unfreezeBalance / 1000_000L);
break;
- case CPU:
- unfreezeBalance = accountCapsule.getAccountResource().getFrozenBalanceForCpu()
+ case ENERGY:
+ unfreezeBalance = accountCapsule.getAccountResource().getFrozenBalanceForEnergy()
.getFrozenBalance();
AccountResource newAccountResource = accountCapsule.getAccountResource().toBuilder()
- .clearFrozenBalanceForCpu().build();
+ .clearFrozenBalanceForEnergy().build();
accountCapsule.setInstance(accountCapsule.getInstance().toBuilder()
.setBalance(oldBalance + unfreezeBalance)
.setAccountResource(newAccountResource).build());
- dbManager.getDynamicPropertiesStore().addTotalCpuWeight(-unfreezeBalance / 1000_000L);
+ dbManager.getDynamicPropertiesStore().addTotalEnergyWeight(-unfreezeBalance / 1000_000L);
break;
}
@@ -94,6 +92,7 @@ public boolean execute(TransactionResultCapsule ret) throws ContractExeException
dbManager.getVotesStore().put(ownerAddress, votesCapsule);
+ ret.setUnfreezeAmount(unfreezeBalance);
ret.setStatus(fee, code.SUCESS);
return true;
@@ -145,19 +144,20 @@ public boolean validate() throws ContractValidateException {
throw new ContractValidateException("It's not time to unfreeze.");
}
break;
- case CPU:
- Frozen frozenBalanceForCpu = accountCapsule.getAccountResource().getFrozenBalanceForCpu();
- if (frozenBalanceForCpu.getFrozenBalance() <= 0) {
+ case ENERGY:
+ Frozen frozenBalanceForEnergy = accountCapsule.getAccountResource()
+ .getFrozenBalanceForEnergy();
+ if (frozenBalanceForEnergy.getFrozenBalance() <= 0) {
throw new ContractValidateException("no frozenBalance");
}
- if (frozenBalanceForCpu.getExpireTime() > now) {
+ if (frozenBalanceForEnergy.getExpireTime() > now) {
throw new ContractValidateException("It's not time to unfreeze.");
}
break;
default:
throw new ContractValidateException(
- "ResourceCode error.valid ResourceCode[BANDWIDTH、CPU]");
+ "ResourceCode error.valid ResourceCode[BANDWIDTH、ENERGY]");
}
return true;
diff --git a/src/main/java/org/tron/core/actuator/UpdateSettingContractActuator.java b/src/main/java/org/tron/core/actuator/UpdateSettingContractActuator.java
new file mode 100755
index 00000000000..d6941d4290a
--- /dev/null
+++ b/src/main/java/org/tron/core/actuator/UpdateSettingContractActuator.java
@@ -0,0 +1,120 @@
+package org.tron.core.actuator;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import java.util.Arrays;
+import lombok.extern.slf4j.Slf4j;
+import org.tron.common.utils.StringUtil;
+import org.tron.core.Wallet;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.capsule.ContractCapsule;
+import org.tron.core.capsule.TransactionResultCapsule;
+import org.tron.core.db.AccountStore;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.protos.Contract.UpdateSettingContract;
+import org.tron.protos.Protocol.Transaction.Result.code;
+
+@Slf4j
+public class UpdateSettingContractActuator extends AbstractActuator {
+
+ UpdateSettingContractActuator(Any contract, Manager dbManager) {
+ super(contract, dbManager);
+ }
+
+ @Override
+ public boolean execute(TransactionResultCapsule ret) throws ContractExeException {
+ long fee = calcFee();
+ try {
+ UpdateSettingContract usContract = contract
+ .unpack(UpdateSettingContract.class);
+ long newPercent = usContract.getConsumeUserResourcePercent();
+ byte[] contractAddress = usContract.getContractAddress().toByteArray();
+ ContractCapsule deployedContract = dbManager.getContractStore().get(contractAddress);
+
+ dbManager.getContractStore().put(contractAddress, new ContractCapsule(
+ deployedContract.getInstance().toBuilder().setConsumeUserResourcePercent(newPercent)
+ .build()));
+
+ ret.setStatus(fee, code.SUCESS);
+ } catch (InvalidProtocolBufferException e) {
+ logger.debug(e.getMessage(), e);
+ ret.setStatus(fee, code.FAILED);
+ throw new ContractExeException(e.getMessage());
+ }
+ return true;
+ }
+
+ @Override
+ public boolean validate() throws ContractValidateException {
+ if (this.contract == null) {
+ throw new ContractValidateException("No contract!");
+ }
+ if (this.dbManager == null) {
+ throw new ContractValidateException("No dbManager!");
+ }
+ if (!this.contract.is(UpdateSettingContract.class)) {
+ throw new ContractValidateException(
+ "contract type error,expected type [UpdateSettingContract],real type["
+ + contract
+ .getClass() + "]");
+ }
+ final UpdateSettingContract contract;
+ try {
+ contract = this.contract.unpack(UpdateSettingContract.class);
+ } catch (InvalidProtocolBufferException e) {
+ logger.debug(e.getMessage(), e);
+ throw new ContractValidateException(e.getMessage());
+ }
+ if (!Wallet.addressValid(contract.getOwnerAddress().toByteArray())) {
+ throw new ContractValidateException("Invalid address");
+ }
+ byte[] ownerAddress = contract.getOwnerAddress().toByteArray();
+ String readableOwnerAddress = StringUtil.createReadableString(ownerAddress);
+
+ AccountStore accountStore = dbManager.getAccountStore();
+
+ AccountCapsule accountCapsule = accountStore.get(ownerAddress);
+ if (accountCapsule == null) {
+ throw new ContractValidateException(
+ "Account[" + readableOwnerAddress + "] not exists");
+ }
+
+ long newPercent = contract.getConsumeUserResourcePercent();
+ if (newPercent > 100 || newPercent < 0) {
+ throw new ContractValidateException(
+ "percent not in [0, 100]");
+ }
+
+ byte[] contractAddress = contract.getContractAddress().toByteArray();
+ ContractCapsule deployedContract = dbManager.getContractStore().get(contractAddress);
+
+ if (deployedContract == null) {
+ throw new ContractValidateException(
+ "Contract not exists");
+ }
+
+ byte[] deployedContractOwnerAddress = deployedContract.getInstance().getOriginAddress()
+ .toByteArray();
+
+ if (!Arrays.equals(ownerAddress, deployedContractOwnerAddress)) {
+ throw new ContractValidateException(
+ "Account[" + readableOwnerAddress + "] is not the owner of the contract");
+ }
+
+ return true;
+ }
+
+ @Override
+ public ByteString getOwnerAddress() throws InvalidProtocolBufferException {
+ return contract.unpack(UpdateSettingContract.class).getOwnerAddress();
+ }
+
+ @Override
+ public long calcFee() {
+ return 0;
+ }
+
+}
diff --git a/src/main/java/org/tron/core/actuator/VoteWitnessActuator.java b/src/main/java/org/tron/core/actuator/VoteWitnessActuator.java
index 5f0b50c4cc2..9cda4b68543 100755
--- a/src/main/java/org/tron/core/actuator/VoteWitnessActuator.java
+++ b/src/main/java/org/tron/core/actuator/VoteWitnessActuator.java
@@ -140,7 +140,8 @@ private void countVoteAccount(VoteWitnessContract voteContract) {
AccountCapsule accountCapsule = accountStore.get(ownerAddress);
if (!votesStore.has(ownerAddress)) {
- votesCapsule = new VotesCapsule(voteContract.getOwnerAddress(), accountCapsule.getVotesList());
+ votesCapsule = new VotesCapsule(voteContract.getOwnerAddress(),
+ accountCapsule.getVotesList());
} else {
votesCapsule = votesStore.get(ownerAddress);
}
diff --git a/src/main/java/org/tron/core/actuator/WithdrawBalanceActuator.java b/src/main/java/org/tron/core/actuator/WithdrawBalanceActuator.java
index 232c628706b..981457f70a4 100755
--- a/src/main/java/org/tron/core/actuator/WithdrawBalanceActuator.java
+++ b/src/main/java/org/tron/core/actuator/WithdrawBalanceActuator.java
@@ -49,6 +49,7 @@ public boolean execute(TransactionResultCapsule ret) throws ContractExeException
.setLatestWithdrawTime(now)
.build());
dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule);
+ ret.setWithdrawAmount(allowance);
ret.setStatus(fee, code.SUCESS);
return true;
diff --git a/src/main/java/org/tron/core/capsule/AccountCapsule.java b/src/main/java/org/tron/core/capsule/AccountCapsule.java
index 33f2f7cbc33..05cc545f169 100644
--- a/src/main/java/org/tron/core/capsule/AccountCapsule.java
+++ b/src/main/java/org/tron/core/capsule/AccountCapsule.java
@@ -249,7 +249,7 @@ public long getTronPower() {
tp += account.getFrozen(i).getFrozenBalance();
}
- tp += account.getAccountResource().getFrozenBalanceForCpu().getFrozenBalance();
+ tp += account.getAccountResource().getFrozenBalanceForEnergy().getFrozenBalance();
return tp;
}
@@ -447,14 +447,14 @@ public AccountResource getAccountResource() {
}
- public void setFrozenForCpu(long newFrozenBalanceForCpu, long time) {
- Frozen newFrozenForCpu = Frozen.newBuilder()
- .setFrozenBalance(newFrozenBalanceForCpu)
+ public void setFrozenForEnergy(long newFrozenBalanceForEnergy, long time) {
+ Frozen newFrozenForEnergy = Frozen.newBuilder()
+ .setFrozenBalance(newFrozenBalanceForEnergy)
.setExpireTime(time)
.build();
AccountResource newAccountResource = getAccountResource().toBuilder()
- .setFrozenBalanceForCpu(newFrozenForCpu).build();
+ .setFrozenBalanceForEnergy(newFrozenForEnergy).build();
this.account = this.account.toBuilder()
.setAccountResource(newAccountResource)
@@ -462,24 +462,25 @@ public void setFrozenForCpu(long newFrozenBalanceForCpu, long time) {
}
- public long getCpuFrozenBalance() {
- return this.account.getAccountResource().getFrozenBalanceForCpu().getFrozenBalance();
+ public long getEnergyFrozenBalance() {
+ return this.account.getAccountResource().getFrozenBalanceForEnergy().getFrozenBalance();
}
- public long getCpuUsage() {
- return this.account.getAccountResource().getCpuUsage();
+ public long getEnergyUsage() {
+ return this.account.getAccountResource().getEnergyUsage();
}
- public void setCpuUsage(long cpuUsage) {
+ public void setEnergyUsage(long energyUsage) {
this.account = this.account.toBuilder()
.setAccountResource(
- this.account.getAccountResource().toBuilder().setCpuUsage(cpuUsage).build()).build();
+ this.account.getAccountResource().toBuilder().setEnergyUsage(energyUsage).build())
+ .build();
}
- public void setLatestConsumeTimeForCpu(long latest_time) {
+ public void setLatestConsumeTimeForEnergy(long latest_time) {
this.account = this.account.toBuilder()
.setAccountResource(
- this.account.getAccountResource().toBuilder().setLatestConsumeTimeForCpu(latest_time)
+ this.account.getAccountResource().toBuilder().setLatestConsumeTimeForEnergy(latest_time)
.build()).build();
}
@@ -522,6 +523,10 @@ public long getStorageUsage() {
return this.account.getAccountResource().getStorageUsage();
}
+ public long getStorageLeft() {
+ return getStorageLimit() - getStorageUsage();
+ }
+
public void setStorageUsage(long usage) {
AccountResource accountResource = this.account.getAccountResource();
accountResource = accountResource.toBuilder().setStorageUsage(usage).build();
@@ -544,4 +549,16 @@ public void setLatestExchangeStorageTime(long time) {
.build();
}
+ public void addStorageUsage(long storageUsage) {
+ if (storageUsage <= 0) {
+ return;
+ }
+ AccountResource accountResource = this.account.getAccountResource();
+ accountResource = accountResource.toBuilder()
+ .setStorageUsage(accountResource.getStorageUsage() + storageUsage).build();
+
+ this.account = this.account.toBuilder()
+ .setAccountResource(accountResource)
+ .build();
+ }
}
diff --git a/src/main/java/org/tron/core/capsule/BlockCapsule.java b/src/main/java/org/tron/core/capsule/BlockCapsule.java
index 0a7ecf0b683..5e5346ebb62 100755
--- a/src/main/java/org/tron/core/capsule/BlockCapsule.java
+++ b/src/main/java/org/tron/core/capsule/BlockCapsule.java
@@ -33,6 +33,7 @@
import org.tron.common.utils.Sha256Hash;
import org.tron.common.utils.Time;
import org.tron.core.capsule.utils.MerkleTree;
+import org.tron.core.config.Parameter.ChainConstant;
import org.tron.core.exception.BadItemException;
import org.tron.core.exception.ValidateSignatureException;
import org.tron.protos.Protocol.Block;
@@ -128,7 +129,9 @@ public BlockCapsule(long number, Sha256Hash hash, long when, ByteString witnessA
.setNumber(number)
.setParentHash(hash.getByteString())
.setTimestamp(when)
- .setWitnessAddress(witnessAddress).build();
+ .setVersion(ChainConstant.version)
+ .setWitnessAddress(witnessAddress)
+ .build();
// block header
BlockHeader.Builder blockHeaderBuild = BlockHeader.newBuilder();
diff --git a/src/main/java/org/tron/core/capsule/CodeCapsule.java b/src/main/java/org/tron/core/capsule/CodeCapsule.java
index 8e1aa32ddee..d1bcd78816b 100644
--- a/src/main/java/org/tron/core/capsule/CodeCapsule.java
+++ b/src/main/java/org/tron/core/capsule/CodeCapsule.java
@@ -15,20 +15,11 @@
package org.tron.core.capsule;
-import com.google.protobuf.Any;
-import com.google.protobuf.ByteString;
-import com.google.protobuf.InvalidProtocolBufferException;
-import java.util.Arrays;
import lombok.extern.slf4j.Slf4j;
-import org.tron.common.crypto.ECKey.ECDSASignature;
import org.tron.common.utils.Sha256Hash;
-import org.tron.protos.Contract.TriggerSmartContract;
-import org.tron.protos.Protocol.SmartContract;
-import org.tron.protos.Protocol.Transaction;
-/**
- * Created by Guo Yonggang on 04.14.2018
- */
+import java.util.Arrays;
+
@Slf4j
public class CodeCapsule implements ProtoCapsule {
@@ -38,49 +29,10 @@ public CodeCapsule(byte[] code) {
this.code = code;
}
- public CodeCapsule(ByteString bs) {
- this.code = bs.toByteArray();
- }
-
- public static SmartContract getCreationContractFromTransaction(Transaction trx) {
- try {
- Any any = trx.getRawData().getContract(0).getParameter();
- SmartContract contractCreationContract = any.unpack(SmartContract.class);
- return contractCreationContract;
- } catch (InvalidProtocolBufferException e) {
- return null;
- }
- }
-
- public static TriggerSmartContract getCallContractFromTransaction(Transaction trx) {
- try {
- Any any = trx.getRawData().getContract(0).getParameter();
- TriggerSmartContract contractCallContract = any.unpack(TriggerSmartContract.class);
- return contractCallContract;
- } catch (InvalidProtocolBufferException e) {
- return null;
- }
- }
-
- public Sha256Hash getHash() {
- return Sha256Hash.of(this.code);
- }
-
public Sha256Hash getCodeHash() {
return Sha256Hash.of(this.code);
}
- public static String getBase64FromByteString(ByteString sign) {
- byte[] r = sign.substring(0, 32).toByteArray();
- byte[] s = sign.substring(32, 64).toByteArray();
- byte v = sign.byteAt(64);
- if (v < 27) {
- v += 27; //revId -> v
- }
- ECDSASignature signature = ECDSASignature.fromComponents(r, s, v);
- return signature.toBase64();
- }
-
@Override
public byte[] getData() {
return this.code;
diff --git a/src/main/java/org/tron/core/capsule/ContractCapsule.java b/src/main/java/org/tron/core/capsule/ContractCapsule.java
index f7e5a7d1ebc..8de8347594e 100644
--- a/src/main/java/org/tron/core/capsule/ContractCapsule.java
+++ b/src/main/java/org/tron/core/capsule/ContractCapsule.java
@@ -88,4 +88,12 @@ public SmartContract getInstance() {
public String toString() {
return this.smartContract.toString();
}
+
+ public byte[] getOriginAddress() {
+ return this.smartContract.getOriginAddress().toByteArray();
+ }
+
+ public long getConsumeUserResourcePercent() {
+ return this.smartContract.getConsumeUserResourcePercent();
+ }
}
diff --git a/src/main/java/org/tron/core/capsule/ExchangeCapsule.java b/src/main/java/org/tron/core/capsule/ExchangeCapsule.java
new file mode 100644
index 00000000000..aba8f24fb91
--- /dev/null
+++ b/src/main/java/org/tron/core/capsule/ExchangeCapsule.java
@@ -0,0 +1,139 @@
+package org.tron.core.capsule;
+
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import lombok.extern.slf4j.Slf4j;
+import org.tron.common.utils.ByteArray;
+import org.tron.core.capsule.utils.ExchangeProcessor;
+import org.tron.protos.Protocol.Exchange;
+
+@Slf4j
+public class ExchangeCapsule implements ProtoCapsule {
+
+ private Exchange exchange;
+
+ public ExchangeCapsule(final Exchange exchange) {
+ this.exchange = exchange;
+ }
+
+ public ExchangeCapsule(final byte[] data) {
+ try {
+ this.exchange = Exchange.parseFrom(data);
+ } catch (InvalidProtocolBufferException e) {
+ logger.debug(e.getMessage(), e);
+ }
+ }
+
+ public ExchangeCapsule(ByteString address, final long id, long createTime,
+ byte[] firstTokenID, byte[] secondTokenID) {
+ this.exchange = Exchange.newBuilder()
+ .setExchangeId(id)
+ .setCreatorAddress(address)
+ .setCreateTime(createTime)
+ .setFirstTokenId(ByteString.copyFrom(firstTokenID))
+ .setSecondTokenId(ByteString.copyFrom(secondTokenID))
+ .build();
+ }
+
+ public long getID() {
+ return this.exchange.getExchangeId();
+ }
+
+ public void setID(long id) {
+ this.exchange = this.exchange.toBuilder()
+ .setExchangeId(id)
+ .build();
+ }
+
+ public ByteString getCreatorAddress() {
+ return this.exchange.getCreatorAddress();
+ }
+
+ public void setExchangeAddress(ByteString address) {
+ this.exchange = this.exchange.toBuilder()
+ .setCreatorAddress(address)
+ .build();
+ }
+
+ public void setBalance(long firstTokenBalance, long secondTokenBalance) {
+ this.exchange = this.exchange.toBuilder()
+ .setFirstTokenBalance(firstTokenBalance)
+ .setSecondTokenBalance(secondTokenBalance)
+ .build();
+ }
+
+ public long getCreateTime() {
+ return this.exchange.getCreateTime();
+ }
+
+ public void setCreateTime(long time) {
+ this.exchange = this.exchange.toBuilder()
+ .setCreateTime(time)
+ .build();
+ }
+
+ public byte[] getFirstTokenId() {
+ return this.exchange.getFirstTokenId().toByteArray();
+ }
+
+ public byte[] getSecondTokenId() {
+ return this.exchange.getSecondTokenId().toByteArray();
+ }
+
+ public long getFirstTokenBalance() {
+ return this.exchange.getFirstTokenBalance();
+ }
+
+ public long getSecondTokenBalance() {
+ return this.exchange.getSecondTokenBalance();
+ }
+
+
+ public byte[] createDbKey() {
+ return calculateDbKey(getID());
+ }
+
+ public static byte[] calculateDbKey(long number) {
+ return ByteArray.fromLong(number);
+ }
+
+ public long transaction(byte[] sellTokenID, long sellTokenQuant) {
+ long supply = 1_000_000_000_000_000_000L;
+ ExchangeProcessor processor = new ExchangeProcessor(supply);
+
+ long buyTokenQuant = 0;
+ long firstTokenBalance = this.exchange.getFirstTokenBalance();
+ long secondTokenBalance = this.exchange.getSecondTokenBalance();
+
+ if (this.exchange.getFirstTokenId().equals(ByteString.copyFrom(sellTokenID))) {
+ buyTokenQuant = processor.exchange(firstTokenBalance,
+ secondTokenBalance,
+ sellTokenQuant);
+ this.exchange = this.exchange.toBuilder()
+ .setFirstTokenBalance(firstTokenBalance + sellTokenQuant)
+ .setSecondTokenBalance(secondTokenBalance - buyTokenQuant)
+ .build();
+ } else {
+ buyTokenQuant = processor.exchange(secondTokenBalance,
+ firstTokenBalance,
+ sellTokenQuant);
+ this.exchange = this.exchange.toBuilder()
+ .setFirstTokenBalance(firstTokenBalance - buyTokenQuant)
+ .setSecondTokenBalance(secondTokenBalance + sellTokenQuant)
+ .build();
+ }
+
+ return buyTokenQuant;
+ }
+
+ @Override
+ public byte[] getData() {
+ return this.exchange.toByteArray();
+ }
+
+ @Override
+ public Exchange getInstance() {
+ return this.exchange;
+ }
+
+}
diff --git a/src/main/java/org/tron/core/capsule/ReceiptCapsule.java b/src/main/java/org/tron/core/capsule/ReceiptCapsule.java
index 6d5c6054c4c..dccb0417248 100644
--- a/src/main/java/org/tron/core/capsule/ReceiptCapsule.java
+++ b/src/main/java/org/tron/core/capsule/ReceiptCapsule.java
@@ -1,44 +1,135 @@
package org.tron.core.capsule;
import org.tron.common.utils.Sha256Hash;
+import org.tron.core.Constant;
+import org.tron.core.db.EnergyProcessor;
+import org.tron.core.db.Manager;
import org.tron.protos.Protocol.ResourceReceipt;
public class ReceiptCapsule {
+
private ResourceReceipt receipt;
private Sha256Hash receiptAddress;
public ReceiptCapsule(ResourceReceipt data, Sha256Hash receiptAddress) {
- receipt = data;
+ this.receipt = data;
this.receiptAddress = receiptAddress;
}
public ReceiptCapsule(Sha256Hash receiptAddress) {
- receipt = ResourceReceipt.newBuilder().build();
+ this.receipt = ResourceReceipt.newBuilder().build();
this.receiptAddress = receiptAddress;
}
- public void setCpuUsage(long usage) {
- receipt.toBuilder().setCpuFee(usage);
+ public void setReceipt(ResourceReceipt receipt) {
+ this.receipt = receipt;
+ }
+
+ public ResourceReceipt getReceipt() {
+ return this.receipt;
+ }
+
+ public Sha256Hash getReceiptAddress() {
+ return this.receiptAddress;
+ }
+
+ public void setNetUsage(long netUsage) {
+ this.receipt = this.receipt.toBuilder().setNetUsage(netUsage).build();
}
- public void calculateCpuFee() {
- //TODO: calculate
+ public void setNetFee(long netFee) {
+ this.receipt = this.receipt.toBuilder().setNetFee(netFee).build();
}
- public void setStorageDelta(long delta) {
- receipt.toBuilder().setCpuFee(delta);
+ public long getEnergyUsage() {
+ return this.receipt.getEnergyUsage();
}
- public void payCpuBill() {
- //TODO: pay cpu bill
+ public long getEnergyFee() {
+ return this.receipt.getEnergyFee();
}
- public void payStorageBill() {
- //TODO: pay storage bill
+ public void setEnergyUsage(long energyUsage) {
+ this.receipt = this.receipt.toBuilder().setEnergyUsage(energyUsage).build();
+ }
+
+ public void setEnergyFee(long energyFee) {
+ this.receipt = this.receipt.toBuilder().setEnergyFee(energyFee).build();
+ }
+
+ public long getOriginEnergyUsage() {
+ return this.receipt.getOriginEnergyUsage();
+ }
+
+ public long getEnergyUsageTotal() {
+ return this.receipt.getEnergyUsageTotal();
+ }
+
+ public void setOriginEnergyUsage(long energyUsage) {
+ this.receipt = this.receipt.toBuilder().setOriginEnergyUsage(energyUsage).build();
+ }
+
+ public void setEnergyUsageTotal(long energyUsage) {
+ this.receipt = this.receipt.toBuilder().setEnergyUsageTotal(energyUsage).build();
+ }
+
+ public long getNetUsage() {
+ return this.receipt.getNetUsage();
+ }
+
+ public long getNetFee() {
+ return this.receipt.getNetFee();
+ }
+
+ /**
+ * payEnergyBill pay receipt energy bill by energy processor.
+ */
+ public void payEnergyBill(Manager manager, AccountCapsule origin, AccountCapsule caller,
+ long percent, EnergyProcessor energyProcessor, long now) {
+ if (0 == receipt.getEnergyUsageTotal()) {
+ return;
+ }
+
+ if (caller.getAddress().equals(origin.getAddress())) {
+ payEnergyBill(manager, caller, receipt.getEnergyUsageTotal(), energyProcessor, now);
+ } else {
+ long originUsage = Math.multiplyExact(receipt.getEnergyUsageTotal(), percent) / 100;
+ originUsage = Math
+ .min(originUsage, energyProcessor.getAccountLeftEnergyFromFreeze(origin));
+ long callerUsage = receipt.getEnergyUsageTotal() - originUsage;
+ energyProcessor.useEnergy(origin, originUsage, now);
+ this.setOriginEnergyUsage(originUsage);
+ payEnergyBill(manager, caller, callerUsage, energyProcessor, now);
+ }
+ }
+
+ private void payEnergyBill(
+ Manager manager,
+ AccountCapsule account,
+ long usage,
+ EnergyProcessor energyProcessor,
+ long now) {
+ long accountEnergyLeft = energyProcessor.getAccountLeftEnergyFromFreeze(account);
+ if (accountEnergyLeft >= usage) {
+ energyProcessor.useEnergy(account, usage, now);
+ this.setEnergyUsage(usage);
+ } else {
+ energyProcessor.useEnergy(account, accountEnergyLeft, now);
+ long SUN_PER_ENERGY = manager.getDynamicPropertiesStore().getEnergyFee() == 0
+ ? Constant.SUN_PER_ENERGY
+ : manager.getDynamicPropertiesStore().getEnergyFee();
+ long energyFee =
+ (usage - accountEnergyLeft) * SUN_PER_ENERGY;
+ this.setEnergyUsage(accountEnergyLeft);
+ this.setEnergyFee(energyFee);
+ account.setBalance(account.getBalance() - energyFee);
+ }
+
+ manager.getAccountStore().put(account.getAddress().toByteArray(), account);
}
- public void buyStorage(long storage) {
- //TODO: buy the min storage
+ public static ResourceReceipt copyReceipt(ReceiptCapsule origin) {
+ return origin.getReceipt().toBuilder().build();
}
}
diff --git a/src/main/java/org/tron/core/capsule/StorageCapsule.java b/src/main/java/org/tron/core/capsule/StorageCapsule.java
deleted file mode 100644
index f75337d1f99..00000000000
--- a/src/main/java/org/tron/core/capsule/StorageCapsule.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * java-tron is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * java-tron is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.tron.core.capsule;
-
-import com.google.protobuf.ByteString;
-import com.google.protobuf.InvalidProtocolBufferException;
-import lombok.extern.slf4j.Slf4j;
-import org.tron.common.crypto.ECKey.ECDSASignature;
-import org.tron.common.runtime.vm.DataWord;
-import org.tron.common.utils.Sha256Hash;
-import org.tron.protos.Protocol.StorageItem;
-
-
-/**
- * @author Guo Yonggang
- * @since 28.04.2018
- */
-@Slf4j
-public class StorageCapsule implements ProtoCapsule {
-
- private StorageItem storage;
-
- public StorageCapsule(byte[] code) {
- try {
- this.storage = StorageItem.parseFrom(code);
- } catch (InvalidProtocolBufferException e) {
- //
- }
- }
-
- public StorageCapsule(StorageItem cache) {
- this.storage = cache;
- }
-
- public Sha256Hash getHash() {
- byte[] storageBytes = this.storage.toByteArray();
- return Sha256Hash.of(storageBytes);
- }
-
- public Sha256Hash getRawHash() {
- return Sha256Hash.of(this.storage.toByteArray());
- }
-
- public static String getBase64FromByteString(ByteString sign) {
- byte[] r = sign.substring(0, 32).toByteArray();
- byte[] s = sign.substring(32, 64).toByteArray();
- byte v = sign.byteAt(64);
- if (v < 27) {
- v += 27; //revId -> v
- }
- ECDSASignature signature = ECDSASignature.fromComponents(r, s, v);
- return signature.toBase64();
- }
-
- public DataWord get(DataWord key) {
- if (!this.storage.containsItems(key.toHexString())) {
- return null;
- }
-
- DataWord value = new DataWord(this.storage.getItemsMap().get(key.toHexString()).toByteArray());
- return value;
- }
-
- public void put(DataWord key, DataWord value) {
- this.storage = this.storage.toBuilder().
- putItems(key.toHexString(), ByteString.copyFrom(value.getData())).build();
- }
-
- @Override
- public byte[] getData() {
- return this.storage.toByteArray();
- }
-
- @Override
- public StorageItem getInstance() {
- return this.storage;
- }
-
- @Override
- public String toString() {
- return this.storage.toString();
- }
-}
diff --git a/src/main/java/org/tron/core/capsule/StorageRowCapsule.java b/src/main/java/org/tron/core/capsule/StorageRowCapsule.java
new file mode 100644
index 00000000000..d73da7b234e
--- /dev/null
+++ b/src/main/java/org/tron/core/capsule/StorageRowCapsule.java
@@ -0,0 +1,84 @@
+/*
+ * java-tron is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * java-tron is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.tron.core.capsule;
+
+import java.util.Arrays;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.spongycastle.util.encoders.Hex;
+import org.tron.common.runtime.vm.DataWord;
+import org.tron.common.utils.Sha256Hash;
+
+
+@Slf4j
+public class StorageRowCapsule implements ProtoCapsule {
+
+ private byte[] rowValue;
+ @Setter
+ @Getter
+ private byte[] rowKey;
+
+ @Getter
+ private boolean dirty = false;
+
+ private void markDirty() {
+ dirty = true;
+ }
+
+ private StorageRowCapsule() {
+ }
+
+ public StorageRowCapsule(byte[] rowKey, byte[] rowValue) {
+ this.rowKey = rowKey;
+ this.rowValue = rowValue;
+ markDirty();
+ }
+
+ public StorageRowCapsule(byte[] rowValue) {
+ this.rowValue = rowValue;
+ }
+
+
+ public Sha256Hash getHash() {
+ return Sha256Hash.of(this.rowValue);
+ }
+
+
+ public DataWord getValue() {
+ return new DataWord(this.rowValue);
+ }
+
+ public void setValue(DataWord value) {
+ this.rowValue = value.getData();
+ markDirty();
+ }
+
+ @Override
+ public byte[] getData() {
+ return this.rowValue;
+ }
+
+ @Override
+ public byte[] getInstance() {
+ return this.rowValue;
+ }
+
+ @Override
+ public String toString() {
+ return Arrays.toString(rowValue);
+ }
+}
diff --git a/src/main/java/org/tron/core/capsule/TransactionCapsule.java b/src/main/java/org/tron/core/capsule/TransactionCapsule.java
index 7275b00b3f8..209423bcf07 100755
--- a/src/main/java/org/tron/core/capsule/TransactionCapsule.java
+++ b/src/main/java/org/tron/core/capsule/TransactionCapsule.java
@@ -1,501 +1,526 @@
-/*
- * java-tron is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * java-tron is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.tron.core.capsule;
-
-import static org.tron.protos.Contract.AssetIssueContract;
-import static org.tron.protos.Contract.VoteAssetContract;
-import static org.tron.protos.Contract.VoteWitnessContract;
-import static org.tron.protos.Contract.WitnessCreateContract;
-import static org.tron.protos.Contract.WitnessUpdateContract;
-
-import com.google.protobuf.Any;
-import com.google.protobuf.ByteString;
-import com.google.protobuf.InvalidProtocolBufferException;
-import java.security.SignatureException;
-import java.util.Arrays;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-import lombok.Setter;
-import lombok.extern.slf4j.Slf4j;
-import org.tron.common.crypto.ECKey;
-import org.tron.common.crypto.ECKey.ECDSASignature;
-import org.tron.common.utils.ByteArray;
-import org.tron.common.utils.Sha256Hash;
-import org.tron.core.Wallet;
-import org.tron.core.db.AccountStore;
-import org.tron.core.exception.BadItemException;
-import org.tron.core.exception.ValidateSignatureException;
-import org.tron.protos.Contract;
-import org.tron.protos.Contract.AccountCreateContract;
-import org.tron.protos.Contract.AccountUpdateContract;
-import org.tron.protos.Contract.BuyStorageContract;
-import org.tron.protos.Contract.CreateSmartContract;
-import org.tron.protos.Contract.FreezeBalanceContract;
-import org.tron.protos.Contract.ParticipateAssetIssueContract;
-import org.tron.protos.Contract.ProposalApproveContract;
-import org.tron.protos.Contract.ProposalCreateContract;
-import org.tron.protos.Contract.ProposalDeleteContract;
-import org.tron.protos.Contract.SellStorageContract;
-import org.tron.protos.Contract.SetAccountIdContract;
-import org.tron.protos.Contract.TransferAssetContract;
-import org.tron.protos.Contract.TransferContract;
-import org.tron.protos.Contract.TriggerSmartContract;
-import org.tron.protos.Contract.UnfreezeAssetContract;
-import org.tron.protos.Contract.UnfreezeBalanceContract;
-import org.tron.protos.Contract.UpdateAssetContract;
-import org.tron.protos.Contract.WithdrawBalanceContract;
-import org.tron.protos.Protocol.Transaction;
-import org.tron.protos.Protocol.Transaction.Contract.ContractType;
-
-@Slf4j
-public class TransactionCapsule implements ProtoCapsule {
-
- private Transaction transaction;
- @Setter
- private boolean isVerified = false;
-
- /**
- * constructor TransactionCapsule.
- */
- public TransactionCapsule(Transaction trx) {
- this.transaction = trx;
- }
-
- /**
- * get account from bytes data.
- */
- public TransactionCapsule(byte[] data) throws BadItemException {
- try {
- this.transaction = Transaction.parseFrom(data);
- } catch (InvalidProtocolBufferException e) {
- throw new BadItemException("Transaction proto data parse exception");
- }
- }
-
- /*lll
- public TransactionCapsule(byte[] key, long value) throws IllegalArgumentException {
- if (!Wallet.addressValid(key)) {
- throw new IllegalArgumentException("Invalid address");
- }
- TransferContract transferContract = TransferContract.newBuilder()
- .setAmount(value)
- .setOwnerAddress(ByteString.copyFrom("0x0000000000000000000".getBytes()))
- .setToAddress(ByteString.copyFrom(key))
- .build();
- Transaction.raw.Builder transactionBuilder = Transaction.raw.newBuilder().addContract(
- Transaction.Contract.newBuilder().setType(ContractType.TransferContract).setParameter(
- Any.pack(transferContract)).build());
- logger.info("Transaction create succeeded!");
- transaction = Transaction.newBuilder().setRawData(transactionBuilder.build()).build();
- }*/
-
- public TransactionCapsule(AccountCreateContract contract, AccountStore accountStore) {
- AccountCapsule account = accountStore.get(contract.getOwnerAddress().toByteArray());
- if (account != null && account.getType() == contract.getType()) {
- return; // Account isexit
- }
-
- createTransaction(contract, ContractType.AccountCreateContract);
- }
-
- public TransactionCapsule(TransferContract contract, AccountStore accountStore) {
- Transaction.Contract.Builder contractBuilder = Transaction.Contract.newBuilder();
-
- AccountCapsule owner = accountStore.get(contract.getOwnerAddress().toByteArray());
- if (owner == null || owner.getBalance() < contract.getAmount()) {
- return; //The balance is not enough
- }
-
- createTransaction(contract, ContractType.TransferContract);
- }
-
- public TransactionCapsule(VoteWitnessContract voteWitnessContract) {
- createTransaction(voteWitnessContract, ContractType.VoteWitnessContract);
- }
-
- public TransactionCapsule(WitnessCreateContract witnessCreateContract) {
- createTransaction(witnessCreateContract, ContractType.WitnessCreateContract);
- }
-
- public TransactionCapsule(WitnessUpdateContract witnessUpdateContract) {
- createTransaction(witnessUpdateContract, ContractType.WitnessUpdateContract);
- }
-
- public TransactionCapsule(TransferAssetContract transferAssetContract) {
- createTransaction(transferAssetContract, ContractType.TransferAssetContract);
- }
-
- public TransactionCapsule(ParticipateAssetIssueContract participateAssetIssueContract) {
- createTransaction(participateAssetIssueContract, ContractType.ParticipateAssetIssueContract);
- }
-
- public void resetResult() {
- if (this.getInstance().getRetCount() > 0) {
- this.transaction = this.getInstance().toBuilder().clearRet().build();
- }
- }
-
- public void setResult(TransactionResultCapsule transactionResultCapsule) {
- this.transaction = this.getInstance().toBuilder().addRet(transactionResultCapsule.getInstance())
- .build();
- }
-
- public void setReference(long blockNum, byte[] blockHash) {
- byte[] refBlockNum = ByteArray.fromLong(blockNum);
- Transaction.raw rawData = this.transaction.getRawData().toBuilder()
- .setRefBlockHash(ByteString.copyFrom(ByteArray.subArray(blockHash, 8, 16)))
- .setRefBlockBytes(ByteString.copyFrom(ByteArray.subArray(refBlockNum, 6, 8)))
- .build();
- this.transaction = this.transaction.toBuilder().setRawData(rawData).build();
- }
-
- /**
- * @param expiration must be in milliseconds format
- */
- public void setExpiration(long expiration) {
- Transaction.raw rawData = this.transaction.getRawData().toBuilder().setExpiration(expiration)
- .build();
- this.transaction = this.transaction.toBuilder().setRawData(rawData).build();
- }
-
- public long getExpiration() {
- return transaction.getRawData().getExpiration();
- }
-
- public void setTimestamp() {
- Transaction.raw rawData = this.transaction.getRawData().toBuilder()
- .setTimestamp(System.currentTimeMillis())
- .build();
- this.transaction = this.transaction.toBuilder().setRawData(rawData).build();
- }
-
- public long getTimestamp() {
- return transaction.getRawData().getTimestamp();
- }
-
- @Deprecated
- public TransactionCapsule(AssetIssueContract assetIssueContract) {
- createTransaction(assetIssueContract, ContractType.AssetIssueContract);
- }
-
- public TransactionCapsule(com.google.protobuf.Message message, ContractType contractType) {
- Transaction.raw.Builder transactionBuilder = Transaction.raw.newBuilder().addContract(
- Transaction.Contract.newBuilder().setType(contractType).setParameter(
- Any.pack(message)).build());
- transaction = Transaction.newBuilder().setRawData(transactionBuilder.build()).build();
- }
-
- @Deprecated
- public void createTransaction(com.google.protobuf.Message message, ContractType contractType) {
- Transaction.raw.Builder transactionBuilder = Transaction.raw.newBuilder().addContract(
- Transaction.Contract.newBuilder().setType(contractType).setParameter(
- Any.pack(message)).build());
- transaction = Transaction.newBuilder().setRawData(transactionBuilder.build()).build();
- }
-
- public Sha256Hash getMerkleHash() {
- byte[] transBytes = this.transaction.toByteArray();
- return Sha256Hash.of(transBytes);
- }
-
- private Sha256Hash getRawHash() {
- return Sha256Hash.of(this.transaction.getRawData().toByteArray());
- }
-
- /**
- * check balance of the address.
- */
- public boolean checkBalance(byte[] address, byte[] to, long amount, long balance) {
- if (!Wallet.addressValid(address)) {
- logger.error("address invalid");
- return false;
- }
-
- if (!Wallet.addressValid(to)) {
- logger.error("address invalid");
- return false;
- }
-
- if (amount <= 0) {
- logger.error("amount required a positive number");
- return false;
- }
-
- if (amount > balance) {
- logger.error("don't have enough money");
- return false;
- }
-
- return true;
- }
-
- public void sign(byte[] privateKey) {
- ECKey ecKey = ECKey.fromPrivate(privateKey);
- ECDSASignature signature = ecKey.sign(getRawHash().getBytes());
- ByteString sig = ByteString.copyFrom(signature.toByteArray());
- this.transaction = this.transaction.toBuilder().addSignature(sig).build();
- }
-
- // todo mv this static function to capsule util
- public static byte[] getOwner(Transaction.Contract contract) {
- ByteString owner;
- try {
- Any contractParameter = contract.getParameter();
- switch (contract.getType()) {
- case AccountCreateContract:
- owner = contractParameter.unpack(AccountCreateContract.class).getOwnerAddress();
- break;
- case TransferContract:
- owner = contractParameter.unpack(TransferContract.class).getOwnerAddress();
- break;
- case TransferAssetContract:
- owner = contractParameter.unpack(TransferAssetContract.class).getOwnerAddress();
- break;
- case VoteAssetContract:
- owner = contractParameter.unpack(VoteAssetContract.class).getOwnerAddress();
- break;
- case VoteWitnessContract:
- owner = contractParameter.unpack(VoteWitnessContract.class).getOwnerAddress();
- break;
- case WitnessCreateContract:
- owner = contractParameter.unpack(WitnessCreateContract.class).getOwnerAddress();
- break;
- case AssetIssueContract:
- owner = contractParameter.unpack(AssetIssueContract.class).getOwnerAddress();
- break;
- case WitnessUpdateContract:
- owner = contractParameter.unpack(WitnessUpdateContract.class).getOwnerAddress();
- break;
- case ParticipateAssetIssueContract:
- owner = contractParameter.unpack(ParticipateAssetIssueContract.class).getOwnerAddress();
- break;
- case AccountUpdateContract:
- owner = contractParameter.unpack(AccountUpdateContract.class).getOwnerAddress();
- break;
- case FreezeBalanceContract:
- owner = contractParameter.unpack(FreezeBalanceContract.class).getOwnerAddress();
- break;
- case UnfreezeBalanceContract:
- owner = contractParameter.unpack(UnfreezeBalanceContract.class).getOwnerAddress();
- break;
- case UnfreezeAssetContract:
- owner = contractParameter.unpack(UnfreezeAssetContract.class).getOwnerAddress();
- break;
- case WithdrawBalanceContract:
- owner = contractParameter.unpack(WithdrawBalanceContract.class).getOwnerAddress();
- break;
- case CreateSmartContract:
- owner = contractParameter.unpack(Contract.CreateSmartContract.class).getOwnerAddress();
- break;
- case TriggerSmartContract:
- owner = contractParameter.unpack(Contract.TriggerSmartContract.class).getOwnerAddress();
- break;
- case UpdateAssetContract:
- owner = contractParameter.unpack(UpdateAssetContract.class).getOwnerAddress();
- break;
- case ProposalCreateContract:
- owner = contractParameter.unpack(ProposalCreateContract.class).getOwnerAddress();
- break;
- case ProposalApproveContract:
- owner = contractParameter.unpack(ProposalApproveContract.class).getOwnerAddress();
- break;
- case ProposalDeleteContract:
- owner = contractParameter.unpack(ProposalDeleteContract.class).getOwnerAddress();
- break;
- case SetAccountIdContract:
- owner = contractParameter.unpack(SetAccountIdContract.class).getOwnerAddress();
- break;
- case BuyStorageContract:
- owner = contractParameter.unpack(BuyStorageContract.class).getOwnerAddress();
- break;
- case SellStorageContract:
- owner = contractParameter.unpack(SellStorageContract.class).getOwnerAddress();
- break;
- // todo add other contract
- default:
- return null;
- }
- return owner.toByteArray();
- } catch (Exception ex) {
- logger.error(ex.getMessage());
- return null;
- }
- }
-
- // todo mv this static function to capsule util
- public static byte[] getToAddress(Transaction.Contract contract) {
- ByteString to;
- try {
- Any contractParameter = contract.getParameter();
- switch (contract.getType()) {
- case TransferContract:
- to = contractParameter.unpack(TransferContract.class).getToAddress();
- break;
- case TransferAssetContract:
- to = contractParameter.unpack(TransferAssetContract.class).getToAddress();
- break;
- case ParticipateAssetIssueContract:
- to = contractParameter.unpack(ParticipateAssetIssueContract.class).getToAddress();
- break;
- // todo add other contract
-
- default:
- return null;
- }
- return to.toByteArray();
- } catch (Exception ex) {
- logger.error(ex.getMessage());
- return null;
- }
- }
-
- // todo mv this static function to capsule util
- public static long getCpuLimitInTrx(Transaction.Contract contract) {
- int cpuForTrx;
- try {
- Any contractParameter = contract.getParameter();
- switch (contract.getType()) {
- case TriggerSmartContract:
- return contractParameter.unpack(TriggerSmartContract.class).getCpuLimitInTrx();
- case CreateSmartContract:
- return contractParameter.unpack(CreateSmartContract.class).getCpuLimitInTrx();
- default:
- return 0;
- }
- } catch (Exception ex) {
- logger.error(ex.getMessage());
- return 0;
- }
- }
-
- public static String getBase64FromByteString(ByteString sign) {
- byte[] r = sign.substring(0, 32).toByteArray();
- byte[] s = sign.substring(32, 64).toByteArray();
- byte v = sign.byteAt(64);
- if (v < 27) {
- v += 27; //revId -> v
- }
- ECDSASignature signature = ECDSASignature.fromComponents(r, s, v);
- return signature.toBase64();
- }
-
-
- /**
- * validate signature
- */
- public boolean validateSignature() throws ValidateSignatureException {
- if (isVerified == true) {
- return true;
- }
-
- if (this.getInstance().getSignatureCount() !=
- this.getInstance().getRawData().getContractCount()) {
- throw new ValidateSignatureException("miss sig or contract");
- }
-
- List listContract = this.transaction.getRawData().getContractList();
- for (int i = 0; i < this.transaction.getSignatureCount(); ++i) {
- try {
- Transaction.Contract contract = listContract.get(i);
- byte[] owner = getOwner(contract);
- byte[] address = ECKey.signatureToAddress(getRawHash().getBytes(),
- getBase64FromByteString(this.transaction.getSignature(i)));
- if (!Arrays.equals(owner, address)) {
- isVerified = false;
- throw new ValidateSignatureException("sig error");
- }
- } catch (SignatureException e) {
- isVerified = false;
- throw new ValidateSignatureException(e.getMessage());
- }
- }
-
- isVerified = true;
- return true;
- }
-
- public Sha256Hash getTransactionId() {
- return getRawHash();
- }
-
- @Override
- public byte[] getData() {
- return this.transaction.toByteArray();
- }
-
- public long getSerializedSize() {
- return this.transaction.getSerializedSize();
- }
-
- @Override
- public Transaction getInstance() {
- return this.transaction;
- }
-
- private StringBuffer toStringBuff = new StringBuffer();
-
- @Override
- public String toString() {
-
- toStringBuff.setLength(0);
- toStringBuff.append("TransactionCapsule \n[ ");
-
- toStringBuff.append("hash=").append(getTransactionId()).append("\n");
- AtomicInteger i = new AtomicInteger();
- if (!getInstance().getRawData().getContractList().isEmpty()) {
- toStringBuff.append("contract list:{ ");
- getInstance().getRawData().getContractList().forEach(contract -> {
- toStringBuff.append("[" + i + "] ").append("type: ").append(contract.getType())
- .append("\n");
- toStringBuff.append("from address=").append(getOwner(contract)).append("\n");
- toStringBuff.append("to address=").append(getToAddress(contract)).append("\n");
- if (contract.getType().equals(ContractType.TransferContract)) {
- TransferContract transferContract;
- try {
- transferContract = contract.getParameter()
- .unpack(TransferContract.class);
- toStringBuff.append("transfer amount=").append(transferContract.getAmount())
- .append("\n");
- } catch (InvalidProtocolBufferException e) {
- e.printStackTrace();
- }
- } else if (contract.getType().equals(ContractType.TransferAssetContract)) {
- TransferAssetContract transferAssetContract;
- try {
- transferAssetContract = contract.getParameter()
- .unpack(TransferAssetContract.class);
- toStringBuff.append("transfer asset=").append(transferAssetContract.getAssetName())
- .append("\n");
- toStringBuff.append("transfer amount=").append(transferAssetContract.getAmount())
- .append("\n");
- } catch (InvalidProtocolBufferException e) {
- e.printStackTrace();
- }
- }
- if (this.transaction.getSignatureList().size() >= i.get() + 1) {
- toStringBuff.append("sign=").append(getBase64FromByteString(
- this.transaction.getSignature(i.getAndIncrement()))).append("\n");
- }
- });
- toStringBuff.append("}\n");
- } else {
- toStringBuff.append("contract list is empty\n");
- }
-
- toStringBuff.append("]");
- return toStringBuff.toString();
- }
-}
+/*
+ * java-tron is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * java-tron is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.tron.core.capsule;
+
+import static org.tron.protos.Contract.AssetIssueContract;
+import static org.tron.protos.Contract.VoteAssetContract;
+import static org.tron.protos.Contract.VoteWitnessContract;
+import static org.tron.protos.Contract.WitnessCreateContract;
+import static org.tron.protos.Contract.WitnessUpdateContract;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import java.security.SignatureException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+import org.tron.common.crypto.ECKey;
+import org.tron.common.crypto.ECKey.ECDSASignature;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.Sha256Hash;
+import org.tron.core.Wallet;
+import org.tron.core.db.AccountStore;
+import org.tron.core.exception.BadItemException;
+import org.tron.core.exception.ValidateSignatureException;
+import org.tron.protos.Contract;
+import org.tron.protos.Contract.AccountCreateContract;
+import org.tron.protos.Contract.AccountUpdateContract;
+import org.tron.protos.Contract.CreateSmartContract;
+import org.tron.protos.Contract.ExchangeCreateContract;
+import org.tron.protos.Contract.ExchangeInjectContract;
+import org.tron.protos.Contract.ExchangeTransactionContract;
+import org.tron.protos.Contract.ExchangeWithdrawContract;
+import org.tron.protos.Contract.FreezeBalanceContract;
+import org.tron.protos.Contract.ParticipateAssetIssueContract;
+import org.tron.protos.Contract.ProposalApproveContract;
+import org.tron.protos.Contract.ProposalCreateContract;
+import org.tron.protos.Contract.ProposalDeleteContract;
+import org.tron.protos.Contract.SetAccountIdContract;
+import org.tron.protos.Contract.TransferAssetContract;
+import org.tron.protos.Contract.TransferContract;
+import org.tron.protos.Contract.TriggerSmartContract;
+import org.tron.protos.Contract.UnfreezeAssetContract;
+import org.tron.protos.Contract.UnfreezeBalanceContract;
+import org.tron.protos.Contract.UpdateAssetContract;
+import org.tron.protos.Contract.UpdateSettingContract;
+import org.tron.protos.Contract.WithdrawBalanceContract;
+import org.tron.protos.Protocol.Transaction;
+import org.tron.protos.Protocol.Transaction.Contract.ContractType;
+
+@Slf4j
+public class TransactionCapsule implements ProtoCapsule {
+
+ private Transaction transaction;
+ @Setter
+ private boolean isVerified = false;
+
+ /**
+ * constructor TransactionCapsule.
+ */
+ public TransactionCapsule(Transaction trx) {
+ this.transaction = trx;
+ }
+
+ /**
+ * get account from bytes data.
+ */
+ public TransactionCapsule(byte[] data) throws BadItemException {
+ try {
+ this.transaction = Transaction.parseFrom(data);
+ } catch (InvalidProtocolBufferException e) {
+ throw new BadItemException("Transaction proto data parse exception");
+ }
+ }
+
+ /*lll
+ public TransactionCapsule(byte[] key, long value) throws IllegalArgumentException {
+ if (!Wallet.addressValid(key)) {
+ throw new IllegalArgumentException("Invalid address");
+ }
+ TransferContract transferContract = TransferContract.newBuilder()
+ .setAmount(value)
+ .setOwnerAddress(ByteString.copyFrom("0x0000000000000000000".getBytes()))
+ .setToAddress(ByteString.copyFrom(key))
+ .build();
+ Transaction.raw.Builder transactionBuilder = Transaction.raw.newBuilder().addContract(
+ Transaction.Contract.newBuilder().setType(ContractType.TransferContract).setParameter(
+ Any.pack(transferContract)).build());
+ logger.info("Transaction create succeeded!");
+ transaction = Transaction.newBuilder().setRawData(transactionBuilder.build()).build();
+ }*/
+
+ public TransactionCapsule(AccountCreateContract contract, AccountStore accountStore) {
+ AccountCapsule account = accountStore.get(contract.getOwnerAddress().toByteArray());
+ if (account != null && account.getType() == contract.getType()) {
+ return; // Account isexit
+ }
+
+ createTransaction(contract, ContractType.AccountCreateContract);
+ }
+
+ public TransactionCapsule(TransferContract contract, AccountStore accountStore) {
+ Transaction.Contract.Builder contractBuilder = Transaction.Contract.newBuilder();
+
+ AccountCapsule owner = accountStore.get(contract.getOwnerAddress().toByteArray());
+ if (owner == null || owner.getBalance() < contract.getAmount()) {
+ return; //The balance is not enough
+ }
+
+ createTransaction(contract, ContractType.TransferContract);
+ }
+
+ public TransactionCapsule(VoteWitnessContract voteWitnessContract) {
+ createTransaction(voteWitnessContract, ContractType.VoteWitnessContract);
+ }
+
+ public TransactionCapsule(WitnessCreateContract witnessCreateContract) {
+ createTransaction(witnessCreateContract, ContractType.WitnessCreateContract);
+ }
+
+ public TransactionCapsule(WitnessUpdateContract witnessUpdateContract) {
+ createTransaction(witnessUpdateContract, ContractType.WitnessUpdateContract);
+ }
+
+ public TransactionCapsule(TransferAssetContract transferAssetContract) {
+ createTransaction(transferAssetContract, ContractType.TransferAssetContract);
+ }
+
+ public TransactionCapsule(ParticipateAssetIssueContract participateAssetIssueContract) {
+ createTransaction(participateAssetIssueContract, ContractType.ParticipateAssetIssueContract);
+ }
+
+ public void resetResult() {
+ if (this.getInstance().getRetCount() > 0) {
+ this.transaction = this.getInstance().toBuilder().clearRet().build();
+ }
+ }
+
+ public void setResult(TransactionResultCapsule transactionResultCapsule) {
+ this.transaction = this.getInstance().toBuilder().addRet(transactionResultCapsule.getInstance())
+ .build();
+ }
+
+ public void setReference(long blockNum, byte[] blockHash) {
+ byte[] refBlockNum = ByteArray.fromLong(blockNum);
+ Transaction.raw rawData = this.transaction.getRawData().toBuilder()
+ .setRefBlockHash(ByteString.copyFrom(ByteArray.subArray(blockHash, 8, 16)))
+ .setRefBlockBytes(ByteString.copyFrom(ByteArray.subArray(refBlockNum, 6, 8)))
+ .build();
+ this.transaction = this.transaction.toBuilder().setRawData(rawData).build();
+ }
+
+ /**
+ * @param expiration must be in milliseconds format
+ */
+ public void setExpiration(long expiration) {
+ Transaction.raw rawData = this.transaction.getRawData().toBuilder().setExpiration(expiration)
+ .build();
+ this.transaction = this.transaction.toBuilder().setRawData(rawData).build();
+ }
+
+ public long getExpiration() {
+ return transaction.getRawData().getExpiration();
+ }
+
+ public void setTimestamp() {
+ Transaction.raw rawData = this.transaction.getRawData().toBuilder()
+ .setTimestamp(System.currentTimeMillis())
+ .build();
+ this.transaction = this.transaction.toBuilder().setRawData(rawData).build();
+ }
+
+ public long getTimestamp() {
+ return transaction.getRawData().getTimestamp();
+ }
+
+ @Deprecated
+ public TransactionCapsule(AssetIssueContract assetIssueContract) {
+ createTransaction(assetIssueContract, ContractType.AssetIssueContract);
+ }
+
+ public TransactionCapsule(com.google.protobuf.Message message, ContractType contractType) {
+ Transaction.raw.Builder transactionBuilder = Transaction.raw.newBuilder().addContract(
+ Transaction.Contract.newBuilder().setType(contractType).setParameter(
+ Any.pack(message)).build());
+ transaction = Transaction.newBuilder().setRawData(transactionBuilder.build()).build();
+ }
+
+ @Deprecated
+ public void createTransaction(com.google.protobuf.Message message, ContractType contractType) {
+ Transaction.raw.Builder transactionBuilder = Transaction.raw.newBuilder().addContract(
+ Transaction.Contract.newBuilder().setType(contractType).setParameter(
+ Any.pack(message)).build());
+ transaction = Transaction.newBuilder().setRawData(transactionBuilder.build()).build();
+ }
+
+ public Sha256Hash getMerkleHash() {
+ byte[] transBytes = this.transaction.toByteArray();
+ return Sha256Hash.of(transBytes);
+ }
+
+ private Sha256Hash getRawHash() {
+ return Sha256Hash.of(this.transaction.getRawData().toByteArray());
+ }
+
+ /**
+ * check balance of the address.
+ */
+ public boolean checkBalance(byte[] address, byte[] to, long amount, long balance) {
+ if (!Wallet.addressValid(address)) {
+ logger.error("address invalid");
+ return false;
+ }
+
+ if (!Wallet.addressValid(to)) {
+ logger.error("address invalid");
+ return false;
+ }
+
+ if (amount <= 0) {
+ logger.error("amount required a positive number");
+ return false;
+ }
+
+ if (amount > balance) {
+ logger.error("don't have enough money");
+ return false;
+ }
+
+ return true;
+ }
+
+ public void sign(byte[] privateKey) {
+ ECKey ecKey = ECKey.fromPrivate(privateKey);
+ ECDSASignature signature = ecKey.sign(getRawHash().getBytes());
+ ByteString sig = ByteString.copyFrom(signature.toByteArray());
+ this.transaction = this.transaction.toBuilder().addSignature(sig).build();
+ }
+
+ // todo mv this static function to capsule util
+ public static byte[] getOwner(Transaction.Contract contract) {
+ ByteString owner;
+ try {
+ Any contractParameter = contract.getParameter();
+ switch (contract.getType()) {
+ case AccountCreateContract:
+ owner = contractParameter.unpack(AccountCreateContract.class).getOwnerAddress();
+ break;
+ case TransferContract:
+ owner = contractParameter.unpack(TransferContract.class).getOwnerAddress();
+ break;
+ case TransferAssetContract:
+ owner = contractParameter.unpack(TransferAssetContract.class).getOwnerAddress();
+ break;
+ case VoteAssetContract:
+ owner = contractParameter.unpack(VoteAssetContract.class).getOwnerAddress();
+ break;
+ case VoteWitnessContract:
+ owner = contractParameter.unpack(VoteWitnessContract.class).getOwnerAddress();
+ break;
+ case WitnessCreateContract:
+ owner = contractParameter.unpack(WitnessCreateContract.class).getOwnerAddress();
+ break;
+ case AssetIssueContract:
+ owner = contractParameter.unpack(AssetIssueContract.class).getOwnerAddress();
+ break;
+ case WitnessUpdateContract:
+ owner = contractParameter.unpack(WitnessUpdateContract.class).getOwnerAddress();
+ break;
+ case ParticipateAssetIssueContract:
+ owner = contractParameter.unpack(ParticipateAssetIssueContract.class).getOwnerAddress();
+ break;
+ case AccountUpdateContract:
+ owner = contractParameter.unpack(AccountUpdateContract.class).getOwnerAddress();
+ break;
+ case FreezeBalanceContract:
+ owner = contractParameter.unpack(FreezeBalanceContract.class).getOwnerAddress();
+ break;
+ case UnfreezeBalanceContract:
+ owner = contractParameter.unpack(UnfreezeBalanceContract.class).getOwnerAddress();
+ break;
+ case UnfreezeAssetContract:
+ owner = contractParameter.unpack(UnfreezeAssetContract.class).getOwnerAddress();
+ break;
+ case WithdrawBalanceContract:
+ owner = contractParameter.unpack(WithdrawBalanceContract.class).getOwnerAddress();
+ break;
+ case CreateSmartContract:
+ owner = contractParameter.unpack(Contract.CreateSmartContract.class).getOwnerAddress();
+ break;
+ case TriggerSmartContract:
+ owner = contractParameter.unpack(Contract.TriggerSmartContract.class).getOwnerAddress();
+ break;
+ case UpdateAssetContract:
+ owner = contractParameter.unpack(UpdateAssetContract.class).getOwnerAddress();
+ break;
+ case ProposalCreateContract:
+ owner = contractParameter.unpack(ProposalCreateContract.class).getOwnerAddress();
+ break;
+ case ProposalApproveContract:
+ owner = contractParameter.unpack(ProposalApproveContract.class).getOwnerAddress();
+ break;
+ case ProposalDeleteContract:
+ owner = contractParameter.unpack(ProposalDeleteContract.class).getOwnerAddress();
+ break;
+ case SetAccountIdContract:
+ owner = contractParameter.unpack(SetAccountIdContract.class).getOwnerAddress();
+ break;
+// case BuyStorageContract:
+// owner = contractParameter.unpack(BuyStorageContract.class).getOwnerAddress();
+// break;
+// case BuyStorageBytesContract:
+// owner = contractParameter.unpack(BuyStorageBytesContract.class).getOwnerAddress();
+// break;
+// case SellStorageContract:
+// owner = contractParameter.unpack(SellStorageContract.class).getOwnerAddress();
+// break;
+ case UpdateSettingContract:
+ owner = contractParameter.unpack(UpdateSettingContract.class)
+ .getOwnerAddress();
+ break;
+ case ExchangeCreateContract:
+ owner = contractParameter.unpack(ExchangeCreateContract.class).getOwnerAddress();
+ break;
+ case ExchangeInjectContract:
+ owner = contractParameter.unpack(ExchangeInjectContract.class).getOwnerAddress();
+ break;
+ case ExchangeWithdrawContract:
+ owner = contractParameter.unpack(ExchangeWithdrawContract.class).getOwnerAddress();
+ break;
+ case ExchangeTransactionContract:
+ owner = contractParameter.unpack(ExchangeTransactionContract.class).getOwnerAddress();
+ break;
+ // todo add other contract
+ default:
+ return null;
+ }
+ return owner.toByteArray();
+ } catch (Exception ex) {
+ logger.error(ex.getMessage());
+ return null;
+ }
+ }
+
+ // todo mv this static function to capsule util
+ public static byte[] getToAddress(Transaction.Contract contract) {
+ ByteString to;
+ try {
+ Any contractParameter = contract.getParameter();
+ switch (contract.getType()) {
+ case TransferContract:
+ to = contractParameter.unpack(TransferContract.class).getToAddress();
+ break;
+ case TransferAssetContract:
+ to = contractParameter.unpack(TransferAssetContract.class).getToAddress();
+ break;
+ case ParticipateAssetIssueContract:
+ to = contractParameter.unpack(ParticipateAssetIssueContract.class).getToAddress();
+ break;
+ // todo add other contract
+
+ default:
+ return null;
+ }
+ return to.toByteArray();
+ } catch (Exception ex) {
+ logger.error(ex.getMessage());
+ return null;
+ }
+ }
+
+ // todo mv this static function to capsule util
+ public static long getCallValue(Transaction.Contract contract) {
+ int energyForTrx;
+ try {
+ Any contractParameter = contract.getParameter();
+ long callValue;
+ switch (contract.getType()) {
+ case TriggerSmartContract:
+ return contractParameter.unpack(TriggerSmartContract.class).getCallValue();
+
+ case CreateSmartContract:
+ return contractParameter.unpack(CreateSmartContract.class).getNewContract()
+ .getCallValue();
+ default:
+ return 0L;
+ }
+ } catch (Exception ex) {
+ logger.error(ex.getMessage());
+ return 0L;
+ }
+ }
+
+ public static String getBase64FromByteString(ByteString sign) {
+ byte[] r = sign.substring(0, 32).toByteArray();
+ byte[] s = sign.substring(32, 64).toByteArray();
+ byte v = sign.byteAt(64);
+ if (v < 27) {
+ v += 27; //revId -> v
+ }
+ ECDSASignature signature = ECDSASignature.fromComponents(r, s, v);
+ return signature.toBase64();
+ }
+
+
+ /**
+ * validate signature
+ */
+ public boolean validateSignature() throws ValidateSignatureException {
+ if (isVerified == true) {
+ return true;
+ }
+
+ if (this.getInstance().getSignatureCount() !=
+ this.getInstance().getRawData().getContractCount()) {
+ throw new ValidateSignatureException("miss sig or contract");
+ }
+
+ List listContract = this.transaction.getRawData().getContractList();
+ for (int i = 0; i < this.transaction.getSignatureCount(); ++i) {
+ try {
+ Transaction.Contract contract = listContract.get(i);
+ byte[] owner = getOwner(contract);
+ byte[] address = ECKey.signatureToAddress(getRawHash().getBytes(),
+ getBase64FromByteString(this.transaction.getSignature(i)));
+ if (!Arrays.equals(owner, address)) {
+ isVerified = false;
+ throw new ValidateSignatureException("sig error");
+ }
+ } catch (SignatureException e) {
+ isVerified = false;
+ throw new ValidateSignatureException(e.getMessage());
+ }
+ }
+
+ isVerified = true;
+ return true;
+ }
+
+ public Sha256Hash getTransactionId() {
+ return getRawHash();
+ }
+
+ @Override
+ public byte[] getData() {
+ return this.transaction.toByteArray();
+ }
+
+ public long getSerializedSize() {
+ return this.transaction.getSerializedSize();
+ }
+
+ @Override
+ public Transaction getInstance() {
+ return this.transaction;
+ }
+
+ private StringBuffer toStringBuff = new StringBuffer();
+
+ @Override
+ public String toString() {
+
+ toStringBuff.setLength(0);
+ toStringBuff.append("TransactionCapsule \n[ ");
+
+ toStringBuff.append("hash=").append(getTransactionId()).append("\n");
+ AtomicInteger i = new AtomicInteger();
+ if (!getInstance().getRawData().getContractList().isEmpty()) {
+ toStringBuff.append("contract list:{ ");
+ getInstance().getRawData().getContractList().forEach(contract -> {
+ toStringBuff.append("[" + i + "] ").append("type: ").append(contract.getType())
+ .append("\n");
+ toStringBuff.append("from address=").append(getOwner(contract)).append("\n");
+ toStringBuff.append("to address=").append(getToAddress(contract)).append("\n");
+ if (contract.getType().equals(ContractType.TransferContract)) {
+ TransferContract transferContract;
+ try {
+ transferContract = contract.getParameter()
+ .unpack(TransferContract.class);
+ toStringBuff.append("transfer amount=").append(transferContract.getAmount())
+ .append("\n");
+ } catch (InvalidProtocolBufferException e) {
+ e.printStackTrace();
+ }
+ } else if (contract.getType().equals(ContractType.TransferAssetContract)) {
+ TransferAssetContract transferAssetContract;
+ try {
+ transferAssetContract = contract.getParameter()
+ .unpack(TransferAssetContract.class);
+ toStringBuff.append("transfer asset=").append(transferAssetContract.getAssetName())
+ .append("\n");
+ toStringBuff.append("transfer amount=").append(transferAssetContract.getAmount())
+ .append("\n");
+ } catch (InvalidProtocolBufferException e) {
+ e.printStackTrace();
+ }
+ }
+ if (this.transaction.getSignatureList().size() >= i.get() + 1) {
+ toStringBuff.append("sign=").append(getBase64FromByteString(
+ this.transaction.getSignature(i.getAndIncrement()))).append("\n");
+ }
+ });
+ toStringBuff.append("}\n");
+ } else {
+ toStringBuff.append("contract list is empty\n");
+ }
+
+ toStringBuff.append("]");
+ return toStringBuff.toString();
+ }
+}
diff --git a/src/main/java/org/tron/core/capsule/TransactionInfoCapsule.java b/src/main/java/org/tron/core/capsule/TransactionInfoCapsule.java
index 8ed29ac6c5e..4670d9067f5 100644
--- a/src/main/java/org/tron/core/capsule/TransactionInfoCapsule.java
+++ b/src/main/java/org/tron/core/capsule/TransactionInfoCapsule.java
@@ -2,9 +2,19 @@
import com.google.protobuf.ByteString;
import com.google.protobuf.InvalidProtocolBufferException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.tron.common.runtime.Runtime;
+import org.tron.common.runtime.vm.LogInfo;
+import org.tron.common.runtime.vm.program.ProgramResult;
import org.tron.core.exception.BadItemException;
+import org.tron.protos.Protocol.Block;
import org.tron.protos.Protocol.TransactionInfo;
+import org.tron.protos.Protocol.TransactionInfo.Log;
+import org.tron.protos.Protocol.TransactionInfo.code;
@Slf4j
public class TransactionInfoCapsule implements ProtoCapsule {
@@ -43,10 +53,36 @@ public byte[] getId() {
return transactionInfo.getId().toByteArray();
}
+
+ public void setUnfreezeAmount(long amount) {
+ this.transactionInfo = this.transactionInfo.toBuilder().setUnfreezeAmount(amount).build();
+ }
+
+ public long getUnfreezeAmount() {
+ return transactionInfo.getUnfreezeAmount();
+ }
+
+ public void setWithdrawAmount(long amount) {
+ this.transactionInfo = this.transactionInfo.toBuilder().setWithdrawAmount(amount).build();
+ }
+
+ public long getWithdrawAmount() {
+ return transactionInfo.getWithdrawAmount();
+ }
+
public void setFee(long fee) {
this.transactionInfo = this.transactionInfo.toBuilder().setFee(fee).build();
}
+ public void setResult(code result) {
+ this.transactionInfo = this.transactionInfo.toBuilder().setResult(result).build();
+ }
+
+ public void setResMessage(String message) {
+ this.transactionInfo = this.transactionInfo.toBuilder()
+ .setResMessage(ByteString.copyFromUtf8(message)).build();
+ }
+
public void addFee(long fee) {
this.transactionInfo = this.transactionInfo.toBuilder()
.setFee(this.transactionInfo.getFee() + fee).build();
@@ -78,8 +114,21 @@ public void setContractResult(byte[] ret) {
public void setContractAddress(byte[] contractAddress) {
this.transactionInfo = this.transactionInfo.toBuilder()
- .setContractAddress(ByteString.copyFrom(contractAddress))
- .build();
+ .setContractAddress(ByteString.copyFrom(contractAddress))
+ .build();
+ }
+
+ public void setReceipt(ReceiptCapsule receipt) {
+ this.transactionInfo = this.transactionInfo.toBuilder()
+ .setReceipt(receipt.getReceipt())
+ .build();
+ }
+
+
+ public void addAllLog(List logs) {
+ this.transactionInfo = this.transactionInfo.toBuilder()
+ .addAllLog(logs)
+ .build();
}
@Override
@@ -91,4 +140,45 @@ public byte[] getData() {
public TransactionInfo getInstance() {
return this.transactionInfo;
}
+
+ public static TransactionInfoCapsule buildInstance(TransactionCapsule trxCap, Block block,
+ Runtime runtime, ReceiptCapsule traceReceipt) {
+
+ TransactionInfo.Builder builder = TransactionInfo.newBuilder();
+
+ builder.setResult(code.SUCESS);
+ if (StringUtils.isNoneEmpty(runtime.getRuntimeError())) {
+ builder.setResult(code.FAILED);
+ builder.setResMessage(ByteString.copyFromUtf8(runtime.getRuntimeError()));
+ }
+ builder.setId(ByteString.copyFrom(trxCap.getTransactionId().getBytes()));
+
+ ProgramResult programResult = runtime.getResult();
+ long fee = programResult.getRet().getFee() + traceReceipt.getEnergyFee();
+ ByteString contractResult = ByteString.copyFrom(programResult.getHReturn());
+ ByteString ContractAddress = ByteString.copyFrom(programResult.getContractAddress());
+
+ builder.setFee(fee);
+ builder.addContractResult(contractResult);
+ builder.setContractAddress(ContractAddress);
+ builder.setUnfreezeAmount(programResult.getRet().getUnfreezeAmount());
+ builder.setWithdrawAmount(programResult.getRet().getWithdrawAmount());
+
+ List logList = new ArrayList<>();
+ programResult.getLogInfoList().forEach(
+ logInfo -> {
+ logList.add(LogInfo.buildLog(logInfo));
+ }
+ );
+ builder.addAllLog(logList);
+
+ if (Objects.nonNull(block)) {
+ builder.setBlockNumber(block.getBlockHeader().getRawData().getNumber());
+ builder.setBlockTimeStamp(block.getBlockHeader().getRawData().getTimestamp());
+ }
+
+ builder.setReceipt(traceReceipt.getReceipt());
+
+ return new TransactionInfoCapsule(builder.build());
+ }
}
\ No newline at end of file
diff --git a/src/main/java/org/tron/core/capsule/TransactionResultCapsule.java b/src/main/java/org/tron/core/capsule/TransactionResultCapsule.java
index 13e79f763e7..5582b679445 100644
--- a/src/main/java/org/tron/core/capsule/TransactionResultCapsule.java
+++ b/src/main/java/org/tron/core/capsule/TransactionResultCapsule.java
@@ -46,17 +46,24 @@ public long getFee() {
return transactionResult.getFee();
}
- public void setFee(long fee) {
- this.transactionResult = this.transactionResult.toBuilder().setFee(fee).build();
+ public void setUnfreezeAmount(long amount) {
+ this.transactionResult = this.transactionResult.toBuilder().setUnfreezeAmount(amount).build();
}
- public byte[] getConstantResult() {
- return transactionResult.getConstantResult().toByteArray();
+ public long getUnfreezeAmount() {
+ return transactionResult.getUnfreezeAmount();
}
- public void setConstantResult(byte[] constantResult) {
- this.transactionResult = this.transactionResult.toBuilder()
- .setConstantResult(ByteString.copyFrom(constantResult)).build();
+ public void setWithdrawAmount(long amount) {
+ this.transactionResult = this.transactionResult.toBuilder().setWithdrawAmount(amount).build();
+ }
+
+ public long getWithdrawAmount() {
+ return transactionResult.getWithdrawAmount();
+ }
+
+ public void setFee(long fee) {
+ this.transactionResult = this.transactionResult.toBuilder().setFee(fee).build();
}
public void addFee(long fee) {
diff --git a/src/main/java/org/tron/core/capsule/utils/ExchangeProcessor.java b/src/main/java/org/tron/core/capsule/utils/ExchangeProcessor.java
new file mode 100644
index 00000000000..65a46f1a876
--- /dev/null
+++ b/src/main/java/org/tron/core/capsule/utils/ExchangeProcessor.java
@@ -0,0 +1,62 @@
+package org.tron.core.capsule.utils;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class ExchangeProcessor {
+
+ private long supply;
+
+ public ExchangeProcessor(long supply) {
+ this.supply = supply;
+ }
+
+ private long exchange_to_supply(long balance, long quant) {
+ logger.info("balance: " + balance);
+ long newBalance = balance + quant;
+ logger.info("balance + quant: " + newBalance);
+
+ double issuedSupply = -supply * (1.0 - Math.pow(1.0 + (double) quant / newBalance, 0.0005));
+ logger.info("issuedSupply: " + issuedSupply);
+ long out = (long) issuedSupply;
+ supply += out;
+
+ return out;
+ }
+
+ private long exchange_to_supply2(long balance, long quant) {
+ logger.info("balance: " + balance);
+ long newBalance = balance - quant;
+ logger.info("balance - quant: " + (balance - quant));
+
+ double issuedSupply = -supply * (1.0 - Math.pow(1.0 + (double) quant / newBalance, 0.0005));
+ logger.info("issuedSupply: " + issuedSupply);
+ long out = (long) issuedSupply;
+ supply += out;
+
+ return out;
+ }
+
+ private long exchange_from_supply(long balance, long supplyQuant) {
+ supply -= supplyQuant;
+
+ double exchangeBalance =
+ balance * (Math.pow(1.0 + (double) supplyQuant / supply, 2000.0) - 1.0);
+ logger.info("exchangeBalance: " + exchangeBalance);
+ long out = (long) exchangeBalance;
+ long newBalance = balance - out;
+
+// if (isTRX) {
+// out = Math.round(exchangeBalance / 100000) * 100000;
+// logger.info("---out: " + out);
+// }
+
+ return out;
+ }
+
+ public long exchange(long sellTokenBalance, long buyTokenBalance, long sellTokenQuant) {
+ long relay = exchange_to_supply(sellTokenBalance, sellTokenQuant);
+ return exchange_from_supply(buyTokenBalance, relay);
+ }
+
+}
diff --git a/src/main/java/org/tron/core/config/Parameter.java b/src/main/java/org/tron/core/config/Parameter.java
index ba844f71b78..7b0cdfc7a95 100644
--- a/src/main/java/org/tron/core/config/Parameter.java
+++ b/src/main/java/org/tron/core/config/Parameter.java
@@ -23,7 +23,7 @@ interface ChainConstant {
int BLOCK_FILLED_SLOTS_NUMBER = 128;
int MAX_VOTE_NUMBER = 30;
int MAX_FROZEN_NUMBER = 1;
-
+ int version = 1;
}
interface NodeConstant {
@@ -57,15 +57,17 @@ interface DatabaseConstants {
}
enum ChainParameters {
- MAINTENANCE_TIME_INTERVAL, //ms
- ACCOUNT_UPGRADE_COST, //drop
- CREATE_ACCOUNT_FEE, //drop
- TRANSACTION_FEE, //drop
- ASSET_ISSUE_FEE, //drop
- WITNESS_PAY_PER_BLOCK, //drop
- WITNESS_STANDBY_ALLOWANCE, //drop
- CREATE_NEW_ACCOUNT_FEE_IN_SYSTEM_CONTRACT, //drop
- CREATE_NEW_ACCOUNT_BANDWIDTH_RATE, // 1 ~
+ MAINTENANCE_TIME_INTERVAL, //ms ,0
+ ACCOUNT_UPGRADE_COST, //drop ,1
+ CREATE_ACCOUNT_FEE, //drop ,2
+ TRANSACTION_FEE, //drop ,3
+ ASSET_ISSUE_FEE, //drop ,4
+ WITNESS_PAY_PER_BLOCK, //drop ,5
+ WITNESS_STANDBY_ALLOWANCE, //drop ,6
+ CREATE_NEW_ACCOUNT_FEE_IN_SYSTEM_CONTRACT, //drop ,7
+ CREATE_NEW_ACCOUNT_BANDWIDTH_RATE, // 1 ~ ,8
+ ALLOW_CREATION_OF_CONTRACTS, // 0 / >0 ,9
+ REMOVE_THE_POWER_OF_THE_GR // 1 ,10
// ONE_DAY_NET_LIMIT,
// MAX_FROZEN_TIME,
// MIN_FROZEN_TIME,
diff --git a/src/main/java/org/tron/core/config/args/Args.java b/src/main/java/org/tron/core/config/args/Args.java
index b96c2a6bff3..09248fd33ae 100644
--- a/src/main/java/org/tron/core/config/args/Args.java
+++ b/src/main/java/org/tron/core/config/args/Args.java
@@ -34,7 +34,6 @@
import org.tron.common.crypto.ECKey;
import org.tron.common.overlay.discover.node.Node;
import org.tron.common.utils.ByteArray;
-import org.tron.common.utils.StringUtil;
import org.tron.core.Constant;
import org.tron.core.Wallet;
import org.tron.core.config.Configuration;
@@ -66,6 +65,11 @@ public class Args {
@Parameter(names = {"-w", "--witness"})
private boolean witness = false;
+ @Getter
+ @Setter
+ @Parameter(names = {"--debug"})
+ private boolean debug = false;
+
@Getter
@Parameter(description = "--seed-nodes")
private List seedNodes = new ArrayList<>();
@@ -273,6 +277,22 @@ public class Args {
@Setter
private double activeConnectFactor;
+ @Getter
+ @Setter
+ private double disconnectNumberFactor;
+
+ @Getter
+ @Setter
+ private double maxConnectNumberFactor;
+
+ @Getter
+ @Setter
+ private long receiveTcpMinDataLength;
+
+ @Getter
+ @Setter
+ private boolean isOpenFullTcpDisconnect;
+
public static void clearParam() {
INSTANCE.outputDirectory = "output-directory";
INSTANCE.help = false;
@@ -324,6 +344,10 @@ public static void clearParam() {
INSTANCE.walletExtensionApi = false;
INSTANCE.connectFactor = 0.3;
INSTANCE.activeConnectFactor = 0.1;
+ INSTANCE.disconnectNumberFactor = 0.4;
+ INSTANCE.maxConnectNumberFactor = 0.8;
+ INSTANCE.receiveTcpMinDataLength = 2048;
+ INSTANCE.isOpenFullTcpDisconnect = false;
}
/**
@@ -545,6 +569,15 @@ public static void setParam(final String[] args, final String confFileName) {
INSTANCE.activeConnectFactor = config.hasPath("node.activeConnectFactor") ?
config.getDouble("node.activeConnectFactor") : 0.1;
+ INSTANCE.disconnectNumberFactor = config.hasPath("node.disconnectNumberFactor") ?
+ config.getDouble("node.disconnectNumberFactor") : 0.4;
+ INSTANCE.maxConnectNumberFactor = config.hasPath("node.maxConnectNumberFactor") ?
+ config.getDouble("node.maxConnectNumberFactor") : 0.8;
+ INSTANCE.receiveTcpMinDataLength = config.hasPath("node.receiveTcpMinDataLength") ?
+ config.getLong("node.receiveTcpMinDataLength") : 2048;
+ INSTANCE.isOpenFullTcpDisconnect = config.hasPath("node.isOpenFullTcpDisconnect") && config
+ .getBoolean("node.isOpenFullTcpDisconnect");
+
initBackupProperty(config);
logConfig();
diff --git a/src/main/java/org/tron/core/db/AccountContractIndexStore.java b/src/main/java/org/tron/core/db/AccountContractIndexStore.java
deleted file mode 100644
index 044ed4bbafa..00000000000
--- a/src/main/java/org/tron/core/db/AccountContractIndexStore.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.tron.core.db;
-
-import java.util.Objects;
-import org.apache.commons.lang3.ArrayUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.tron.core.capsule.BytesCapsule;
-
-@Component
-public class AccountContractIndexStore extends TronStoreWithRevoking {
-
- @Autowired
- public AccountContractIndexStore(@Value("account-contract-index") String dbName) {
- super(dbName);
- }
-
- @Override
- public BytesCapsule get(byte[] key) {
- byte[] value = revokingDB.getUnchecked(key);
- if (Objects.nonNull(value)) {
- return new BytesCapsule(value);
- }
- return null;
- }
-
- public void put(BytesCapsule normalAccountAddress, BytesCapsule contractAddress) {
- super.put(normalAccountAddress.getData(), contractAddress);
- }
-
- @Override
- public boolean has(byte[] key) {
- byte[] value = revokingDB.getUnchecked(key);
- if (ArrayUtils.isEmpty(value)) {
- return false;
- }
- return true;
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/org/tron/core/db/BandwidthProcessor.java b/src/main/java/org/tron/core/db/BandwidthProcessor.java
index 553213db348..e3169e0fecd 100644
--- a/src/main/java/org/tron/core/db/BandwidthProcessor.java
+++ b/src/main/java/org/tron/core/db/BandwidthProcessor.java
@@ -12,9 +12,7 @@
import org.tron.core.capsule.AssetIssueCapsule;
import org.tron.core.capsule.TransactionCapsule;
import org.tron.core.capsule.TransactionResultCapsule;
-import org.tron.core.config.Parameter.ChainConstant;
import org.tron.core.exception.AccountResourceInsufficientException;
-import org.tron.core.exception.BalanceInsufficientException;
import org.tron.core.exception.ContractValidateException;
import org.tron.protos.Contract.TransferAssetContract;
import org.tron.protos.Contract.TransferContract;
@@ -50,7 +48,8 @@ private void updateUsage(AccountCapsule accountCapsule, long now) {
}
@Override
- public void consume(TransactionCapsule trx, TransactionResultCapsule ret)
+ public void consume(TransactionCapsule trx, TransactionResultCapsule ret,
+ TransactionTrace trace)
throws ContractValidateException, AccountResourceInsufficientException {
List contracts =
trx.getInstance().getRawData().getContractList();
@@ -58,15 +57,17 @@ public void consume(TransactionCapsule trx, TransactionResultCapsule ret)
for (Contract contract : contracts) {
long bytes = trx.getSerializedSize();
logger.debug("trxId {},bandwidth cost :{}", trx.getTransactionId(), bytes);
+ trace.setNetBill(bytes, 0);
byte[] address = TransactionCapsule.getOwner(contract);
AccountCapsule accountCapsule = dbManager.getAccountStore().get(address);
- if (accountCapsule == null) {
+ if (accountCapsule == null) {
throw new ContractValidateException("account not exists");
}
long now = dbManager.getWitnessController().getHeadSlot();
if (contractCreateNewAccount(contract)) {
consumeForCreateNewAccount(accountCapsule, bytes, now, ret);
+ trace.setNetBill(0, ret.getFee());
continue;
}
@@ -85,6 +86,7 @@ public void consume(TransactionCapsule trx, TransactionResultCapsule ret)
}
if (useTransactionFee(accountCapsule, bytes, ret)) {
+ trace.setNetBill(0, ret.getFee());
continue;
}
@@ -135,7 +137,8 @@ public boolean consumeBandwidthForCreateNewAccount(AccountCapsule accountCapsule
if (bytes * createNewAccountBandwidthRatio <= (netLimit - newNetUsage)) {
latestConsumeTime = now;
long latestOperationTime = dbManager.getHeadBlockTimeStamp();
- newNetUsage = increase(newNetUsage, bytes * createNewAccountBandwidthRatio, latestConsumeTime, now);
+ newNetUsage = increase(newNetUsage, bytes * createNewAccountBandwidthRatio, latestConsumeTime,
+ now);
accountCapsule.setLatestConsumeTime(latestConsumeTime);
accountCapsule.setLatestOperationTime(latestOperationTime);
accountCapsule.setNetUsage(newNetUsage);
diff --git a/src/main/java/org/tron/core/db/DynamicPropertiesStore.java b/src/main/java/org/tron/core/db/DynamicPropertiesStore.java
index ea8a04d4982..3d273c66b46 100755
--- a/src/main/java/org/tron/core/db/DynamicPropertiesStore.java
+++ b/src/main/java/org/tron/core/db/DynamicPropertiesStore.java
@@ -9,7 +9,6 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
-import org.tron.common.runtime.vm.PrecompiledContracts;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.Sha256Hash;
import org.tron.core.capsule.BytesCapsule;
@@ -32,6 +31,8 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking
private static final byte[] LATEST_PROPOSAL_NUM = "LATEST_PROPOSAL_NUM".getBytes();
+ private static final byte[] LATEST_EXCHANGE_NUM = "LATEST_EXCHANGE_NUM".getBytes();
+
private static final byte[] BLOCK_FILLED_SLOTS = "BLOCK_FILLED_SLOTS".getBytes();
private static final byte[] BLOCK_FILLED_SLOTS_INDEX = "BLOCK_FILLED_SLOTS_INDEX".getBytes();
@@ -74,9 +75,11 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking
//ONE_DAY_NET_LIMIT - PUBLIC_NET_LIMIT
private static final byte[] TOTAL_NET_LIMIT = "TOTAL_NET_LIMIT".getBytes();
- private static final byte[] TOTAL_CPU_WEIGHT = "TOTAL_CPU_WEIGHT".getBytes();
+ private static final byte[] TOTAL_ENERGY_WEIGHT = "TOTAL_ENERGY_WEIGHT".getBytes();
+
+ private static final byte[] TOTAL_ENERGY_LIMIT = "TOTAL_ENERGY_LIMIT".getBytes();
- private static final byte[] TOTAL_CPU_LIMIT = "TOTAL_CPU_LIMIT".getBytes();
+ private static final byte[] ENERGY_FEE = "ENERGY_FEE".getBytes();
//abandon
private static final byte[] CREATE_ACCOUNT_FEE = "CREATE_ACCOUNT_FEE".getBytes();
@@ -91,6 +94,10 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking
private static final byte[] ASSET_ISSUE_FEE = "ASSET_ISSUE_FEE".getBytes();
+ private static final byte[] EXCHANGE_CREATE_FEE = "EXCHANGE_CREATE_FEE".getBytes();
+
+ private static final byte[] EXCHANGE_BALANCE_LIMIT = "EXCHANGE_BALANCE_LIMIT".getBytes();
+
private static final byte[] TOTAL_TRANSACTION_COST = "TOTAL_TRANSACTION_COST".getBytes();
private static final byte[] TOTAL_CREATE_ACCOUNT_COST = "TOTAL_CREATE_ACCOUNT_COST".getBytes();
@@ -105,6 +112,16 @@ public class DynamicPropertiesStore extends TronStoreWithRevoking
private static final byte[] STORAGE_EXCHANGE_TAX_RATE = "STORAGE_EXCHANGE_TAX_RATE".getBytes();
+ private static final byte[] FORK_CONTROLLER = "FORK_CONTROLLER".getBytes();
+
+ //This value is only allowed to be 0, 1, -1
+ private static final byte[] REMOVE_THE_POWER_OF_THE_GR = "REMOVE_THE_POWER_OF_THE_GR".getBytes();
+
+ //If the parameter is larger than 0, the contract is allowed to be created.
+ private static final byte[] ALLOW_CREATION_OF_CONTRACTS = "ALLOW_CREATION_OF_CONTRACTS"
+ .getBytes();
+
+
@Autowired
private DynamicPropertiesStore(@Value("properties") String dbName) {
super(dbName);
@@ -145,6 +162,12 @@ private DynamicPropertiesStore(@Value("properties") String dbName) {
this.saveLatestProposalNum(0);
}
+ try {
+ this.getLatestExchangeNum();
+ } catch (IllegalArgumentException e) {
+ this.saveLatestExchangeNum(0);
+ }
+
try {
this.getBlockFilledSlotsIndex();
} catch (IllegalArgumentException e) {
@@ -254,15 +277,21 @@ private DynamicPropertiesStore(@Value("properties") String dbName) {
}
try {
- this.getTotalCpuWeight();
+ this.getTotalEnergyWeight();
+ } catch (IllegalArgumentException e) {
+ this.saveTotalEnergyWeight(0L);
+ }
+
+ try {
+ this.getTotalEnergyLimit();
} catch (IllegalArgumentException e) {
- this.saveTotalCpuWeight(0L);
+ this.saveTotalEnergyLimit(50_000_000_000L);
}
try {
- this.getTotalCpuLimit();
+ this.getEnergyFee();
} catch (IllegalArgumentException e) {
- this.saveTotalCpuLimit(32400_000_000L);
+ this.saveEnergyFee(100L);// 100 sun per energy
}
try {
@@ -286,7 +315,7 @@ private DynamicPropertiesStore(@Value("properties") String dbName) {
try {
this.getTransactionFee();
} catch (IllegalArgumentException e) {
- this.saveTransactionFee(10L); // 10Drop/byte
+ this.saveTransactionFee(10L); // 10sun/byte
}
try {
@@ -295,6 +324,18 @@ private DynamicPropertiesStore(@Value("properties") String dbName) {
this.saveAssetIssueFee(1024000000L);
}
+ try {
+ this.getExchangeCreateFee();
+ } catch (IllegalArgumentException e) {
+ this.saveExchangeCreateFee(1024000000L);
+ }
+
+ try {
+ this.getExchangeBalanceLimit();
+ } catch (IllegalArgumentException e) {
+ this.saveExchangeBalanceLimit(1_000_000_000_000_000L);
+ }
+
try {
this.getTotalTransactionCost();
} catch (IllegalArgumentException e) {
@@ -337,6 +378,18 @@ private DynamicPropertiesStore(@Value("properties") String dbName) {
this.saveStorageExchangeTaxRate(10);
}
+ try {
+ this.getRemoveThePowerOfTheGr();
+ } catch (IllegalArgumentException e) {
+ this.saveRemoveThePowerOfTheGr(0);
+ }
+
+ try {
+ this.getAllowCreationOfContracts();
+ } catch (IllegalArgumentException e) {
+ this.saveAllowCreationOfContracts(0L);
+ }
+
try {
this.getBlockFilledSlots();
} catch (IllegalArgumentException e) {
@@ -603,17 +656,17 @@ public long getTotalNetWeight() {
() -> new IllegalArgumentException("not found TOTAL_NET_WEIGHT"));
}
- public void saveTotalCpuWeight(long totalCpuWeight) {
- this.put(TOTAL_CPU_WEIGHT,
- new BytesCapsule(ByteArray.fromLong(totalCpuWeight)));
+ public void saveTotalEnergyWeight(long totalEnergyWeight) {
+ this.put(TOTAL_ENERGY_WEIGHT,
+ new BytesCapsule(ByteArray.fromLong(totalEnergyWeight)));
}
- public long getTotalCpuWeight() {
- return Optional.ofNullable(getUnchecked(TOTAL_CPU_WEIGHT))
+ public long getTotalEnergyWeight() {
+ return Optional.ofNullable(getUnchecked(TOTAL_ENERGY_WEIGHT))
.map(BytesCapsule::getData)
.map(ByteArray::toLong)
.orElseThrow(
- () -> new IllegalArgumentException("not found TOTAL_CPU_WEIGHT"));
+ () -> new IllegalArgumentException("not found TOTAL_ENERGY_WEIGHT"));
}
@@ -630,17 +683,31 @@ public long getTotalNetLimit() {
() -> new IllegalArgumentException("not found TOTAL_NET_LIMIT"));
}
- public void saveTotalCpuLimit(long totalCpuLimit) {
- this.put(TOTAL_CPU_LIMIT,
- new BytesCapsule(ByteArray.fromLong(totalCpuLimit)));
+ public void saveTotalEnergyLimit(long totalEnergyLimit) {
+ this.put(TOTAL_ENERGY_LIMIT,
+ new BytesCapsule(ByteArray.fromLong(totalEnergyLimit)));
}
- public long getTotalCpuLimit() {
- return Optional.ofNullable(getUnchecked(TOTAL_CPU_LIMIT))
+ public long getTotalEnergyLimit() {
+ return Optional.ofNullable(getUnchecked(TOTAL_ENERGY_LIMIT))
.map(BytesCapsule::getData)
.map(ByteArray::toLong)
.orElseThrow(
- () -> new IllegalArgumentException("not found TOTAL_CPU_LIMIT"));
+ () -> new IllegalArgumentException("not found TOTAL_ENERGY_LIMIT"));
+ }
+
+
+ public void saveEnergyFee(long totalEnergyFee) {
+ this.put(ENERGY_FEE,
+ new BytesCapsule(ByteArray.fromLong(totalEnergyFee)));
+ }
+
+ public long getEnergyFee() {
+ return Optional.ofNullable(getUnchecked(ENERGY_FEE))
+ .map(BytesCapsule::getData)
+ .map(ByteArray::toLong)
+ .orElseThrow(
+ () -> new IllegalArgumentException("not found ENERGY_FEE"));
}
public void saveCreateAccountFee(long fee) {
@@ -709,6 +776,32 @@ public long getAssetIssueFee() {
() -> new IllegalArgumentException("not found ASSET_ISSUE_FEE"));
}
+ public void saveExchangeCreateFee(long fee) {
+ this.put(EXCHANGE_CREATE_FEE,
+ new BytesCapsule(ByteArray.fromLong(fee)));
+ }
+
+ public long getExchangeCreateFee() {
+ return Optional.ofNullable(getUnchecked(EXCHANGE_CREATE_FEE))
+ .map(BytesCapsule::getData)
+ .map(ByteArray::toLong)
+ .orElseThrow(
+ () -> new IllegalArgumentException("not found EXCHANGE_CREATE_FEE"));
+ }
+
+ public void saveExchangeBalanceLimit(long limit) {
+ this.put(EXCHANGE_BALANCE_LIMIT,
+ new BytesCapsule(ByteArray.fromLong(limit)));
+ }
+
+ public long getExchangeBalanceLimit() {
+ return Optional.ofNullable(getUnchecked(EXCHANGE_BALANCE_LIMIT))
+ .map(BytesCapsule::getData)
+ .map(ByteArray::toLong)
+ .orElseThrow(
+ () -> new IllegalArgumentException("not found EXCHANGE_BALANCE_LIMIT"));
+ }
+
public void saveTotalTransactionCost(long value) {
this.put(TOTAL_TRANSACTION_COST,
new BytesCapsule(ByteArray.fromLong(value)));
@@ -800,6 +893,38 @@ public long getStorageExchangeTaxRate() {
() -> new IllegalArgumentException("not found STORAGE_EXCHANGE_TAX_RATE"));
}
+ public void saveRemoveThePowerOfTheGr(long rate) {
+ this.put(REMOVE_THE_POWER_OF_THE_GR,
+ new BytesCapsule(ByteArray.fromLong(rate)));
+ }
+
+ public long getRemoveThePowerOfTheGr() {
+ return Optional.ofNullable(getUnchecked(REMOVE_THE_POWER_OF_THE_GR))
+ .map(BytesCapsule::getData)
+ .map(ByteArray::toLong)
+ .orElseThrow(
+ () -> new IllegalArgumentException("not found REMOVE_THE_POWER_OF_THE_GR"));
+ }
+
+
+
+ public void saveAllowCreationOfContracts(long allowCreationOfContracts) {
+ this.put(DynamicPropertiesStore.ALLOW_CREATION_OF_CONTRACTS,
+ new BytesCapsule(ByteArray.fromLong(allowCreationOfContracts)));
+ }
+
+ public long getAllowCreationOfContracts() {
+ return Optional.ofNullable(getUnchecked(ALLOW_CREATION_OF_CONTRACTS))
+ .map(BytesCapsule::getData)
+ .map(ByteArray::toLong)
+ .orElseThrow(
+ () -> new IllegalArgumentException("not found ALLOW_CREATION_OF_CONTRACTS"));
+ }
+
+ public boolean supportVM() {
+ return getAllowCreationOfContracts() == 1L;
+ }
+
public void saveBlockFilledSlots(int[] blockFilledSlots) {
logger.debug("blockFilledSlots:" + intArrayToString(blockFilledSlots));
this.put(BLOCK_FILLED_SLOTS,
@@ -857,6 +982,18 @@ public long getLatestProposalNum() {
() -> new IllegalArgumentException("not found latest PROPOSAL_NUM"));
}
+ public void saveLatestExchangeNum(long number) {
+ this.put(LATEST_EXCHANGE_NUM, new BytesCapsule(ByteArray.fromLong(number)));
+ }
+
+ public long getLatestExchangeNum() {
+ return Optional.ofNullable(getUnchecked(LATEST_EXCHANGE_NUM))
+ .map(BytesCapsule::getData)
+ .map(ByteArray::toLong)
+ .orElseThrow(
+ () -> new IllegalArgumentException("not found latest EXCHANGE_NUM"));
+ }
+
/**
* get timestamp of creating global latest block.
*/
@@ -968,10 +1105,10 @@ public void addTotalNetWeight(long amount) {
}
//The unit is trx
- public void addTotalCpuWeight(long amount) {
- long totalCpuWeight = getTotalCpuWeight();
- totalCpuWeight += amount;
- saveTotalCpuWeight(totalCpuWeight);
+ public void addTotalEnergyWeight(long amount) {
+ long totalEnergyWeight = getTotalEnergyWeight();
+ totalEnergyWeight += amount;
+ saveTotalEnergyWeight(totalEnergyWeight);
}
public void addTotalCreateAccountCost(long fee) {
@@ -988,4 +1125,13 @@ public void addTotalTransactionCost(long fee) {
long newValue = getTotalTransactionCost() + fee;
saveTotalTransactionCost(newValue);
}
+
+ public void forked() {
+ put(FORK_CONTROLLER, new BytesCapsule(Boolean.toString(true).getBytes()));
+ }
+
+ public boolean getForked() {
+ byte[] value = revokingDB.getUnchecked(FORK_CONTROLLER);
+ return value == null ? Boolean.FALSE : Boolean.valueOf(new String(value));
+ }
}
diff --git a/src/main/java/org/tron/core/db/CpuProcessor.java b/src/main/java/org/tron/core/db/EnergyProcessor.java
similarity index 51%
rename from src/main/java/org/tron/core/db/CpuProcessor.java
rename to src/main/java/org/tron/core/db/EnergyProcessor.java
index 25d5907d001..94cd460fce3 100644
--- a/src/main/java/org/tron/core/db/CpuProcessor.java
+++ b/src/main/java/org/tron/core/db/EnergyProcessor.java
@@ -1,6 +1,8 @@
package org.tron.core.db;
+import static java.lang.Long.max;
+
import java.util.List;
import lombok.extern.slf4j.Slf4j;
import org.tron.core.capsule.AccountCapsule;
@@ -12,9 +14,9 @@
import org.tron.protos.Protocol.Transaction.Contract;
@Slf4j
-public class CpuProcessor extends ResourceProcessor {
+public class EnergyProcessor extends ResourceProcessor {
- public CpuProcessor(Manager manager) {
+ public EnergyProcessor(Manager manager) {
super(manager);
}
@@ -27,15 +29,16 @@ public void updateUsage(AccountCapsule accountCapsule) {
private void updateUsage(AccountCapsule accountCapsule, long now) {
AccountResource accountResource = accountCapsule.getAccountResource();
- long oldCpuUsage = accountResource.getCpuUsage();
- long latestConsumeTime = accountResource.getLatestConsumeTimeForCpu();
+ long oldEnergyUsage = accountResource.getEnergyUsage();
+ long latestConsumeTime = accountResource.getLatestConsumeTimeForEnergy();
- accountCapsule.setCpuUsage(increase(oldCpuUsage, 0, latestConsumeTime, now));
+ accountCapsule.setEnergyUsage(increase(oldEnergyUsage, 0, latestConsumeTime, now));
}
@Override
- public void consume(TransactionCapsule trx, TransactionResultCapsule ret)
+ public void consume(TransactionCapsule trx, TransactionResultCapsule ret,
+ TransactionTrace trace)
throws ContractValidateException, AccountResourceInsufficientException {
List contracts =
trx.getInstance().getRawData().getContractList();
@@ -47,9 +50,9 @@ public void consume(TransactionCapsule trx, TransactionResultCapsule ret)
// continue;
// }
//todo
-// long cpuTime = trx.getReceipt().getCpuTime();
- long cpuTime = 100L;
- logger.debug("trxId {},cpu cost :{}", trx.getTransactionId(), cpuTime);
+// long energy = trx.getReceipt().getEnergy();
+ long energy = 100L;
+ logger.debug("trxId {},energy cost :{}", trx.getTransactionId(), energy);
byte[] address = TransactionCapsule.getOwner(contract);
AccountCapsule accountCapsule = dbManager.getAccountStore().get(address);
if (accountCapsule == null) {
@@ -58,29 +61,30 @@ public void consume(TransactionCapsule trx, TransactionResultCapsule ret)
long now = dbManager.getWitnessController().getHeadSlot();
//todo
-// int creatorRatio = contract.getUserCpuConsumeRatio();
+// int creatorRatio = contract.getUserEnergyConsumeRatio();
int creatorRatio = 50;
- long creatorCpuTime = cpuTime * creatorRatio / 100;
+ long creatorEnergy = energy * creatorRatio / 100;
AccountCapsule contractProvider = dbManager.getAccountStore()
.get(contract.getProvider().toByteArray());
- if (!useCpu(contractProvider, creatorCpuTime, now)) {
- throw new ContractValidateException("creator has not enough cpu[" + creatorCpuTime + "]");
+ if (!useEnergy(contractProvider, creatorEnergy, now)) {
+ throw new ContractValidateException(
+ "creator has not enough energy[" + creatorEnergy + "]");
}
- long userCpuTime = cpuTime * (100 - creatorRatio) / 100;
+ long userEnergy = energy * (100 - creatorRatio) / 100;
//1.The creator and the use of this have sufficient resources
- if (useCpu(accountCapsule, userCpuTime, now)) {
+ if (useEnergy(accountCapsule, userEnergy, now)) {
continue;
}
// todo long feeLimit = getUserFeeLimit();
long feeLimit = 1000000;//sun
- long fee = calculateFee(userCpuTime);
+ long fee = calculateFee(userEnergy);
if (fee > feeLimit) {
throw new AccountResourceInsufficientException(
- "Account has Insufficient Cpu[" + userCpuTime + "] and feeLimit[" + feeLimit
+ "Account has Insufficient Energy[" + userEnergy + "] and feeLimit[" + feeLimit
+ "] is not enough to trigger this contract");
}
@@ -90,13 +94,13 @@ public void consume(TransactionCapsule trx, TransactionResultCapsule ret)
}
throw new AccountResourceInsufficientException(
- "Account has insufficient Cpu[" + userCpuTime + "] and balance[" + fee
+ "Account has insufficient Energy[" + userEnergy + "] and balance[" + fee
+ "] to trigger this contract");
}
}
- private long calculateFee(long userCpuTime) {
- return userCpuTime * 30;// 30 drop / macroSecond, move to dynamicStore later
+ private long calculateFee(long userEnergy) {
+ return userEnergy * 30;// 30 drop / macroSecond, move to dynamicStore later
}
@@ -110,41 +114,56 @@ private boolean useFee(AccountCapsule accountCapsule, long fee,
}
}
- public boolean useCpu(AccountCapsule accountCapsule, long cpuTime, long now) {
+ public boolean useEnergy(AccountCapsule accountCapsule, long energy, long now) {
- long cpuUsage = accountCapsule.getCpuUsage();
- long latestConsumeTime = accountCapsule.getAccountResource().getLatestConsumeTimeForCpu();
- long cpuLimit = calculateGlobalCpuLimit(
- accountCapsule.getAccountResource().getFrozenBalanceForCpu().getFrozenBalance());
+ long energyUsage = accountCapsule.getEnergyUsage();
+ long latestConsumeTime = accountCapsule.getAccountResource().getLatestConsumeTimeForEnergy();
+ long energyLimit = calculateGlobalEnergyLimit(
+ accountCapsule.getAccountResource().getFrozenBalanceForEnergy().getFrozenBalance());
- long newCpuUsage = increase(cpuUsage, 0, latestConsumeTime, now);
+ long newEnergyUsage = increase(energyUsage, 0, latestConsumeTime, now);
- if (cpuTime > (cpuLimit - newCpuUsage)) {
+ if (energy > (energyLimit - newEnergyUsage)) {
return false;
}
latestConsumeTime = now;
long latestOperationTime = dbManager.getHeadBlockTimeStamp();
- newCpuUsage = increase(newCpuUsage, cpuTime, latestConsumeTime, now);
- accountCapsule.setCpuUsage(newCpuUsage);
+ newEnergyUsage = increase(newEnergyUsage, energy, latestConsumeTime, now);
+ accountCapsule.setEnergyUsage(newEnergyUsage);
accountCapsule.setLatestOperationTime(latestOperationTime);
- accountCapsule.setLatestConsumeTimeForCpu(latestConsumeTime);
+ accountCapsule.setLatestConsumeTimeForEnergy(latestConsumeTime);
dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule);
return true;
}
- public long calculateGlobalCpuLimit(long frozeBalance) {
+ public long calculateGlobalEnergyLimit(long frozeBalance) {
if (frozeBalance < 1000_000L) {
return 0;
}
- long cpuWeight = frozeBalance / 1000_000L;
- long totalCpuLimit = dbManager.getDynamicPropertiesStore().getTotalCpuLimit();
- long totalCpuWeight = dbManager.getDynamicPropertiesStore().getTotalCpuWeight();
- assert totalCpuWeight > 0;
- return (long) (cpuWeight * ((double) totalCpuLimit / totalCpuWeight));
+ long energyWeight = frozeBalance / 1000_000L;
+ long totalEnergyLimit = dbManager.getDynamicPropertiesStore().getTotalEnergyLimit();
+ long totalEnergyWeight = dbManager.getDynamicPropertiesStore().getTotalEnergyWeight();
+ assert totalEnergyWeight > 0;
+ return (long) (energyWeight * ((double) totalEnergyLimit / totalEnergyWeight));
}
+
+ public long getAccountLeftEnergyFromFreeze(AccountCapsule accountCapsule) {
+
+ long now = dbManager.getWitnessController().getHeadSlot();
+
+ long energyUsage = accountCapsule.getEnergyUsage();
+ long latestConsumeTime = accountCapsule.getAccountResource().getLatestConsumeTimeForEnergy();
+ long energyLimit = calculateGlobalEnergyLimit(
+ accountCapsule.getAccountResource().getFrozenBalanceForEnergy().getFrozenBalance());
+
+ long newEnergyUsage = increase(energyUsage, 0, latestConsumeTime, now);
+
+ return max(energyLimit - newEnergyUsage, 0); // us
+ }
+
}
diff --git a/src/main/java/org/tron/core/db/ExchangeStore.java b/src/main/java/org/tron/core/db/ExchangeStore.java
new file mode 100644
index 00000000000..7dac15d2bca
--- /dev/null
+++ b/src/main/java/org/tron/core/db/ExchangeStore.java
@@ -0,0 +1,38 @@
+package org.tron.core.db;
+
+import com.google.common.collect.Streams;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.tron.core.capsule.ExchangeCapsule;
+import org.tron.core.exception.ItemNotFoundException;
+
+@Component
+public class ExchangeStore extends TronStoreWithRevoking {
+
+ @Autowired
+ public ExchangeStore(@Value("exchange") String dbName) {
+ super(dbName);
+ }
+
+ @Override
+ public ExchangeCapsule get(byte[] key) throws ItemNotFoundException {
+ byte[] value = revokingDB.get(key);
+ return new ExchangeCapsule(value);
+ }
+
+ /**
+ * get all exchanges.
+ */
+ public List getAllExchanges() {
+ return Streams.stream(iterator())
+ .map(Map.Entry::getValue)
+ .sorted(
+ (ExchangeCapsule a, ExchangeCapsule b) -> a.getCreateTime() <= b.getCreateTime() ? 1
+ : -1)
+ .collect(Collectors.toList());
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/tron/core/db/Manager.java b/src/main/java/org/tron/core/db/Manager.java
index cd7b6c53f19..357fbd78883 100644
--- a/src/main/java/org/tron/core/db/Manager.java
+++ b/src/main/java/org/tron/core/db/Manager.java
@@ -16,12 +16,15 @@
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javafx.util.Pair;
import javax.annotation.PostConstruct;
@@ -38,6 +41,7 @@
import org.tron.common.runtime.vm.program.invoke.ProgramInvokeFactoryImpl;
import org.tron.common.storage.DepositImpl;
import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.ForkController;
import org.tron.common.utils.SessionOptional;
import org.tron.common.utils.Sha256Hash;
import org.tron.common.utils.StringUtil;
@@ -47,6 +51,7 @@
import org.tron.core.capsule.BlockCapsule;
import org.tron.core.capsule.BlockCapsule.BlockId;
import org.tron.core.capsule.BytesCapsule;
+import org.tron.core.capsule.ReceiptCapsule;
import org.tron.core.capsule.TransactionCapsule;
import org.tron.core.capsule.TransactionInfoCapsule;
import org.tron.core.capsule.TransactionResultCapsule;
@@ -71,10 +76,14 @@
import org.tron.core.exception.HighFreqException;
import org.tron.core.exception.ItemNotFoundException;
import org.tron.core.exception.NonCommonBlockException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.ReceiptException;
import org.tron.core.exception.TaposException;
import org.tron.core.exception.TooBigTransactionException;
import org.tron.core.exception.TransactionExpirationException;
+import org.tron.core.exception.TransactionTraceException;
import org.tron.core.exception.UnLinkedBlockException;
+import org.tron.core.exception.UnsupportVMException;
import org.tron.core.exception.ValidateScheduleException;
import org.tron.core.exception.ValidateSignatureException;
import org.tron.core.witness.ProposalController;
@@ -83,6 +92,7 @@
import org.tron.protos.Protocol.Block;
import org.tron.protos.Protocol.Transaction;
+
@Slf4j
@Component
public class Manager {
@@ -95,8 +105,6 @@ public class Manager {
@Autowired
private BlockStore blockStore;
@Autowired
- private UtxoStore utxoStore;
- @Autowired
private WitnessStore witnessStore;
@Autowired
private AssetIssueStore assetIssueStore;
@@ -107,8 +115,6 @@ public class Manager {
@Autowired
private AccountIdIndexStore accountIdIndexStore;
@Autowired
- private AccountContractIndexStore accountContractIndexStore;
- @Autowired
private WitnessScheduleStore witnessScheduleStore;
@Autowired
private RecentBlockStore recentBlockStore;
@@ -117,13 +123,16 @@ public class Manager {
@Autowired
private ProposalStore proposalStore;
@Autowired
+ private ExchangeStore exchangeStore;
+ @Autowired
private TransactionHistoryStore transactionHistoryStore;
@Autowired
private CodeStore codeStore;
@Autowired
private ContractStore contractStore;
@Autowired
- private StorageStore storageStore;
+ @Getter
+ private StorageRowStore storageRowStore;
// for network
@Autowired
@@ -160,10 +169,18 @@ public class Manager {
private ExecutorService validateSignService;
+ private Thread repushThread;
+
+ private boolean isRunRepushThread = true;
+
@Getter
private Cache transactionIdCache = CacheBuilder
.newBuilder().maximumSize(100_000).recordStats().build();
+ @Getter
+ @Autowired
+ private ForkController forkController;
+
public WitnessStore getWitnessStore() {
return this.witnessStore;
}
@@ -188,10 +205,6 @@ public void setWitnessScheduleStore(final WitnessScheduleStore witnessScheduleSt
this.witnessScheduleStore = witnessScheduleStore;
}
- public StorageStore getStorageStore() {
- return storageStore;
- }
-
public CodeStore getCodeStore() {
return codeStore;
}
@@ -208,6 +221,10 @@ public ProposalStore getProposalStore() {
return this.proposalStore;
}
+ public ExchangeStore getExchangeStore() {
+ return this.exchangeStore;
+ }
+
public List getPendingTransactions() {
return this.pendingTransactions;
}
@@ -216,6 +233,10 @@ public List getPoppedTransactions() {
return this.popedTransactions;
}
+ public BlockingQueue getRepushTransactions() {
+ return repushTransactions;
+ }
+
// transactions cache
private List pendingTransactions;
@@ -223,6 +244,9 @@ public List getPoppedTransactions() {
private List popedTransactions =
Collections.synchronizedList(Lists.newArrayList());
+ // the capacity is equal to Integer.MAX_VALUE default
+ private BlockingQueue repushTransactions;
+
// for test only
public List getWitnesses() {
return witnessController.getActiveWitnesses();
@@ -285,15 +309,36 @@ public void clearAndWriteNeighbours(Set nodes) {
this.peersStore.put("neighbours".getBytes(), nodes);
}
-
- public AccountContractIndexStore getAccountContractIndexStore() {
- return accountContractIndexStore;
- }
-
public Set readNeighbours() {
return this.peersStore.get("neighbours".getBytes());
}
+ /**
+ * Cycle thread to repush Transactions
+ */
+ private Runnable repushLoop =
+ () -> {
+ while (isRunRepushThread) {
+ try {
+ TransactionCapsule tx = this.getRepushTransactions().poll(1, TimeUnit.SECONDS);
+ if (tx != null) {
+ this.rePush(tx);
+ }
+ } catch (InterruptedException ex) {
+ logger.error(ex.getMessage());
+ Thread.currentThread().interrupt();
+ } catch (Exception ex) {
+ logger.error("unknown exception happened in witness loop", ex);
+ } catch (Throwable throwable) {
+ logger.error("unknown throwable happened in witness loop", throwable);
+ }
+ }
+ };
+
+ public void stopRepushThread() {
+ isRunRepushThread = false;
+ }
+
@PostConstruct
public void init() {
revokingStore.disable();
@@ -301,6 +346,8 @@ public void init() {
this.setWitnessController(WitnessController.createInstance(this));
this.setProposalController(ProposalController.createInstance(this));
this.pendingTransactions = Collections.synchronizedList(Lists.newArrayList());
+ this.repushTransactions = new LinkedBlockingQueue<>();
+
this.initGenesis();
try {
this.khaosDb.start(getBlockById(getDynamicPropertiesStore().getLatestBlockHeaderHash()));
@@ -321,6 +368,7 @@ public void init() {
Args.getInstance().getOutputDirectory());
System.exit(1);
}
+ forkController.init(this);
revokingStore.enable();
// this.codeStore = CodeStore.create("code");
@@ -329,6 +377,9 @@ public void init() {
validateSignService = Executors
.newFixedThreadPool(Args.getInstance().getValidateSignThreadNum());
+
+ repushThread = new Thread(repushLoop);
+ repushThread.start();
}
public BlockId getGenesisBlockId() {
@@ -519,19 +570,21 @@ void validateCommon(TransactionCapsule transactionCapsule)
}
void validateDup(TransactionCapsule transactionCapsule) throws DupTransactionException {
- if (getTransactionStore().getUnchecked(transactionCapsule.getTransactionId().getBytes()) != null) {
- logger.debug(ByteArray.toHexString(transactionCapsule.getTransactionId().getBytes()));
- throw new DupTransactionException("dup trans");
- }
+ if (getTransactionStore().getUnchecked(transactionCapsule.getTransactionId().getBytes())
+ != null) {
+ logger.debug(ByteArray.toHexString(transactionCapsule.getTransactionId().getBytes()));
+ throw new DupTransactionException("dup trans");
+ }
}
/**
- * push transaction into db.
+ * push transaction into pending.
*/
- public boolean pushTransactions(final TransactionCapsule trx)
+ public boolean pushTransaction(final TransactionCapsule trx)
throws ValidateSignatureException, ContractValidateException, ContractExeException,
AccountResourceInsufficientException, DupTransactionException, TaposException,
- TooBigTransactionException, TransactionExpirationException {
+ TooBigTransactionException, TransactionExpirationException, ReceiptException,
+ TransactionTraceException, OutOfSlotTimeException, UnsupportVMException {
if (!trx.validateSignature()) {
throw new ValidateSignatureException("trans sig validate failed");
@@ -553,16 +606,18 @@ public boolean pushTransactions(final TransactionCapsule trx)
}
- public void consumeBandwidth(TransactionCapsule trx, TransactionResultCapsule ret)
+ public void consumeBandwidth(TransactionCapsule trx, TransactionResultCapsule ret,
+ TransactionTrace trace)
throws ContractValidateException, AccountResourceInsufficientException {
BandwidthProcessor processor = new BandwidthProcessor(this);
- processor.consume(trx, ret);
+ processor.consume(trx, ret, trace);
}
- public void consumeCpu(TransactionCapsule trx, TransactionResultCapsule ret)
+ public void consumeEnergy(TransactionCapsule trx, TransactionResultCapsule ret,
+ TransactionTrace trace)
throws ContractValidateException, AccountResourceInsufficientException {
- CpuProcessor processor = new CpuProcessor(this);
- processor.consume(trx, ret);
+ EnergyProcessor processor = new EnergyProcessor(this);
+ processor.consume(trx, ret, trace);
}
@Deprecated
@@ -612,6 +667,9 @@ public void eraseBlock() {
revokingStore.pop();
logger.info("end to erase block:" + oldHeadBlock);
popedTransactions.addAll(oldHeadBlock.getTransactions());
+ // todo: need add ??
+ // repushTransactions.addAll(oldHeadBlock.getTransactions());
+ //
} catch (ItemNotFoundException | BadItemException e) {
logger.warn(e.getMessage(), e);
}
@@ -619,8 +677,9 @@ public void eraseBlock() {
private void applyBlock(BlockCapsule block) throws ContractValidateException,
ContractExeException, ValidateSignatureException, AccountResourceInsufficientException,
- TransactionExpirationException, TooBigTransactionException, DupTransactionException,
- TaposException, ValidateScheduleException {
+ TransactionExpirationException, TooBigTransactionException, DupTransactionException, ReceiptException,
+ TaposException, ValidateScheduleException, TransactionTraceException, OutOfSlotTimeException,
+ UnsupportVMException {
processBlock(block);
this.blockStore.put(block.getBlockId().getBytes(), block);
this.blockIndexStore.put(block.getBlockId());
@@ -630,7 +689,8 @@ private void switchFork(BlockCapsule newHead)
throws ValidateSignatureException, ContractValidateException, ContractExeException,
ValidateScheduleException, AccountResourceInsufficientException, TaposException,
TooBigTransactionException, DupTransactionException, TransactionExpirationException,
- NonCommonBlockException {
+ NonCommonBlockException, ReceiptException, TransactionTraceException, OutOfSlotTimeException,
+ UnsupportVMException {
Pair, LinkedList> binaryTree;
try {
binaryTree =
@@ -671,8 +731,12 @@ private void switchFork(BlockCapsule newHead)
| TaposException
| DupTransactionException
| TransactionExpirationException
+ | TransactionTraceException
+ | ReceiptException
+ | OutOfSlotTimeException
| TooBigTransactionException
- | ValidateScheduleException e) {
+ | ValidateScheduleException
+ | UnsupportVMException e) {
logger.warn(e.getMessage(), e);
exception = e;
throw e;
@@ -727,8 +791,9 @@ public synchronized void pushBlock(final BlockCapsule block)
throws ValidateSignatureException, ContractValidateException, ContractExeException,
UnLinkedBlockException, ValidateScheduleException, AccountResourceInsufficientException,
TaposException, TooBigTransactionException, DupTransactionException, TransactionExpirationException,
- BadNumberBlockException, BadBlockException, NonCommonBlockException {
- try (PendingManager pm = new PendingManager(this)) {
+ BadNumberBlockException, BadBlockException, NonCommonBlockException, ReceiptException, TransactionTraceException,
+ OutOfSlotTimeException, UnsupportVMException {
+ try (PendingManager pm = new PendingManager(this)) {
if (!block.generatedByMyself) {
if (!block.validateSignature()) {
@@ -829,7 +894,8 @@ public void updateDynamicProperties(BlockCapsule block) {
for (int i = 1; i < slot; ++i) {
if (!witnessController.getScheduledWitness(i).equals(block.getWitnessAddress())) {
WitnessCapsule w =
- this.witnessStore.getUnchecked(StringUtil.createDbKey(witnessController.getScheduledWitness(i)));
+ this.witnessStore
+ .getUnchecked(StringUtil.createDbKey(witnessController.getScheduledWitness(i)));
w.setTotalMissed(w.getTotalMissed() + 1);
this.witnessStore.put(w.createDbKey(), w);
logger.info(
@@ -937,10 +1003,9 @@ public boolean hasBlocks() {
* Process transaction.
*/
public boolean processTransaction(final TransactionCapsule trxCap, Block block)
- throws ValidateSignatureException, ContractValidateException, ContractExeException,
+ throws ValidateSignatureException, ContractValidateException, ContractExeException, ReceiptException,
AccountResourceInsufficientException, TransactionExpirationException, TooBigTransactionException,
- DupTransactionException, TaposException {
-
+ DupTransactionException, TaposException, TransactionTraceException, OutOfSlotTimeException, UnsupportVMException {
if (trxCap == null) {
return false;
}
@@ -958,41 +1023,30 @@ public boolean processTransaction(final TransactionCapsule trxCap, Block block)
throw new ValidateSignatureException("trans sig validate failed");
}
- TransactionTrace trace = new TransactionTrace(trxCap);
- trace.init();
+ TransactionTrace trace = new TransactionTrace(trxCap, this);
+// TODO vm switch
+// if (!this.dynamicPropertiesStore.supportVM() && trace.needVM()) {
+// throw new UnsupportVMException("this node doesn't support vm, trx id: " + trxCap.getTransactionId().toString());
+// }
DepositImpl deposit = DepositImpl.createRoot(this);
- Runtime runtime;
-
- runtime = new Runtime(trace, block, deposit,
+ Runtime runtime = new Runtime(trace, block, deposit,
new ProgramInvokeFactoryImpl());
- consumeBandwidth(trxCap, runtime.getResult().getRet());
+ consumeBandwidth(trxCap, runtime.getResult().getRet(), trace);
- runtime.init();
-
- //exec
+ trace.init();
trace.exec(runtime);
+ trace.pay();
- //check SR's bill and ours.
- if(block != null) {
- trace.checkBill();
- }
+ transactionStore.put(trxCap.getTransactionId().getBytes(), trxCap);
- trace.finalize();
+ RuntimeException runtimeException = runtime.getResult().getException();
+ ReceiptCapsule traceReceipt = trace.getReceipt();
+ TransactionInfoCapsule transactionInfo = TransactionInfoCapsule
+ .buildInstance(trxCap, block, runtime, traceReceipt);
- if (runtime.getResult().getException() != null) {
- throw new RuntimeException("Runtime exe failed!");
- }
- // todo judge result in runtime same as block,trx,recipt
- // todo 一个账户只能一个合约账户
- transactionStore.put(trxCap.getTransactionId().getBytes(), trxCap);
- TransactionInfoCapsule transactionInfoCapsule = new TransactionInfoCapsule();
- transactionInfoCapsule.setId(trxCap.getTransactionId().getBytes());
- transactionInfoCapsule.setFee(runtime.getResult().getRet().getFee());
- transactionInfoCapsule.setContractResult(runtime.getResult().getHReturn());
- transactionInfoCapsule.setContractAddress(runtime.getResult().getContractAddress());
- transactionHistoryStore.put(trxCap.getTransactionId().getBytes(), transactionInfoCapsule);
+ transactionHistoryStore.put(trxCap.getTransactionId().getBytes(), transactionInfo);
return true;
}
@@ -1015,7 +1069,8 @@ public BlockCapsule getBlockByNum(final long num) throws ItemNotFoundException,
public synchronized BlockCapsule generateBlock(
final WitnessCapsule witnessCapsule, final long when, final byte[] privateKey)
throws ValidateSignatureException, ContractValidateException, ContractExeException,
- UnLinkedBlockException, ValidateScheduleException, AccountResourceInsufficientException {
+
+ UnLinkedBlockException, ValidateScheduleException, AccountResourceInsufficientException, TransactionTraceException {
final long timestamp = this.dynamicPropertiesStore.getLatestBlockHeaderTimestamp();
final long number = this.dynamicPropertiesStore.getLatestBlockHeaderNumber();
@@ -1032,6 +1087,7 @@ public synchronized BlockCapsule generateBlock(
new BlockCapsule(number + 1, preHash, when, witnessCapsule.getAddress());
session.reset();
session.setValue(revokingStore.buildSession());
+
Iterator iterator = pendingTransactions.iterator();
while (iterator.hasNext()) {
TransactionCapsule trx = (TransactionCapsule) iterator.next();
@@ -1049,11 +1105,13 @@ public synchronized BlockCapsule generateBlock(
}
// apply transaction
try (ISession tmpSeesion = revokingStore.buildSession()) {
- processTransaction(trx, null);
+ if (forkController.forkOrNot(trx)) {
+ processTransaction(trx, null);
// trx.resetResult();
- tmpSeesion.merge();
- // push into block
- blockCapsule.addTransaction(trx);
+ tmpSeesion.merge();
+ // push into block
+ blockCapsule.addTransaction(trx);
+ }
iterator.remove();
} catch (ContractExeException e) {
logger.info("contract not processed during execute");
@@ -1079,6 +1137,14 @@ public synchronized BlockCapsule generateBlock(
} catch (ValidateSignatureException e) {
logger.info("contract not processed during ValidateSignatureException");
logger.debug(e.getMessage(), e);
+ } catch (ReceiptException e) {
+ logger.info("receipt exception: {}", e.getMessage());
+ logger.debug(e.getMessage(), e);
+ } catch (OutOfSlotTimeException e) {
+ logger.info("OutOfSlotTime exception: {}", e.getMessage());
+ logger.debug(e.getMessage(), e);
+ } catch (UnsupportVMException e) {
+ logger.warn(e.getMessage(), e);
}
}
@@ -1094,6 +1160,7 @@ public synchronized BlockCapsule generateBlock(
blockCapsule.setMerkleRoot();
blockCapsule.sign(privateKey);
blockCapsule.generatedByMyself = true;
+
try {
this.pushBlock(blockCapsule);
return blockCapsule;
@@ -1111,6 +1178,14 @@ public synchronized BlockCapsule generateBlock(
logger.info("block exception");
} catch (NonCommonBlockException e) {
logger.info("non common exception");
+ } catch (ReceiptException e) {
+ logger.info("receipt exception: {}", e.getMessage());
+ logger.debug(e.getMessage(), e);
+ } catch (OutOfSlotTimeException e) {
+ logger.info("OutOfSlotTime exception: {}", e.getMessage());
+ logger.debug(e.getMessage(), e);
+ } catch (UnsupportVMException e) {
+ logger.warn(e.getMessage(), e);
}
return null;
@@ -1144,21 +1219,14 @@ private void setBlockStore(final BlockStore blockStore) {
this.blockStore = blockStore;
}
- public UtxoStore getUtxoStore() {
- return this.utxoStore;
- }
-
- private void setUtxoStore(final UtxoStore utxoStore) {
- this.utxoStore = utxoStore;
- }
-
/**
* process block.
*/
public void processBlock(BlockCapsule block)
throws ValidateSignatureException, ContractValidateException, ContractExeException,
AccountResourceInsufficientException, TaposException, TooBigTransactionException,
- DupTransactionException, TransactionExpirationException, ValidateScheduleException {
+ DupTransactionException, TransactionExpirationException, ValidateScheduleException,
+ ReceiptException, TransactionTraceException, OutOfSlotTimeException, UnsupportVMException {
// todo set revoking db max size.
// checkWitness
@@ -1188,6 +1256,7 @@ public void processBlock(BlockCapsule block)
updateMaintenanceState(needMaint);
//witnessController.updateWitnessSchedule();
updateRecentBlock(block);
+
}
private void updateTransHashCache(BlockCapsule block) {
@@ -1231,6 +1300,12 @@ public void updateLatestSolidifiedBlock() {
}
getDynamicPropertiesStore().saveLatestSolidifiedBlockNum(latestSolidifiedBlockNum);
logger.info("update solid block, num = {}", latestSolidifiedBlockNum);
+ try {
+ BlockCapsule solidifiedBlock = getBlockByNum(latestSolidifiedBlockNum);
+ forkController.update(solidifiedBlock);
+ } catch (ItemNotFoundException | BadItemException e) {
+ logger.error("solidified block not found");
+ }
}
public long getSyncBeginNumber() {
@@ -1265,6 +1340,7 @@ private void processMaintenance(BlockCapsule block) {
proposalController.processProposals();
witnessController.updateWitness();
this.dynamicPropertiesStore.updateNextMaintenanceTime(block.getTimeStamp());
+ forkController.reset();
}
/**
@@ -1352,10 +1428,9 @@ public void closeAllStore() {
closeOneStore(assetIssueStore);
closeOneStore(dynamicPropertiesStore);
closeOneStore(transactionStore);
- closeOneStore(utxoStore);
closeOneStore(codeStore);
closeOneStore(contractStore);
- closeOneStore(storageStore);
+ closeOneStore(storageRowStore);
System.err.println("******** end to close db ********");
}
@@ -1371,7 +1446,8 @@ private void closeOneStore(ITronChainBase database) {
}
public boolean isTooManyPending() {
- if (getPendingTransactions().size() + PendingManager.getTmpTransactions().size()
+ // if (getPendingTransactions().size() + PendingManager.getTmpTransactions().size()
+ if (getPendingTransactions().size() + getRepushTransactions().size()
> MAX_TRANSACTION_PENDING) {
return true;
}
@@ -1431,4 +1507,45 @@ public synchronized void preValidateTransactionSign(BlockCapsule block)
}
}
}
+
+ public void rePush(TransactionCapsule tx) {
+
+ try {
+ if (transactionStore.get(tx.getTransactionId().getBytes()) != null) {
+ return;
+ }
+ } catch (BadItemException e) {
+ // do nothing
+ }
+
+ try {
+ this.pushTransaction(tx);
+ } catch (ValidateSignatureException e) {
+ logger.debug(e.getMessage(), e);
+ } catch (ContractValidateException e) {
+ logger.debug(e.getMessage(), e);
+ } catch (ContractExeException e) {
+ logger.debug(e.getMessage(), e);
+ } catch (AccountResourceInsufficientException e) {
+ logger.debug(e.getMessage(), e);
+ } catch (DupTransactionException e) {
+ logger.debug("pending manager: dup trans", e);
+ } catch (TaposException e) {
+ logger.debug("pending manager: tapos exception", e);
+ } catch (TooBigTransactionException e) {
+ logger.debug("too big transaction");
+ } catch (ReceiptException e) {
+ logger.info("Receipt exception," + e.getMessage());
+ } catch (TransactionExpirationException e) {
+ logger.debug("expiration transaction");
+ } catch (TransactionTraceException e) {
+ logger.debug("transactionTrace transaction");
+ } catch (OutOfSlotTimeException e) {
+ logger.debug("outOfSlotTime transaction");
+ } catch (UnsupportVMException e) {
+ logger.debug(e.getMessage(), e);
+ }
+ }
+
+
}
diff --git a/src/main/java/org/tron/core/db/PendingManager.java b/src/main/java/org/tron/core/db/PendingManager.java
index 03308e4e193..3b56be4e423 100644
--- a/src/main/java/org/tron/core/db/PendingManager.java
+++ b/src/main/java/org/tron/core/db/PendingManager.java
@@ -5,15 +5,6 @@
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.tron.core.capsule.TransactionCapsule;
-import org.tron.core.exception.BadItemException;
-import org.tron.core.exception.AccountResourceInsufficientException;
-import org.tron.core.exception.ContractExeException;
-import org.tron.core.exception.ContractValidateException;
-import org.tron.core.exception.DupTransactionException;
-import org.tron.core.exception.TaposException;
-import org.tron.core.exception.TooBigTransactionException;
-import org.tron.core.exception.TransactionExpirationException;
-import org.tron.core.exception.ValidateSignatureException;
@Slf4j
public class PendingManager implements AutoCloseable {
@@ -23,6 +14,7 @@ public class PendingManager implements AutoCloseable {
Manager dbManager;
public PendingManager(Manager db) {
+
this.dbManager = db;
tmpTransactions.addAll(db.getPendingTransactions());
db.getPendingTransactions().clear();
@@ -31,43 +23,26 @@ public PendingManager(Manager db) {
@Override
public void close() {
- rePush(this.tmpTransactions);
- rePush(dbManager.getPoppedTransactions());
- dbManager.getPoppedTransactions().clear();
+
+ for (TransactionCapsule tx : this.tmpTransactions) {
+ try {
+ dbManager.getRepushTransactions().put(tx);
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage());
+ Thread.currentThread().interrupt();
+ }
+ }
tmpTransactions.clear();
- }
- private void rePush(List txs) {
- txs.stream()
- .filter(
- trx -> {
- try {
- return
- dbManager.getTransactionStore().get(trx.getTransactionId().getBytes()) == null;
- } catch (BadItemException e) {
- return true;
- }
- })
- .forEach(trx -> {
- try {
- dbManager.pushTransactions(trx);
- } catch (ValidateSignatureException e) {
- logger.debug(e.getMessage(), e);
- } catch (ContractValidateException e) {
- logger.debug(e.getMessage(), e);
- } catch (ContractExeException e) {
- logger.debug(e.getMessage(), e);
- } catch (AccountResourceInsufficientException e) {
- logger.debug(e.getMessage(), e);
- } catch (DupTransactionException e) {
- logger.debug("pending manager: dup trans", e);
- } catch (TaposException e) {
- logger.debug("pending manager: tapos exception", e);
- } catch (TooBigTransactionException e) {
- logger.debug("too big transaction");
- } catch (TransactionExpirationException e) {
- logger.debug("expiration transaction");
- }
- });
+ for (TransactionCapsule tx : dbManager.getPoppedTransactions()) {
+ try {
+ dbManager.getRepushTransactions().put(tx);
+ } catch (InterruptedException e) {
+ logger.error(e.getMessage());
+ Thread.currentThread().interrupt();
+ }
+ }
+ dbManager.getPoppedTransactions().clear();
+
}
}
diff --git a/src/main/java/org/tron/core/db/ProposalStore.java b/src/main/java/org/tron/core/db/ProposalStore.java
index b941d2edb27..e31c0146cd2 100644
--- a/src/main/java/org/tron/core/db/ProposalStore.java
+++ b/src/main/java/org/tron/core/db/ProposalStore.java
@@ -25,7 +25,7 @@ public ProposalCapsule get(byte[] key) throws ItemNotFoundException {
}
/**
- * get all witnesses.
+ * get all proposals.
*/
public List getAllProposals() {
return Streams.stream(iterator())
diff --git a/src/main/java/org/tron/core/db/ResourceProcessor.java b/src/main/java/org/tron/core/db/ResourceProcessor.java
index e6ef7097ffe..2e62e445dba 100644
--- a/src/main/java/org/tron/core/db/ResourceProcessor.java
+++ b/src/main/java/org/tron/core/db/ResourceProcessor.java
@@ -22,7 +22,8 @@ public ResourceProcessor(Manager manager) {
abstract void updateUsage(AccountCapsule accountCapsule);
- abstract void consume(TransactionCapsule trx, TransactionResultCapsule ret)
+ abstract void consume(TransactionCapsule trx, TransactionResultCapsule ret,
+ TransactionTrace trace)
throws ContractValidateException, AccountResourceInsufficientException;
protected long increase(long lastUsage, long usage, long lastTime, long now) {
diff --git a/src/main/java/org/tron/core/db/StorageMarket.java b/src/main/java/org/tron/core/db/StorageMarket.java
index 4384fd63627..206ce2ec611 100644
--- a/src/main/java/org/tron/core/db/StorageMarket.java
+++ b/src/main/java/org/tron/core/db/StorageMarket.java
@@ -22,6 +22,28 @@ private long exchange_to_supply(boolean isTRX, long quant) {
long newBalance = balance + quant;
logger.info("balance + quant: " + (balance + quant));
+// if (isTRX) {
+// dbManager.getDynamicPropertiesStore().saveTotalStoragePool(newBalance);
+// } else {
+// dbManager.getDynamicPropertiesStore().saveTotalStorageReserved(newBalance);
+// }
+
+ double issuedSupply = -supply * (1.0 - Math.pow(1.0 + (double) quant / newBalance, 0.0005));
+ logger.info("issuedSupply: " + issuedSupply);
+ long out = (long) issuedSupply;
+ supply += out;
+
+ return out;
+ }
+
+ private long exchange_to_supply2(boolean isTRX, long quant) {
+ logger.info("isTRX: " + isTRX);
+ long balance = isTRX ? dbManager.getDynamicPropertiesStore().getTotalStoragePool() :
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+ logger.info("balance: " + balance);
+ long newBalance = balance - quant;
+ logger.info("balance - quant: " + (balance - quant));
+
// if (isTRX) {
// dbManager.getDynamicPropertiesStore().saveTotalStoragePool(newBalance);
// } else {
@@ -47,11 +69,10 @@ private long exchange_from_supply(boolean isTRX, long supplyQuant) {
long out = (long) exchangeBalance;
long newBalance = balance - out;
-// if (isTRX) {
-// dbManager.getDynamicPropertiesStore().saveTotalStoragePool(newBalance);
-// } else {
-// dbManager.getDynamicPropertiesStore().saveTotalStorageReserved(newBalance);
-// }
+ if (isTRX) {
+ out = Math.round(exchangeBalance / 100000) * 100000;
+ logger.info("---out: " + out);
+ }
return out;
}
@@ -71,6 +92,26 @@ public long calculateTax(long duration, long limit) {
return storageTax;
}
+
+ public long tryPayTax(long duration, long limit) {
+ long storageTax = calculateTax(duration, limit);
+ long tax = exchange(storageTax, false);
+ logger.info("tax: " + tax);
+
+ long newTotalTax = dbManager.getDynamicPropertiesStore().getTotalStorageTax() + tax;
+ long newTotalPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool() - tax;
+ long newTotalReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved()
+ + storageTax;
+ logger.info("reserved: " + dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ boolean eq = dbManager.getDynamicPropertiesStore().getTotalStorageReserved()
+ == 128L * 1024 * 1024 * 1024;
+ logger.info("reserved == 128GB: " + eq);
+ logger.info("newTotalTax: " + newTotalTax + " newTotalPool: " + newTotalPool
+ + " newTotalReserved: " + newTotalReserved);
+
+ return storageTax;
+ }
+
public long payTax(long duration, long limit) {
long storageTax = calculateTax(duration, limit);
long tax = exchange(storageTax, false);
@@ -93,22 +134,61 @@ public long payTax(long duration, long limit) {
return storageTax;
}
- public void buyStorage(AccountCapsule accountCapsule, long quant) {
- long now = dbManager.getHeadBlockTimeStamp();
+ public long tryBuyStorageBytes(long storageBought) {
+ long relay = exchange_to_supply2(false, storageBought);
+ return exchange_from_supply(true, relay);
+ }
+
+ public long tryBuyStorage(long quant) {
+ return exchange(quant, true);
+ }
- long latestExchangeStorageTime = accountCapsule.getLatestExchangeStorageTime();
+ public long trySellStorage(long bytes) {
+ return exchange(bytes, false);
+ }
+
+ public AccountCapsule buyStorageBytes(AccountCapsule accountCapsule, long storageBought) {
+ long now = dbManager.getHeadBlockTimeStamp();
long currentStorageLimit = accountCapsule.getStorageLimit();
- long currentUnusedStorage = currentStorageLimit - accountCapsule.getStorageUsage();
- long duration = now - latestExchangeStorageTime;
- long storageTax = payTax(duration, currentUnusedStorage);
+ long relay = exchange_to_supply2(false, storageBought);
+ long quant = exchange_from_supply(true, relay);
+
+ long newBalance = accountCapsule.getBalance() - quant;
+ logger.info("newBalance: " + newBalance);
+
+ long newStorageLimit = currentStorageLimit + storageBought;
+ logger.info(
+ "storageBought: " + storageBought + " newStorageLimit: "
+ + newStorageLimit);
+
+ accountCapsule.setLatestExchangeStorageTime(now);
+ accountCapsule.setStorageLimit(newStorageLimit);
+ accountCapsule.setBalance(newBalance);
+ dbManager.getAccountStore().put(accountCapsule.createDbKey(), accountCapsule);
+
+ long newTotalPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool() + quant;
+ long newTotalReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved()
+ - storageBought;
+ logger.info("newTotalPool: " + newTotalPool + " newTotalReserved: " + newTotalReserved);
+ dbManager.getDynamicPropertiesStore().saveTotalStoragePool(newTotalPool);
+ dbManager.getDynamicPropertiesStore().saveTotalStorageReserved(newTotalReserved);
+ return accountCapsule;
+ }
+
+
+ public void buyStorage(AccountCapsule accountCapsule, long quant) {
+ long now = dbManager.getHeadBlockTimeStamp();
+ long currentStorageLimit = accountCapsule.getStorageLimit();
long newBalance = accountCapsule.getBalance() - quant;
logger.info("newBalance: " + newBalance);
long storageBought = exchange(quant, true);
- long newStorageLimit = currentStorageLimit - storageTax + storageBought;
- logger.info("storageBought: " + storageBought + " newStorageLimit: " + newStorageLimit);
+ long newStorageLimit = currentStorageLimit + storageBought;
+ logger.info(
+ "storageBought: " + storageBought + " newStorageLimit: "
+ + newStorageLimit);
accountCapsule.setLatestExchangeStorageTime(now);
accountCapsule.setStorageLimit(newStorageLimit);
@@ -126,18 +206,12 @@ public void buyStorage(AccountCapsule accountCapsule, long quant) {
public void sellStorage(AccountCapsule accountCapsule, long bytes) {
long now = dbManager.getHeadBlockTimeStamp();
-
- long latestExchangeStorageTime = accountCapsule.getLatestExchangeStorageTime();
long currentStorageLimit = accountCapsule.getStorageLimit();
- long currentUnusedStorage = currentStorageLimit - accountCapsule.getStorageUsage();
-
- long duration = now - latestExchangeStorageTime;
- long storageTax = payTax(duration, currentUnusedStorage);
long quant = exchange(bytes, false);
long newBalance = accountCapsule.getBalance() + quant;
- long newStorageLimit = currentStorageLimit - storageTax - bytes;
+ long newStorageLimit = currentStorageLimit - bytes;
logger.info("quant: " + quant + " newStorageLimit: " + newStorageLimit);
accountCapsule.setLatestExchangeStorageTime(now);
@@ -154,4 +228,7 @@ public void sellStorage(AccountCapsule accountCapsule, long bytes) {
}
+ public long getAccountLeftStorageInByteFromBought(AccountCapsule accountCapsule) {
+ return accountCapsule.getStorageLimit() - accountCapsule.getStorageUsage();
+ }
}
diff --git a/src/main/java/org/tron/core/db/StorageRowStore.java b/src/main/java/org/tron/core/db/StorageRowStore.java
new file mode 100644
index 00000000000..1b9bc124a31
--- /dev/null
+++ b/src/main/java/org/tron/core/db/StorageRowStore.java
@@ -0,0 +1,30 @@
+package org.tron.core.db;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.tron.core.capsule.StorageRowCapsule;
+
+@Slf4j
+@Component
+public class StorageRowStore extends TronStoreWithRevoking {
+
+ private static StorageRowStore instance;
+
+ @Autowired
+ private StorageRowStore(@Value("storage-row") String dbName) {
+ super(dbName);
+ }
+
+ @Override
+ public StorageRowCapsule get(byte[] key) {
+ StorageRowCapsule row = getUnchecked(key);
+ row.setRowKey(key);
+ return row;
+ }
+
+ void destory() {
+ instance = null;
+ }
+}
diff --git a/src/main/java/org/tron/core/db/StorageStore.java b/src/main/java/org/tron/core/db/StorageStore.java
deleted file mode 100755
index c2503ddbe72..00000000000
--- a/src/main/java/org/tron/core/db/StorageStore.java
+++ /dev/null
@@ -1,49 +0,0 @@
-package org.tron.core.db;
-
-import com.google.common.collect.Streams;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.ArrayUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.tron.core.capsule.StorageCapsule;
-
-@Slf4j
-@Component
-public class StorageStore extends TronStoreWithRevoking {
-
- @Autowired
- private StorageStore(@Value("storage") String dbName) {
- super(dbName);
- }
-
- @Override
- public StorageCapsule get(byte[] key) {
- return getUnchecked(key);
- }
-
- /**
- * get total storages.
- */
- public long getTotalStorages() {
- return Streams.stream(revokingDB.iterator()).count();
- }
-
- private static StorageStore instance;
-
- public static void destory() {
- instance = null;
- }
-
- void destroy() {
- instance = null;
- }
-
- /**
- * find a storage by it's key.
- */
- public byte[] findStorageByKey(byte[] key) {
- return revokingDB.getUnchecked(key);
- }
-
-}
diff --git a/src/main/java/org/tron/core/db/TransactionTrace.java b/src/main/java/org/tron/core/db/TransactionTrace.java
index 796ffea40ef..63bf59c52ed 100644
--- a/src/main/java/org/tron/core/db/TransactionTrace.java
+++ b/src/main/java/org/tron/core/db/TransactionTrace.java
@@ -1,61 +1,143 @@
package org.tron.core.db;
+import static org.tron.common.runtime.vm.program.InternalTransaction.TrxType.TRX_CONTRACT_CALL_TYPE;
+import static org.tron.common.runtime.vm.program.InternalTransaction.TrxType.TRX_CONTRACT_CREATION_TYPE;
+import static org.tron.common.runtime.vm.program.InternalTransaction.TrxType.TRX_PRECOMPILED_TYPE;
+
import org.tron.common.runtime.Runtime;
+import org.tron.common.runtime.vm.program.InternalTransaction;
import org.tron.common.utils.Sha256Hash;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.capsule.ContractCapsule;
import org.tron.core.capsule.ReceiptCapsule;
import org.tron.core.capsule.TransactionCapsule;
import org.tron.core.exception.ContractExeException;
import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.TransactionTraceException;
+import org.tron.protos.Contract.TriggerSmartContract;
+import org.tron.protos.Protocol.Transaction;
+import org.tron.protos.Protocol.Transaction.Contract.ContractType;
public class TransactionTrace {
+
private TransactionCapsule trx;
private ReceiptCapsule receipt;
+ private Manager dbManager;
+
+ private EnergyProcessor energyProcessor;
+
+ private InternalTransaction.TrxType trxType;
+
public TransactionCapsule getTrx() {
return trx;
}
- public TransactionTrace(TransactionCapsule trx) {
+ public TransactionTrace(TransactionCapsule trx, Manager dbManager) {
this.trx = trx;
+ Transaction.Contract.ContractType contractType = this.trx.getInstance().getRawData()
+ .getContract(0).getType();
+ switch (contractType.getNumber()) {
+ case ContractType.TriggerSmartContract_VALUE:
+ trxType = TRX_CONTRACT_CALL_TYPE;
+ break;
+ case ContractType.CreateSmartContract_VALUE:
+ trxType = TRX_CONTRACT_CREATION_TYPE;
+ break;
+ default:
+ trxType = TRX_PRECOMPILED_TYPE;
+ }
+
//TODO: set bill owner
receipt = new ReceiptCapsule(Sha256Hash.ZERO_HASH);
+ this.dbManager = dbManager;
+ this.receipt = new ReceiptCapsule(Sha256Hash.ZERO_HASH);
+
+ this.energyProcessor = new EnergyProcessor(this.dbManager);
+ }
+
+ public boolean needVM() {
+ return this.trxType == TRX_CONTRACT_CALL_TYPE || this.trxType == TRX_CONTRACT_CREATION_TYPE;
}
//pre transaction check
- public void init() {
- //TODO: check
-// receipt.payCpuBill();
- checkStorage();
+ public void init() throws TransactionTraceException {
+
+ // switch (trxType) {
+ // case TRX_PRECOMPILED_TYPE:
+ // break;
+ // case TRX_CONTRACT_CREATION_TYPE:
+ // case TRX_CONTRACT_CALL_TYPE:
+ // // checkForSmartContract();
+ // break;
+ // default:
+ // break;
+ // }
+
}
//set bill
- public void setBill(long cpuUseage, long storageDelta) {
- receipt.setCpuUsage(cpuUseage);
- receipt.setStorageDelta(storageDelta);
+ public void setBill(long energyUseage) {
+ receipt.setEnergyUsageTotal(energyUseage);
}
- private void checkStorage() {
- //TODO if not enough buy some storage auto
- receipt.buyStorage(0);
+ //set net bill
+ public void setNetBill(long netUsage, long netFee) {
+ receipt.setNetUsage(netUsage);
+ receipt.setNetFee(netFee);
}
- public void exec(Runtime runtime) throws ContractExeException, ContractValidateException {
+ public void exec(Runtime runtime)
+ throws ContractExeException, ContractValidateException, OutOfSlotTimeException {
/** VM execute **/
+ runtime.init();
runtime.execute();
runtime.go();
+ runtime.finalization();
}
- public void finalize() {
- //TODO: if SR package this this trx, use their receipt
- //ReceiptCapsule witReceipt = trx.getInstance().getRet(0).getReceipt()
- receipt.payCpuBill();
- receipt.payStorageBill();
- //TODO: pay bill
- }
+ /**
+ * pay actually bill(include ENERGY and storage).
+ */
+ public void pay() {
+ byte[] originAccount;
+ byte[] callerAccount;
+ long percent = 0;
+ switch (trxType) {
+ case TRX_CONTRACT_CREATION_TYPE:
+ callerAccount = TransactionCapsule.getOwner(trx.getInstance().getRawData().getContract(0));
+ originAccount = callerAccount;
+ break;
+ case TRX_CONTRACT_CALL_TYPE:
+ TriggerSmartContract callContract = ContractCapsule
+ .getTriggerContractFromTransaction(trx.getInstance());
+ callerAccount = callContract.getOwnerAddress().toByteArray();
+
+ ContractCapsule contract =
+ dbManager.getContractStore().get(callContract.getContractAddress().toByteArray());
+ originAccount = contract.getInstance().getOriginAddress().toByteArray();
+ percent = Math.max(100 - contract.getConsumeUserResourcePercent(), 0);
+ percent = Math.min(percent, 100);
+ break;
+ default:
+ return;
+ }
- public void checkBill() {
- //TODO: check SR's bill and ours.
+ // originAccount Percent = 30%
+ AccountCapsule origin = dbManager.getAccountStore().get(originAccount);
+ AccountCapsule caller = dbManager.getAccountStore().get(callerAccount);
+ receipt.payEnergyBill(
+ dbManager,
+ origin,
+ caller,
+ percent,
+ energyProcessor,
+ dbManager.getWitnessController().getHeadSlot());
}
+ public ReceiptCapsule getReceipt() {
+ return receipt;
+ }
}
diff --git a/src/main/java/org/tron/core/db/UtxoStore.java b/src/main/java/org/tron/core/db/UtxoStore.java
deleted file mode 100755
index d56579d0ef5..00000000000
--- a/src/main/java/org/tron/core/db/UtxoStore.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * java-tron is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * java-tron is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-
-package org.tron.core.db;
-
-import com.google.protobuf.InvalidProtocolBufferException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
-import java.util.stream.Collectors;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.ArrayUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Qualifier;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import org.tron.common.crypto.ECKey;
-import org.tron.common.utils.ByteArray;
-import org.tron.core.SpendableOutputs;
-import org.tron.protos.Protocol.TXOutput;
-import org.tron.protos.Protocol.TXOutputs;
-
-@Slf4j
-@Component
-public class UtxoStore extends TronDatabase {
-
- @Autowired
- private UtxoStore(@Value("utxo") String dbName) {
- super(dbName);
- }
-
-
- public byte[] find(byte[] key) {
- return dbSource.getData(key);
- }
-
-
- public Set getKeys() {
- return dbSource.allKeys();
- }
-
- /**
- * save utxo.
- */
- public void saveUtxo(byte[] utxoKey, byte[] utxoData) {
- dbSource.putData(utxoKey, utxoData);
- }
-
- /**
- * Find spendable outputs.
- */
- public SpendableOutputs findSpendableOutputs(byte[] pubKeyHash, long amount) {
- SpendableOutputs spendableOutputs = new SpendableOutputs();
- HashMap unspentOutputs = new HashMap<>();
- long accumulated = 0L;
-
- for (byte[] key : getDbSource().allKeys()) {
- try {
- TXOutputs txOutputs = TXOutputs.parseFrom(getDbSource().getData(key));
- String keyToHexString = ByteArray.toHexString(key);
-
- for (int i = 0, len = txOutputs.getOutputsCount(); i < len; i++) {
- TXOutput txOutput = txOutputs.getOutputs(i);
- if (ByteArray.toHexString(ECKey.computeAddress(pubKeyHash))
- .equals(ByteArray.toHexString(txOutput.getPubKeyHash().toByteArray()))
- && accumulated < amount) {
-
- accumulated += txOutput.getValue();
- long[] v = ArrayUtils.nullToEmpty(unspentOutputs.get(keyToHexString));
- unspentOutputs.put(keyToHexString, ArrayUtils.add(v, i));
- }
- }
- } catch (InvalidProtocolBufferException e) {
- logger.debug(e.getMessage(), e);
- }
- }
-
- spendableOutputs.setAmount(accumulated);
- spendableOutputs.setUnspentOutputs(unspentOutputs);
-
- return spendableOutputs;
- }
-
- /**
- * Find related UTXOs.
- */
- public ArrayList findUtxo(byte[] address) {
- return getDbSource().allKeys().stream()
- .map(key -> {
- try {
- return TXOutputs.parseFrom(getDbSource().getData(key));
- } catch (InvalidProtocolBufferException e) {
- logger.debug(e.getMessage(), e);
- return null;
- }
- })
- .filter(Objects::nonNull)
- .map(TXOutputs::getOutputsList)
- .flatMap(List::stream)
- .filter(txOutput -> ByteArray.toHexString(ECKey.computeAddress(address))
- .equals(ByteArray.toHexString(txOutput.getPubKeyHash().toByteArray())))
- .collect(Collectors.toCollection(ArrayList::new));
- }
-
- @Override
- public void put(byte[] key, Object item) {
-
- }
-
- @Override
- public void delete(byte[] key) {
-
- }
-
- @Override
- public Object get(byte[] key) {
- return null;
- }
-
- @Override
- public boolean has(byte[] key) {
- return false;
- }
-
-}
\ No newline at end of file
diff --git a/src/main/java/org/tron/core/db/api/StoreAPI.java b/src/main/java/org/tron/core/db/api/StoreAPI.java
index 8c170c9ad75..ffcd4ff87fd 100644
--- a/src/main/java/org/tron/core/db/api/StoreAPI.java
+++ b/src/main/java/org/tron/core/db/api/StoreAPI.java
@@ -1,12 +1,9 @@
package org.tron.core.db.api;
-import static com.googlecode.cqengine.query.QueryFactory.applyThresholds;
import static com.googlecode.cqengine.query.QueryFactory.ascending;
import static com.googlecode.cqengine.query.QueryFactory.equal;
import static com.googlecode.cqengine.query.QueryFactory.orderBy;
import static com.googlecode.cqengine.query.QueryFactory.queryOptions;
-import static com.googlecode.cqengine.query.QueryFactory.threshold;
-import static com.googlecode.cqengine.query.option.EngineThresholds.INDEX_ORDERING_SELECTIVITY;
import static org.tron.core.config.Parameter.DatabaseConstants.TRANSACTIONS_COUNT_LIMIT_MAX;
import com.google.common.collect.ImmutableList;
@@ -103,8 +100,7 @@ public List getTransactionsFromThis(String address, long offset, lo
index.retrieve(
equal(TransactionIndex.OWNERS, address),
queryOptions(
- orderBy(ascending(TransactionIndex.TIMESTAMP)),
- applyThresholds(threshold(INDEX_ORDERING_SELECTIVITY, 1.0))))) {
+ orderBy(ascending(TransactionIndex.TIMESTAMP))))) {
if (limit > TRANSACTIONS_COUNT_LIMIT_MAX) {
limit = TRANSACTIONS_COUNT_LIMIT_MAX;
}
@@ -122,8 +118,7 @@ public List getTransactionsToThis(String address, long offset, long
index.retrieve(
equal(TransactionIndex.TOS, address),
queryOptions(
- orderBy(ascending(TransactionIndex.TIMESTAMP)),
- applyThresholds(threshold(INDEX_ORDERING_SELECTIVITY, 1.0))))) {
+ orderBy(ascending(TransactionIndex.TIMESTAMP))))) {
if (limit > TRANSACTIONS_COUNT_LIMIT_MAX) {
limit = TRANSACTIONS_COUNT_LIMIT_MAX;
}
diff --git a/src/main/java/org/tron/core/db/api/index/TransactionIndex.java b/src/main/java/org/tron/core/db/api/index/TransactionIndex.java
index e4695b7ccd5..32eeded7024 100644
--- a/src/main/java/org/tron/core/db/api/index/TransactionIndex.java
+++ b/src/main/java/org/tron/core/db/api/index/TransactionIndex.java
@@ -64,6 +64,5 @@ protected void setAttribute() {
.collect(Collectors.toList()));
TIMESTAMP =
attribute("timestamp", bytes -> getObject(bytes).getRawData().getTimestamp());
-
}
}
diff --git a/src/main/java/org/tron/core/events/BlockchainListener.java b/src/main/java/org/tron/core/events/BlockchainListener.java
deleted file mode 100644
index 3562702b411..00000000000
--- a/src/main/java/org/tron/core/events/BlockchainListener.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * java-tron is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * java-tron is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.tron.core.events;
-
-import org.tron.protos.Protocol.Block;
-
-public interface BlockchainListener {
-
- /**
- * New block added to blockchain.
- */
- void addBlock(Block block);
-
- /**
- * Genesis block added to blockchain.
- */
- void addGenesisBlock(Block block);
-}
diff --git a/src/main/java/org/tron/core/exception/OutOfSlotTimeException.java b/src/main/java/org/tron/core/exception/OutOfSlotTimeException.java
new file mode 100644
index 00000000000..644d37cd6d2
--- /dev/null
+++ b/src/main/java/org/tron/core/exception/OutOfSlotTimeException.java
@@ -0,0 +1,17 @@
+package org.tron.core.exception;
+
+public class OutOfSlotTimeException extends Exception {
+
+ public OutOfSlotTimeException() {
+ super();
+ }
+
+ public OutOfSlotTimeException(String message) {
+ super(message);
+ }
+
+ public OutOfSlotTimeException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+}
diff --git a/src/main/java/org/tron/core/exception/ReceiptException.java b/src/main/java/org/tron/core/exception/ReceiptException.java
new file mode 100644
index 00000000000..89c99ce3700
--- /dev/null
+++ b/src/main/java/org/tron/core/exception/ReceiptException.java
@@ -0,0 +1,13 @@
+package org.tron.core.exception;
+
+public class ReceiptException extends TronException {
+
+ public ReceiptException() {
+ super();
+ }
+
+ public ReceiptException(String message) {
+ super(message);
+ }
+}
+
diff --git a/src/main/java/org/tron/core/exception/TransactionTraceException.java b/src/main/java/org/tron/core/exception/TransactionTraceException.java
new file mode 100644
index 00000000000..ffbb7a480dc
--- /dev/null
+++ b/src/main/java/org/tron/core/exception/TransactionTraceException.java
@@ -0,0 +1,13 @@
+package org.tron.core.exception;
+
+public class TransactionTraceException extends TronException {
+
+ public TransactionTraceException() {
+ super();
+ }
+
+ public TransactionTraceException(String message) {
+ super(message);
+ }
+
+}
\ No newline at end of file
diff --git a/src/main/java/org/tron/core/exception/UnsupportVMException.java b/src/main/java/org/tron/core/exception/UnsupportVMException.java
new file mode 100644
index 00000000000..26255a1e076
--- /dev/null
+++ b/src/main/java/org/tron/core/exception/UnsupportVMException.java
@@ -0,0 +1,13 @@
+package org.tron.core.exception;
+
+public class UnsupportVMException extends TronException {
+
+ public UnsupportVMException() {
+ super();
+ }
+
+ public UnsupportVMException(String message) {
+ super(message);
+ }
+
+}
diff --git a/src/main/java/org/tron/core/facade/TronBlockChain.java b/src/main/java/org/tron/core/facade/TronBlockChain.java
deleted file mode 100644
index c03c802584e..00000000000
--- a/src/main/java/org/tron/core/facade/TronBlockChain.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * java-tron is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * java-tron is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- */
-
-package org.tron.core.facade;
-
-import org.tron.protos.Protocol.Block;
-
-public interface TronBlockChain {
-
- /**
- * last added block from blockchain.
- */
- Block getBestBlock();
-}
diff --git a/src/main/java/org/tron/core/net/message/TransactionMessage.java b/src/main/java/org/tron/core/net/message/TransactionMessage.java
index bd47baf9c10..8a9a3aa222c 100644
--- a/src/main/java/org/tron/core/net/message/TransactionMessage.java
+++ b/src/main/java/org/tron/core/net/message/TransactionMessage.java
@@ -38,7 +38,7 @@ public Class> getAnswerMessage() {
}
public TransactionCapsule getTransactionCapsule() {
- this.transactionCapsule.resetResult();
+ //this.transactionCapsule.resetResult();
return this.transactionCapsule;
}
}
diff --git a/src/main/java/org/tron/core/net/message/TronMessageFactory.java b/src/main/java/org/tron/core/net/message/TronMessageFactory.java
index e71a1b3e7d4..be4eedd8343 100644
--- a/src/main/java/org/tron/core/net/message/TronMessageFactory.java
+++ b/src/main/java/org/tron/core/net/message/TronMessageFactory.java
@@ -3,7 +3,6 @@
import org.apache.commons.lang3.ArrayUtils;
import org.tron.common.overlay.message.MessageFactory;
import org.tron.core.exception.P2pException;
-import org.tron.core.exception.P2pException.TypeEnum;
/**
* msg factory.
@@ -12,9 +11,6 @@ public class TronMessageFactory extends MessageFactory {
@Override
public TronMessage create(byte[] data) throws Exception {
- if (data.length <= 1){
- throw new P2pException(TypeEnum.MESSAGE_WITH_WRONG_LENGTH, "len=" + data.length);
- }
try {
byte type = data[0];
byte[] rawData = ArrayUtils.subarray(data, 1, data.length);
diff --git a/src/main/java/org/tron/core/net/node/NodeDelegate.java b/src/main/java/org/tron/core/net/node/NodeDelegate.java
index 2453c7dbe43..f485e13317c 100644
--- a/src/main/java/org/tron/core/net/node/NodeDelegate.java
+++ b/src/main/java/org/tron/core/net/node/NodeDelegate.java
@@ -49,4 +49,6 @@ Deque getBlockChainSummary(BlockId beginBLockId, Deque blockId
BlockCapsule getGenesisBlock();
boolean canChainRevoke(long num);
+
+ boolean forkOrNot(TransactionCapsule transactionCapsule);
}
diff --git a/src/main/java/org/tron/core/net/node/NodeDelegateImpl.java b/src/main/java/org/tron/core/net/node/NodeDelegateImpl.java
index 93942289324..c12c38df432 100755
--- a/src/main/java/org/tron/core/net/node/NodeDelegateImpl.java
+++ b/src/main/java/org/tron/core/net/node/NodeDelegateImpl.java
@@ -30,12 +30,16 @@
import org.tron.core.exception.DupTransactionException;
import org.tron.core.exception.ItemNotFoundException;
import org.tron.core.exception.NonCommonBlockException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.ReceiptException;
import org.tron.core.exception.StoreException;
import org.tron.core.exception.TaposException;
import org.tron.core.exception.TooBigTransactionException;
import org.tron.core.exception.TransactionExpirationException;
+import org.tron.core.exception.TransactionTraceException;
import org.tron.core.exception.TronException;
import org.tron.core.exception.UnLinkedBlockException;
+import org.tron.core.exception.UnsupportVMException;
import org.tron.core.exception.ValidateScheduleException;
import org.tron.core.exception.ValidateSignatureException;
import org.tron.core.net.message.BlockMessage;
@@ -95,8 +99,16 @@ public synchronized LinkedList handleBlock(BlockCapsule block, boole
throw new BadBlockException("TooBigTransaction exception," + e.getMessage());
} catch (TransactionExpirationException e) {
throw new BadBlockException("Expiration exception," + e.getMessage());
+ } catch (ReceiptException e) {
+ throw new BadBlockException("Receipt exception," + e.getMessage());
} catch (BadNumberBlockException e) {
throw new BadBlockException("bad number exception," + e.getMessage());
+ } catch (TransactionTraceException e) {
+ throw new BadBlockException("TransactionTrace Exception," + e.getMessage());
+ } catch (OutOfSlotTimeException e) {
+ throw new BadBlockException("TransactionTrace Exception," + e.getMessage());
+ } catch (UnsupportVMException e) {
+ throw new BadBlockException(e.getMessage());
}
}
@@ -112,8 +124,8 @@ public boolean handleTransaction(TransactionCapsule trx) throws BadTransactionEx
dbManager.getTransactionIdCache().put(trx.getTransactionId(), true);
}
try {
- dbManager.pushTransactions(trx);
- } catch (ContractSizeNotEqualToOneException e){
+ dbManager.pushTransaction(trx);
+ } catch (ContractSizeNotEqualToOneException e) {
logger.info("Contract validate failed" + e.getMessage());
throw new BadTransactionException();
} catch (ContractValidateException e) {
@@ -136,13 +148,25 @@ public boolean handleTransaction(TransactionCapsule trx) throws BadTransactionEx
} catch (TaposException e) {
logger.info("tapos error" + e.getMessage());
return false;
+ } catch (ReceiptException e) {
+ logger.info("Receipt exception," + e.getMessage());
} catch (TooBigTransactionException e) {
logger.info("too big transaction" + e.getMessage());
return false;
} catch (TransactionExpirationException e) {
logger.info("expiration transaction" + e.getMessage());
return false;
+ } catch (TransactionTraceException e) {
+ logger.info("TransactionTrace Exception" + e.getMessage());
+ return false;
+ } catch (OutOfSlotTimeException e) {
+ logger.info("OutOfSlotTimeException Exception" + e.getMessage());
+ return false;
+ } catch (UnsupportVMException e) {
+ logger.warn(e.getMessage());
+ return false;
}
+
return true;
}
@@ -365,4 +389,9 @@ public BlockCapsule getGenesisBlock() {
public boolean canChainRevoke(long num) {
return num >= dbManager.getSyncBeginNumber();
}
+
+ @Override
+ public boolean forkOrNot(TransactionCapsule transactionCapsule) {
+ return dbManager.getForkController().forkOrNot(transactionCapsule);
+ }
}
diff --git a/src/main/java/org/tron/core/net/node/NodeImpl.java b/src/main/java/org/tron/core/net/node/NodeImpl.java
index e30b48300cb..1c2eab5b107 100644
--- a/src/main/java/org/tron/core/net/node/NodeImpl.java
+++ b/src/main/java/org/tron/core/net/node/NodeImpl.java
@@ -4,8 +4,6 @@
import static org.tron.core.config.Parameter.NetConstants.MAX_TRX_PER_PEER;
import static org.tron.core.config.Parameter.NetConstants.MSG_CACHE_DURATION_IN_BLOCKS;
import static org.tron.core.config.Parameter.NetConstants.NET_MAX_TRX_PER_SECOND;
-import static org.tron.core.config.Parameter.NodeConstant.MAX_BLOCKS_ALREADY_FETCHED;
-import static org.tron.core.config.Parameter.NodeConstant.MAX_BLOCKS_IN_PROCESS;
import static org.tron.core.config.Parameter.NodeConstant.MAX_BLOCKS_SYNC_FROM_ONE_PEER;
import com.google.common.cache.Cache;
@@ -29,7 +27,6 @@
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
-import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
@@ -39,6 +36,7 @@
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
+import org.tron.common.overlay.discover.node.statistics.MessageCount;
import org.tron.common.overlay.message.Message;
import org.tron.common.overlay.server.Channel.TronState;
import org.tron.common.overlay.server.SyncPool;
@@ -83,6 +81,8 @@ public class NodeImpl extends PeerConnectionDelegate implements Node {
@Autowired
private SyncPool pool;
+ private MessageCount trxCount = new MessageCount();
+
private Cache TrxCache = CacheBuilder.newBuilder()
.maximumSize(100_000).expireAfterWrite(1, TimeUnit.HOURS).initialCapacity(100_000)
.recordStats().build();
@@ -144,29 +144,23 @@ public void clear() {
}
public void add(Entry id, PeerConnection peer) {
- if (send.containsKey(peer) && send.get(peer).containsKey(id.getValue())) {
- send.get(peer).get(id.getValue()).offer(id.getKey());
- } else if (send.containsKey(peer)) {
+ if (send.containsKey(peer) && !send.get(peer).containsKey(id.getValue())) {
send.get(peer).put(id.getValue(), new LinkedList<>());
- send.get(peer).get(id.getValue()).offer(id.getKey());
- } else {
+ } else if (!send.containsKey(peer)) {
send.put(peer, new HashMap<>());
send.get(peer).put(id.getValue(), new LinkedList<>());
- send.get(peer).get(id.getValue()).offer(id.getKey());
}
+ send.get(peer).get(id.getValue()).offer(id.getKey());
}
public void add(PriorItem id, PeerConnection peer) {
- if (send.containsKey(peer) && send.get(peer).containsKey(id.getType())) {
- send.get(peer).get(id.getType()).offer(id.getHash());
- } else if (send.containsKey(peer)) {
+ if (send.containsKey(peer) && !send.get(peer).containsKey(id.getType())) {
send.get(peer).put(id.getType(), new LinkedList<>());
- send.get(peer).get(id.getType()).offer(id.getHash());
- } else {
+ } else if (!send.containsKey(peer)) {
send.put(peer, new HashMap<>());
send.get(peer).put(id.getType(), new LinkedList<>());
- send.get(peer).get(id.getType()).offer(id.getHash());
}
+ send.get(peer).get(id.getType()).offer(id.getHash());
}
public int getSize(PeerConnection peer) {
@@ -205,9 +199,6 @@ void sendFetch() {
new ThreadFactoryBuilder()
.setNameFormat("TrxsHandlePool-%d").build());
- //public
- //TODO:need auto erase oldest block
-
private Queue freshBlockId = new ConcurrentLinkedQueue() {
@Override
public boolean offer(BlockId blockId) {
@@ -245,7 +236,7 @@ public boolean offer(BlockId blockId) {
private ExecutorService broadPool = Executors.newFixedThreadPool(2, new ThreadFactory() {
@Override
public Thread newThread(Runnable r) {
- return new Thread(r, "broad-msg-");
+ return new Thread(r, "broad-msg");
}
});
@@ -269,9 +260,6 @@ public Thread newThread(Runnable r) {
private ExecutorLoop loopAdvertiseInv;
- private ExecutorService handleBackLogBlocksPool = Executors.newCachedThreadPool();
-
-
private ScheduledExecutorService fetchSyncBlocksExecutor = Executors
.newSingleThreadScheduledExecutor();
@@ -528,6 +516,11 @@ private void consumerAdvObjToSpread() {
spread.putAll(advObjToSpread);
advObjToSpread.clear();
}
+ for (InventoryType type : spread.values()){
+ if (type == InventoryType.TRX){
+ trxCount.add();
+ }
+ }
getActivePeer().stream()
.filter(peer -> !peer.isNeedSyncFromUs())
.forEach(peer ->
@@ -543,10 +536,7 @@ private void consumerAdvObjToSpread() {
}
private synchronized void handleSyncBlock() {
- if (((ThreadPoolExecutor) handleBackLogBlocksPool).getActiveCount() > MAX_BLOCKS_IN_PROCESS) {
- logger.info("we're already processing too many blocks");
- return;
- } else if (isSuspendFetch) {
+ if (isSuspendFetch) {
isSuspendFetch = false;
}
@@ -594,14 +584,6 @@ private synchronized void handleSyncBlock() {
}
});
- if (((ThreadPoolExecutor) handleBackLogBlocksPool).getActiveCount() > MAX_BLOCKS_IN_PROCESS) {
- logger.info("we're already processing too many blocks");
- if (blockWaitToProc.size() >= MAX_BLOCKS_ALREADY_FETCHED) {
- isSuspendFetch = true;
- }
- break;
- }
-
}
}
@@ -632,37 +614,20 @@ private synchronized void logNodeStatus() {
}
public synchronized void disconnectInactive() {
- //logger.debug("size of activePeer: " + getActivePeer().size());
+
getActivePeer().forEach(peer -> {
final boolean[] isDisconnected = {false};
- final ReasonCode[] reasonCode = {ReasonCode.USER_REASON};
peer.getAdvObjWeRequested().values().stream()
.filter(time -> time < Time.getCurrentMillis() - NetConstants.ADV_TIME_OUT)
- .findFirst().ifPresent(time -> {
- isDisconnected[0] = true;
- reasonCode[0] = ReasonCode.FETCH_FAIL;
- });
+ .findFirst().ifPresent(time -> isDisconnected[0] = true);
if (!isDisconnected[0]) {
peer.getSyncBlockRequested().values().stream()
.filter(time -> time < Time.getCurrentMillis() - NetConstants.SYNC_TIME_OUT)
- .findFirst().ifPresent(time -> {
- isDisconnected[0] = true;
- reasonCode[0] = ReasonCode.SYNC_FAIL;
- });
+ .findFirst().ifPresent(time -> isDisconnected[0] = true);
}
-// TODO:optimize here
-// if (!isDisconnected[0]) {
-// if (del.getHeadBlockId().getNum() - peer.getHeadBlockWeBothHave().getNum()
-// > 2 * NetConstants.HEAD_NUM_CHECK_TIME / ChainConstant.BLOCK_PRODUCED_INTERVAL
-// && peer.getConnectTime() < Time.getCurrentMillis() - NetConstants.HEAD_NUM_CHECK_TIME
-// && peer.getSyncBlockRequested().isEmpty()) {
-// isDisconnected[0] = true;
-// }
-// }
-
if (isDisconnected[0]) {
disconnectPeer(peer, ReasonCode.TIME_OUT);
}
@@ -697,6 +662,7 @@ private void onHandleInventoryMessage(PeerConnection peer, InventoryMessage msg)
&& (peer.isAdvInvFull()
|| isFlooded())) {
logger.warn("A peer is flooding us, stop handle inv, the peer is: " + peer);
+ //todo,should be disconnect the peer?
return;
}
@@ -769,6 +735,10 @@ private void onHandleBlockMessage(PeerConnection peer, BlockMessage blkMsg) {
processAdvBlock(peer, blkMsg.getBlockCapsule());
startFetchItem();
}
+ } else {
+ if (!syncFlag) {//not we request and not sync,disconnect
+ banTraitorPeer(peer, ReasonCode.BAD_PROTOCOL);
+ }
}
}
@@ -885,7 +855,8 @@ private void onHandleTransactionMessage(PeerConnection peer, TransactionMessage
peer.getNode().getHost());
return;
}
- if(del.handleTransaction(trxMsg.getTransactionCapsule())){
+ if (del.forkOrNot(trxMsg.getTransactionCapsule())
+ && del.handleTransaction(trxMsg.getTransactionCapsule())) {
broadcast(trxMsg);
}
} catch (TraitorPeerException e) {
@@ -903,18 +874,32 @@ private void onHandleTransactionsMessage(PeerConnection peer, TransactionsMessag
}
}
+ private boolean checkSyncBlockChainMessage(PeerConnection peer, SyncBlockChainMessage syncMsg){
+ long lastBlockNum = syncMsg.getBlockIds().get(syncMsg.getBlockIds().size() - 1).getNum();
+ BlockId lastSyncBlockId = peer.getLastSyncBlockId();
+ if (lastSyncBlockId != null && lastBlockNum < lastSyncBlockId.getNum()){
+ logger.warn("Peer {} receive bad SyncBlockChain message, firstNum {} lastSyncNum {}.", peer.getInetAddress(), lastBlockNum, lastSyncBlockId.getNum());
+ return false;
+ }
+ return true;
+ }
+
private void onHandleSyncBlockChainMessage(PeerConnection peer, SyncBlockChainMessage syncMsg) {
peer.setTronState(TronState.SYNCING);
+ BlockId headBlockId = del.getHeadBlockId();
+ long remainNum = 0;
LinkedList blockIds = new LinkedList<>();
List summaryChainIds = syncMsg.getBlockIds();
- long remainNum = 0;
-
+ if (!checkSyncBlockChainMessage(peer, syncMsg)){
+ disconnectPeer(peer, ReasonCode.BAD_PROTOCOL);
+ return;
+ }
try {
blockIds = del.getLostBlockIds(summaryChainIds);
} catch (StoreException e) {
logger.error(e.getMessage());
}
-
+
if (blockIds.isEmpty()) {
if (CollectionUtils.isNotEmpty(summaryChainIds) && !del
.canChainRevoke(summaryChainIds.get(0).getNum())) {
@@ -943,15 +928,80 @@ private void onHandleSyncBlockChainMessage(PeerConnection peer, SyncBlockChainMe
startSyncWithPeer(peer);
}
+ if (blockIds.peekLast() == null){
+ peer.setLastSyncBlockId(headBlockId);
+ }else {
+ peer.setLastSyncBlockId(blockIds.peekLast());
+ }
+ peer.setRemainNum(remainNum);
peer.sendMessage(new ChainInventoryMessage(blockIds, remainNum));
}
+ private boolean checkFetchInvDataMsg(PeerConnection peer, FetchInvDataMessage fetchInvDataMsg){
+ MessageTypes type = fetchInvDataMsg.getInvMessageType();
+ if (type == MessageTypes.TRX) {
+ int elementCount = peer.getNodeStatistics().messageStatistics.tronInTrxFetchInvDataElement.getCount(10);
+ int maxCount = trxCount.getCount(60);
+ if (elementCount > maxCount){
+ logger.warn("Check FetchInvDataMsg failed: Peer {} request count {} in 10s gt trx count {} generate in 60s", peer.getInetAddress(), elementCount, maxCount);
+ return false;
+ }
+ for (Sha256Hash hash : fetchInvDataMsg.getHashList()) {
+ if (!peer.getAdvObjWeSpread().containsKey(hash)){
+ logger.warn("Check FetchInvDataMsg failed: Peer {} get trx {} we not spread.", peer.getInetAddress(), hash);
+ return false;
+ }
+ }
+ }else {
+ boolean isAdv = true;
+ for (Sha256Hash hash : fetchInvDataMsg.getHashList()) {
+ if (!peer.getAdvObjWeSpread().containsKey(hash)){
+ isAdv = false;
+ break;
+ }
+ }
+ if (isAdv){
+ MessageCount tronOutAdvBlock = peer.getNodeStatistics().messageStatistics.tronOutAdvBlock;
+ tronOutAdvBlock.add(fetchInvDataMsg.getHashList().size());
+ int outBlockCountIn1min = tronOutAdvBlock.getCount(60);
+ int producedBlockIn2min = 120_000 / ChainConstant.BLOCK_PRODUCED_INTERVAL;
+ if (outBlockCountIn1min > producedBlockIn2min){
+ logger.warn("Check FetchInvDataMsg failed: Peer {} outBlockCount {} producedBlockIn2min {}",
+ peer.getInetAddress(), outBlockCountIn1min, producedBlockIn2min);
+ return false;
+ }
+ }else {
+ if (!peer.isNeedSyncFromUs()){
+ logger.warn("Check FetchInvDataMsg failed: Peer {} not need sync from us.", peer.getInetAddress());
+ return false;
+ }
+ for (Sha256Hash hash : fetchInvDataMsg.getHashList()) {
+ long blockNum = new BlockId(hash).getNum();
+ long minBlockNum = peer.getLastSyncBlockId().getNum() - 2 * NodeConstant.SYNC_FETCH_BATCH_NUM;
+ if (blockNum < minBlockNum){
+ logger.warn("Check FetchInvDataMsg failed: Peer {} blockNum {} lt minBlockNum {}", peer.getInetAddress(), blockNum, minBlockNum);
+ return false;
+ }
+ if (peer.getSyncBlockIdCache().getIfPresent(hash) != null){
+ logger.warn("Check FetchInvDataMsg failed: Peer {} blockNum {} hash {} is exist", peer.getInetAddress(), blockNum, hash);
+ return false;
+ }
+ peer.getSyncBlockIdCache().put(hash, 1);
+ }
+ }
+ }
+ return true;
+ }
+
private void onHandleFetchDataMessage(PeerConnection peer, FetchInvDataMessage fetchInvDataMsg) {
- MessageTypes type = fetchInvDataMsg.getInvMessageType();
+ if (!checkFetchInvDataMsg(peer, fetchInvDataMsg)){
+ disconnectPeer(peer, ReasonCode.BAD_PROTOCOL);
+ return;
+ }
+ MessageTypes type = fetchInvDataMsg.getInvMessageType();
BlockCapsule block = null;
-
List transactions = Lists.newArrayList();
int size = 0;
@@ -973,6 +1023,7 @@ private void onHandleFetchDataMessage(PeerConnection peer, FetchInvDataMessage f
if (msg == null) {
logger.error("fetch message {} {} failed.", type, hash);
peer.sendMessage(new ItemNotFound());
+ //todo,should be disconnect?
return;
}
@@ -1181,8 +1232,7 @@ private synchronized void startFetchSyncBlock() {
if (!send.containsKey(peer)) { //TODO: Attention multi thread here
send.put(peer, new LinkedList<>());
}
- for (BlockId blockId :
- peer.getSyncBlockToFetch()) {
+ for (BlockId blockId : peer.getSyncBlockToFetch()) {
if (!request.contains(blockId) //TODO: clean processing block
&& (syncBlockIdWeRequested.getIfPresent(blockId) == null)) {
send.get(peer).add(blockId);
@@ -1303,7 +1353,6 @@ public void shutDown() {
loopSyncBlockChain.shutdown();
loopFetchBlocks.shutdown();
loopAdvertiseInv.shutdown();
- handleBackLogBlocksPool.shutdown();
fetchSyncBlocksExecutor.shutdown();
handleSyncBlockExecutor.shutdown();
}
diff --git a/src/main/java/org/tron/core/net/peer/PeerConnection.java b/src/main/java/org/tron/core/net/peer/PeerConnection.java
index 79dec0fa556..233adcaab93 100644
--- a/src/main/java/org/tron/core/net/peer/PeerConnection.java
+++ b/src/main/java/org/tron/core/net/peer/PeerConnection.java
@@ -3,8 +3,9 @@
import static org.tron.core.config.Parameter.NetConstants.MAX_INVENTORY_SIZE_IN_MINUTES;
import static org.tron.core.config.Parameter.NetConstants.NET_MAX_TRX_PER_SECOND;
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
import java.util.Deque;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
@@ -15,6 +16,8 @@
import java.util.concurrent.ConcurrentLinkedDeque;
import java.util.concurrent.LinkedBlockingQueue;
import javafx.util.Pair;
+import lombok.Getter;
+import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@@ -24,6 +27,7 @@
import org.tron.common.utils.Sha256Hash;
import org.tron.common.utils.Time;
import org.tron.core.capsule.BlockCapsule.BlockId;
+import org.tron.core.config.Parameter.NodeConstant;
import org.tron.core.net.node.Item;
@Slf4j
@@ -31,6 +35,17 @@
@Scope("prototype")
public class PeerConnection extends Channel {
+ private Cache syncBlockIdCache = CacheBuilder.newBuilder()
+ .maximumSize(2 * NodeConstant.SYNC_FETCH_BATCH_NUM).build();
+
+ @Setter
+ @Getter
+ private BlockId lastSyncBlockId;
+
+ @Setter
+ @Getter
+ private long remainNum;
+
private volatile boolean syncFlag = true;
private HelloMessage helloMessage;
@@ -52,19 +67,10 @@ public Map getAdvObjSpreadToUs() {
return advObjSpreadToUs;
}
- public void setAdvObjSpreadToUs(
- HashMap advObjSpreadToUs) {
- this.advObjSpreadToUs = advObjSpreadToUs;
- }
-
public Map getAdvObjWeSpread() {
return advObjWeSpread;
}
- public void setAdvObjWeSpread(HashMap advObjWeSpread) {
- this.advObjWeSpread = advObjWeSpread;
- }
-
public boolean isAdvInhibit() {
return advInhibit;
}
@@ -88,6 +94,10 @@ public Pair, Long> getSyncChainRequested() {
return syncChainRequested;
}
+ public Cache getSyncBlockIdCache() {
+ return syncBlockIdCache;
+ }
+
public void setSyncChainRequested(
Pair, Long> syncChainRequested) {
this.syncChainRequested = syncChainRequested;
@@ -168,7 +178,7 @@ private void removeIterator(Iterator> iterator, long old
}
public boolean isAdvInvFull() {
- return advObjSpreadToUs.size() > MAX_INVENTORY_SIZE_IN_MINUTES * 60 * NET_MAX_TRX_PER_SECOND;
+ return advObjSpreadToUs.size() > MAX_INVENTORY_SIZE_IN_MINUTES * 60 * NET_MAX_TRX_PER_SECOND;
}
public boolean isBanned() {
@@ -280,6 +290,5 @@ public boolean idle() {
public void sendMessage(Message message) {
msgQueue.sendMessage(message);
- nodeStatistics.tronOutMessage.add();
}
}
diff --git a/src/main/java/org/tron/core/services/RpcApiService.java b/src/main/java/org/tron/core/services/RpcApiService.java
index a9c4f8ee1d2..3e7c44ec12a 100755
--- a/src/main/java/org/tron/core/services/RpcApiService.java
+++ b/src/main/java/org/tron/core/services/RpcApiService.java
@@ -17,7 +17,6 @@
import org.apache.commons.codec.binary.Hex;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
-import org.springframework.util.CollectionUtils;
import org.tron.api.DatabaseGrpc.DatabaseImplBase;
import org.tron.api.GrpcAPI;
import org.tron.api.GrpcAPI.AccountNetMessage;
@@ -36,6 +35,7 @@
import org.tron.api.GrpcAPI.EasyTransferMessage;
import org.tron.api.GrpcAPI.EasyTransferResponse;
import org.tron.api.GrpcAPI.EmptyMessage;
+import org.tron.api.GrpcAPI.ExchangeList;
import org.tron.api.GrpcAPI.Node;
import org.tron.api.GrpcAPI.NodeList;
import org.tron.api.GrpcAPI.NumberMessage;
@@ -58,36 +58,32 @@
import org.tron.common.utils.Sha256Hash;
import org.tron.common.utils.StringUtil;
import org.tron.common.utils.Utils;
-import org.tron.core.Constant;
import org.tron.core.Wallet;
import org.tron.core.WalletSolidity;
-import org.tron.core.actuator.Actuator;
-import org.tron.core.actuator.ActuatorFactory;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.BlockCapsule;
-import org.tron.core.capsule.ContractCapsule;
import org.tron.core.capsule.TransactionCapsule;
import org.tron.core.capsule.WitnessCapsule;
import org.tron.core.config.args.Args;
import org.tron.core.db.BandwidthProcessor;
import org.tron.core.db.Manager;
import org.tron.core.exception.ContractValidateException;
-import org.tron.core.exception.HeaderNotFound;
import org.tron.core.exception.StoreException;
import org.tron.protos.Contract;
import org.tron.protos.Contract.AccountCreateContract;
import org.tron.protos.Contract.AssetIssueContract;
-import org.tron.protos.Contract.CreateSmartContract;
import org.tron.protos.Contract.ParticipateAssetIssueContract;
import org.tron.protos.Contract.TransferAssetContract;
import org.tron.protos.Contract.TransferContract;
import org.tron.protos.Contract.UnfreezeAssetContract;
+import org.tron.protos.Contract.UpdateSettingContract;
import org.tron.protos.Contract.VoteWitnessContract;
import org.tron.protos.Contract.WitnessCreateContract;
import org.tron.protos.Protocol;
import org.tron.protos.Protocol.Account;
import org.tron.protos.Protocol.Block;
import org.tron.protos.Protocol.DynamicProperties;
+import org.tron.protos.Protocol.Exchange;
import org.tron.protos.Protocol.Proposal;
import org.tron.protos.Protocol.Transaction;
import org.tron.protos.Protocol.Transaction.Contract.ContractType;
@@ -577,50 +573,7 @@ private void createTransactionExtention(Message request, ContractType contractTy
private TransactionCapsule createTransactionCapsule(com.google.protobuf.Message message,
ContractType contractType) throws ContractValidateException {
- TransactionCapsule trx = new TransactionCapsule(message, contractType);
- if (contractType != ContractType.CreateSmartContract
- && contractType != ContractType.TriggerSmartContract) {
- List actList = ActuatorFactory.createActuator(trx, dbManager);
- for (Actuator act : actList) {
- act.validate();
- }
- }
-
- if (contractType == ContractType.CreateSmartContract) {
- // insure one owner just have one contract
- CreateSmartContract contract = ContractCapsule
- .getSmartContractFromTransaction(trx.getInstance());
- byte[] ownerAddress = contract.getOwnerAddress().toByteArray();
- if (dbManager.getAccountContractIndexStore().get(ownerAddress) != null) {
- throw new ContractValidateException(
- "Trying to create second contract with one account: address: " + Wallet
- .encode58Check(ownerAddress));
- }
-
-// // insure the new contract address haven't exist
-// if (deposit.getAccount(contractAddress) != null) {
-// logger.error("Trying to create a contract with existing contract address: " + Wallet
-// .encode58Check(contractAddress));
-// return;
-// }
- }
-
- try {
- BlockCapsule headBlock = null;
- List blockList = dbManager.getBlockStore().getBlockByLatestNum(1);
- if (CollectionUtils.isEmpty(blockList)) {
- throw new HeaderNotFound("latest block not found");
- } else {
- headBlock = blockList.get(0);
- }
- trx.setReference(headBlock.getNum(), headBlock.getBlockId().getBytes());
- long expiration = headBlock.getTimeStamp() + Constant.TRANSACTION_DEFAULT_EXPIRATION_TIME;
- trx.setExpiration(expiration);
- trx.setTimestamp();
- } catch (HeaderNotFound headerNotFound) {
- headerNotFound.printStackTrace();
- }
- return trx;
+ return wallet.createTransactionCapsule(message, contractType);
}
@Override
@@ -805,6 +758,13 @@ public void voteWitnessAccount2(VoteWitnessContract request,
createTransactionExtention(request, ContractType.VoteWitnessContract, responseObserver);
}
+ @Override
+ public void updateSetting(UpdateSettingContract request,
+ StreamObserver responseObserver) {
+ createTransactionExtention(request, ContractType.UpdateSettingContract,
+ responseObserver);
+ }
+
@Override
public void createWitness(WitnessCreateContract request,
StreamObserver responseObserver) {
@@ -1001,16 +961,48 @@ public void proposalDelete(Contract.ProposalDeleteContract request,
createTransactionExtention(request, ContractType.ProposalDeleteContract, responseObserver);
}
+// @Override
+// public void buyStorage(Contract.BuyStorageContract request,
+// StreamObserver responseObserver) {
+// createTransactionExtention(request, ContractType.BuyStorageContract, responseObserver);
+// }
+//
+// @Override
+// public void buyStorageBytes(Contract.BuyStorageBytesContract request,
+// StreamObserver responseObserver) {
+// createTransactionExtention(request, ContractType.BuyStorageBytesContract, responseObserver);
+// }
+//
+// @Override
+// public void sellStorage(Contract.SellStorageContract request,
+// StreamObserver responseObserver) {
+// createTransactionExtention(request, ContractType.SellStorageContract, responseObserver);
+// }
+
+ @Override
+ public void exchangeCreate(Contract.ExchangeCreateContract request,
+ StreamObserver responseObserver) {
+ createTransactionExtention(request, ContractType.ExchangeCreateContract, responseObserver);
+ }
+
+
@Override
- public void buyStorage(Contract.BuyStorageContract request,
+ public void exchangeInject(Contract.ExchangeInjectContract request,
StreamObserver responseObserver) {
- createTransactionExtention(request, ContractType.BuyStorageContract, responseObserver);
+ createTransactionExtention(request, ContractType.ExchangeInjectContract, responseObserver);
}
@Override
- public void sellStorage(Contract.SellStorageContract request,
+ public void exchangeWithdraw(Contract.ExchangeWithdrawContract request,
StreamObserver responseObserver) {
- createTransactionExtention(request, ContractType.SellStorageContract, responseObserver);
+ createTransactionExtention(request, ContractType.ExchangeWithdrawContract, responseObserver);
+ }
+
+ @Override
+ public void exchangeTransaction(Contract.ExchangeTransactionContract request,
+ StreamObserver responseObserver) {
+ createTransactionExtention(request, ContractType.ExchangeTransactionContract,
+ responseObserver);
}
@Override
@@ -1201,6 +1193,19 @@ public void getProposalById(BytesMessage request,
responseObserver.onCompleted();
}
+ @Override
+ public void getExchangeById(BytesMessage request,
+ StreamObserver responseObserver) {
+ ByteString exchangeId = request.getValue();
+
+ if (Objects.nonNull(exchangeId)) {
+ responseObserver.onNext(wallet.getExchangeById(exchangeId));
+ } else {
+ responseObserver.onNext(null);
+ }
+ responseObserver.onCompleted();
+ }
+
@Override
public void getBlockByLimitNext(BlockLimit request,
StreamObserver responseObserver) {
@@ -1304,7 +1309,7 @@ public void triggerContract(Contract.TriggerSmartContract request,
try {
TransactionCapsule trxCap = createTransactionCapsule(request,
ContractType.TriggerSmartContract);
- trx = wallet.triggerContract(request, trxCap);
+ trx = wallet.triggerContract(request, trxCap, trxExtBuilder, retBuilder);
trxExtBuilder.setTransaction(trx);
trxExtBuilder.setTxid(trxCap.getTransactionId().getByteString());
retBuilder.setResult(true).setCode(response_code.SUCCESS);
@@ -1312,6 +1317,7 @@ public void triggerContract(Contract.TriggerSmartContract request,
retBuilder.setResult(false).setCode(response_code.CONTRACT_VALIDATE_ERROR)
.setMessage(ByteString.copyFromUtf8("contract validate error : " + e.getMessage()));
logger.debug("ContractValidateException: {}", e.getMessage());
+ // FIXME
return;
} catch (Exception e) {
retBuilder.setResult(false).setCode(response_code.OTHER_ERROR)
@@ -1353,6 +1359,13 @@ public void listProposals(EmptyMessage request,
responseObserver.onCompleted();
}
+ @Override
+ public void listExchanges(EmptyMessage request,
+ StreamObserver responseObserver) {
+ responseObserver.onNext(wallet.getExchangeList());
+ responseObserver.onCompleted();
+ }
+
@Override
public void getChainParameters(EmptyMessage request,
StreamObserver responseObserver) {
diff --git a/src/main/java/org/tron/core/services/WitnessService.java b/src/main/java/org/tron/core/services/WitnessService.java
index 4bfeb902082..5003a42bcdc 100755
--- a/src/main/java/org/tron/core/services/WitnessService.java
+++ b/src/main/java/org/tron/core/services/WitnessService.java
@@ -8,9 +8,9 @@
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.DateTime;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.Service;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.backup.BackupManager;
import org.tron.common.backup.BackupManager.BackupStatusEnum;
import org.tron.common.backup.BackupServer;
@@ -24,6 +24,8 @@
import org.tron.core.exception.AccountResourceInsufficientException;
import org.tron.core.exception.ContractExeException;
import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.ReceiptException;
+import org.tron.core.exception.TransactionTraceException;
import org.tron.core.exception.TronException;
import org.tron.core.exception.UnLinkedBlockException;
import org.tron.core.exception.ValidateScheduleException;
@@ -43,13 +45,14 @@ public class WitnessService implements Service {
protected Map localWitnessStateMap = Maps
.newHashMap(); //
private Thread generateThread;
+
private volatile boolean isRunning = false;
private Map privateKeyMap = Maps.newHashMap();
private volatile boolean needSyncCheck = Args.getInstance().isNeedSyncCheck();
private WitnessController controller;
- private AnnotationConfigApplicationContext context;
+ private TronApplicationContext context;
private BackupManager backupManager;
@@ -58,18 +61,19 @@ public class WitnessService implements Service {
/**
* Construction method.
*/
- public WitnessService(Application tronApp, AnnotationConfigApplicationContext context) {
+ public WitnessService(Application tronApp, TronApplicationContext context) {
this.tronApp = tronApp;
this.context = context;
backupManager = context.getBean(BackupManager.class);
backupServer = context.getBean(BackupServer.class);
generateThread = new Thread(scheduleProductionLoop);
controller = tronApp.getDbManager().getWitnessController();
- new Thread(()->{
- while (needSyncCheck){
- try{
+ new Thread(() -> {
+ while (needSyncCheck) {
+ try {
Thread.sleep(100);
- }catch (Exception e){}
+ } catch (Exception e) {
+ }
}
backupServer.initServer();
}).start();
@@ -136,7 +140,7 @@ private void blockProductionLoop() throws InterruptedException {
*/
private BlockProductionCondition tryProduceBlock() throws InterruptedException {
logger.info("Try Produce Block");
- if (!backupManager.getStatus().equals(BackupStatusEnum.MASTER)){
+ if (!backupManager.getStatus().equals(BackupStatusEnum.MASTER)) {
return BlockProductionCondition.BACKUP_STATUS_IS_NOT_MASTER;
}
long now = DateTime.now().getMillis() + 50L;
@@ -218,6 +222,7 @@ private BlockProductionCondition tryProduceBlock() throws InterruptedException {
}
try {
+
controller.setGeneratingBlock(true);
BlockCapsule block = generateBlock(scheduledTime, scheduledWitness);
@@ -248,7 +253,6 @@ private BlockProductionCondition tryProduceBlock() throws InterruptedException {
} finally {
controller.setGeneratingBlock(false);
}
-
}
private void broadcastBlock(BlockCapsule block) {
@@ -260,7 +264,7 @@ private void broadcastBlock(BlockCapsule block) {
}
private BlockCapsule generateBlock(long when, ByteString witnessAddress)
- throws ValidateSignatureException, ContractValidateException, ContractExeException, UnLinkedBlockException, ValidateScheduleException, AccountResourceInsufficientException {
+ throws ValidateSignatureException, ContractValidateException, ContractExeException, UnLinkedBlockException, ValidateScheduleException, AccountResourceInsufficientException, ReceiptException, TransactionTraceException {
return tronApp.getDbManager().generateBlock(this.localWitnessStateMap.get(witnessAddress), when,
this.privateKeyMap.get(witnessAddress));
}
@@ -298,6 +302,7 @@ public void init(Args args) {
public void start() {
isRunning = true;
generateThread.start();
+
}
@Override
diff --git a/src/main/java/org/tron/core/services/http/DeployContractServlet.java b/src/main/java/org/tron/core/services/http/DeployContractServlet.java
new file mode 100644
index 00000000000..b4d0ecb44dd
--- /dev/null
+++ b/src/main/java/org/tron/core/services/http/DeployContractServlet.java
@@ -0,0 +1,87 @@
+package org.tron.core.services.http;
+
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.base.Strings;
+import com.google.protobuf.ByteString;
+import java.io.IOException;
+import java.util.stream.Collectors;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.tron.common.utils.ByteArray;
+import org.tron.core.Wallet;
+import org.tron.protos.Contract.CreateSmartContract;
+import org.tron.protos.Protocol.SmartContract;
+import org.tron.protos.Protocol.SmartContract.ABI;
+import org.tron.protos.Protocol.Transaction;
+import org.tron.protos.Protocol.Transaction.Contract.ContractType;
+
+
+@Component
+@Slf4j
+public class DeployContractServlet extends HttpServlet {
+
+ @Autowired
+ private Wallet wallet;
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) {
+ }
+
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) {
+ try {
+ String contract = request.getReader().lines()
+ .collect(Collectors.joining(System.lineSeparator()));
+ CreateSmartContract.Builder build = CreateSmartContract.newBuilder();
+ JSONObject jsonObject = JSONObject.parseObject(contract);
+ byte[] ownerAddress = ByteArray.fromHexString(jsonObject.getString("owner_address"));
+ build.setOwnerAddress(ByteString.copyFrom(ownerAddress));
+
+ String abi = jsonObject.getString("abi");
+ StringBuffer abiSB = new StringBuffer("{");
+ abiSB.append("\"entrys\":");
+ abiSB.append(abi);
+ abiSB.append("}");
+ ABI.Builder abiBuilder = ABI.newBuilder();
+ JsonFormat.merge(abiSB.toString(), abiBuilder);
+
+ long feeLimit = jsonObject.getLongValue("fee_limit");
+
+ SmartContract.Builder smartBuilder = SmartContract.newBuilder();
+ smartBuilder.setAbi(abiBuilder)
+ .setCallValue(jsonObject.getLongValue("call_value"))
+ .setConsumeUserResourcePercent(jsonObject.getLongValue("consume_user_resource_percent"));
+ if (!ArrayUtils.isEmpty(ownerAddress)) {
+ smartBuilder.setOriginAddress(ByteString.copyFrom(ownerAddress));
+ }
+
+ byte[] byteCode = ByteArray.fromHexString(jsonObject.getString("bytecode"));
+ if (!ArrayUtils.isEmpty(byteCode)) {
+ smartBuilder.setBytecode(ByteString.copyFrom(byteCode));
+ }
+ String name = jsonObject.getString("name");
+ if (!Strings.isNullOrEmpty(name)) {
+ smartBuilder.setName(name);
+ }
+
+ build.setNewContract(smartBuilder);
+ Transaction tx = wallet
+ .createTransactionCapsule(build.build(), ContractType.CreateSmartContract).getInstance();
+ Transaction.Builder txBuilder = tx.toBuilder();
+ Transaction.raw.Builder rawBuilder = tx.getRawData().toBuilder();
+ rawBuilder.setFeeLimit(feeLimit);
+ txBuilder.setRawData(rawBuilder);
+ response.getWriter().println(Util.printTransaction(txBuilder.build()));
+ } catch (Exception e) {
+ logger.debug("Exception: {}", e.getMessage());
+ try {
+ response.getWriter().println(Util.printErrorMsg(e));
+ } catch (IOException ioe) {
+ logger.debug("IOException: {}", ioe.getMessage());
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/tron/core/services/http/FullNodeHttpApiService.java b/src/main/java/org/tron/core/services/http/FullNodeHttpApiService.java
index ff23e337949..66ba259f493 100644
--- a/src/main/java/org/tron/core/services/http/FullNodeHttpApiService.java
+++ b/src/main/java/org/tron/core/services/http/FullNodeHttpApiService.java
@@ -91,6 +91,12 @@ public class FullNodeHttpApiService implements Service {
private GenerateAddressServlet generateAddressServlet;
@Autowired
private ValidateAddressServlet validateAddressServlet;
+ @Autowired
+ private DeployContractServlet deployContractServlet;
+ @Autowired
+ private TriggerSmartContractServlet triggerSmartContractServlet;
+ @Autowired
+ private GetContractServlet getContractServlet;
@Override
public void init() {
@@ -149,6 +155,9 @@ public void start() {
context.addServlet(new ServletHolder(easyTransferByPrivateServlet), "/easytransferbyprivate");
context.addServlet(new ServletHolder(generateAddressServlet), "/generateaddress");
context.addServlet(new ServletHolder(validateAddressServlet), "/validateaddress");
+ context.addServlet(new ServletHolder(deployContractServlet), "/deploycontract");
+ context.addServlet(new ServletHolder(triggerSmartContractServlet), "/triggersmartcontract");
+ context.addServlet(new ServletHolder(getContractServlet), "/getcontract");
server.start();
} catch (Exception e) {
logger.debug("IOException: {}", e.getMessage());
diff --git a/src/main/java/org/tron/core/services/http/GetContractServlet.java b/src/main/java/org/tron/core/services/http/GetContractServlet.java
new file mode 100644
index 00000000000..fa310ba585b
--- /dev/null
+++ b/src/main/java/org/tron/core/services/http/GetContractServlet.java
@@ -0,0 +1,62 @@
+package org.tron.core.services.http;
+
+import com.alibaba.fastjson.JSONObject;
+import java.io.IOException;
+import java.util.stream.Collectors;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.tron.api.GrpcAPI.BytesMessage;
+import org.tron.core.Wallet;
+import org.tron.protos.Protocol.SmartContract;
+
+
+@Component
+@Slf4j
+public class GetContractServlet extends HttpServlet {
+
+ @Autowired
+ private Wallet wallet;
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) {
+ try {
+ String input = request.getParameter("value");
+ JSONObject jsonObject = new JSONObject();
+ jsonObject.put("value", input);
+ BytesMessage.Builder build = BytesMessage.newBuilder();
+ JsonFormat.merge(jsonObject.toJSONString(), build);
+ SmartContract smartContract = wallet.getContract(build.build());
+ JSONObject jsonSmartContract = JSONObject.parseObject(JsonFormat.printToString(smartContract));
+ response.getWriter().println(jsonSmartContract.toJSONString());
+ } catch (Exception e) {
+ logger.debug("Exception: {}", e.getMessage());
+ try {
+ response.getWriter().println(Util.printErrorMsg(e));
+ } catch (IOException ioe) {
+ logger.debug("IOException: {}", ioe.getMessage());
+ }
+ }
+ }
+
+ protected void doPost(HttpServletRequest request, HttpServletResponse response) {
+ try {
+ String input = request.getReader().lines()
+ .collect(Collectors.joining(System.lineSeparator()));
+ BytesMessage.Builder build = BytesMessage.newBuilder();
+ JsonFormat.merge(input, build);
+ SmartContract smartContract = wallet.getContract(build.build());
+ JSONObject jsonSmartContract = JSONObject.parseObject(JsonFormat.printToString(smartContract));
+ response.getWriter().println(jsonSmartContract.toJSONString());
+ } catch (Exception e) {
+ logger.debug("Exception: {}", e.getMessage());
+ try {
+ response.getWriter().println(Util.printErrorMsg(e));
+ } catch (IOException ioe) {
+ logger.debug("IOException: {}", ioe.getMessage());
+ }
+ }
+ }
+}
diff --git a/src/main/java/org/tron/core/services/http/JsonFormat.java b/src/main/java/org/tron/core/services/http/JsonFormat.java
index af4eb7132c6..7f2143820ce 100644
--- a/src/main/java/org/tron/core/services/http/JsonFormat.java
+++ b/src/main/java/org/tron/core/services/http/JsonFormat.java
@@ -49,6 +49,7 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import org.apache.commons.lang3.StringUtils;
import org.tron.common.utils.ByteArray;
@@ -625,6 +626,12 @@ private static Object handlePrimitive(Tokenizer tokenizer, FieldDescriptor field
}
} else {
String id = tokenizer.consumeIdentifier();
+ if (StringUtils.isAllLowerCase(id)){
+ char b = id.charAt(0);
+ b = (char)(b + 'A' - 'a');
+ String s = id.substring(1);
+ id = b + s;
+ }
value = enumType.findValueByName(id);
if (value == null) {
throw tokenizer.parseExceptionPreviousToken("Enum type \""
diff --git a/src/main/java/org/tron/core/services/http/TriggerSmartContractServlet.java b/src/main/java/org/tron/core/services/http/TriggerSmartContractServlet.java
new file mode 100644
index 00000000000..be56103c193
--- /dev/null
+++ b/src/main/java/org/tron/core/services/http/TriggerSmartContractServlet.java
@@ -0,0 +1,91 @@
+package org.tron.core.services.http;
+
+import com.alibaba.fastjson.JSONObject;
+import com.google.protobuf.ByteString;
+import java.io.IOException;
+import java.util.stream.Collectors;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.spongycastle.util.encoders.Hex;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.tron.api.GrpcAPI.Return;
+import org.tron.api.GrpcAPI.Return.response_code;
+import org.tron.api.GrpcAPI.TransactionExtention;
+import org.tron.common.crypto.Hash;
+import org.tron.common.utils.ByteArray;
+import org.tron.core.Wallet;
+import org.tron.core.capsule.TransactionCapsule;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.protos.Contract.TriggerSmartContract;
+import org.tron.protos.Protocol.Transaction;
+import org.tron.protos.Protocol.Transaction.Contract.ContractType;
+
+
+@Component
+@Slf4j
+public class TriggerSmartContractServlet extends HttpServlet {
+
+ @Autowired
+ private Wallet wallet;
+
+ protected void doGet(HttpServletRequest request, HttpServletResponse response) {
+ }
+
+ public static String parseMethod(String methodSign, String params) {
+ byte[] selector = new byte[4];
+ System.arraycopy(Hash.sha3(methodSign.getBytes()), 0, selector, 0, 4);
+ System.out.println(methodSign + ":" + Hex.toHexString(selector));
+ if (StringUtils.isEmpty(params)) {
+ return Hex.toHexString(selector);
+ }
+ String result = Hex.toHexString(selector) + params;
+ return result;
+ }
+
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws IOException {
+ TriggerSmartContract.Builder build = TriggerSmartContract.newBuilder();
+ TransactionExtention.Builder trxExtBuilder = TransactionExtention.newBuilder();
+ Return.Builder retBuilder = Return.newBuilder();
+
+ try {
+ String contract = request.getReader().lines()
+ .collect(Collectors.joining(System.lineSeparator()));
+ JsonFormat.merge(contract, build);
+ JSONObject jsonObject = JSONObject.parseObject(contract);
+ String selector = jsonObject.getString("function_selector");
+ String parameter = jsonObject.getString("parameter");
+ String data = parseMethod(selector, parameter);
+ build.setData(ByteString.copyFrom(ByteArray.fromHexString(data)));
+
+ long feeLimit = jsonObject.getLongValue("fee_limit");
+
+ TransactionCapsule trxCap = wallet
+ .createTransactionCapsule(build.build(), ContractType.TriggerSmartContract);
+
+ Transaction.Builder txBuilder = trxCap.getInstance().toBuilder();
+ Transaction.raw.Builder rawBuilder = trxCap.getInstance().getRawData().toBuilder();
+ rawBuilder.setFeeLimit(feeLimit);
+ txBuilder.setRawData(rawBuilder);
+
+ Transaction trx = wallet
+ .triggerContract(build.build(), new TransactionCapsule(txBuilder.build()), trxExtBuilder,
+ retBuilder);
+ trxExtBuilder.setTransaction(trx);
+ trxExtBuilder.setTxid(trxCap.getTransactionId().getByteString());
+ retBuilder.setResult(true).setCode(response_code.SUCCESS);
+ } catch (ContractValidateException e) {
+ retBuilder.setResult(false).setCode(response_code.CONTRACT_VALIDATE_ERROR)
+ .setMessage(ByteString.copyFromUtf8(e.getMessage()));
+ } catch (Exception e) {
+ retBuilder.setResult(false).setCode(response_code.OTHER_ERROR)
+ .setMessage(ByteString.copyFromUtf8(e.getClass() + " : " + e.getMessage()));
+ }
+ trxExtBuilder.setResult(retBuilder);
+ response.getWriter().println(Util.printTransactionExtention(trxExtBuilder.build()));
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/org/tron/core/services/http/Util.java b/src/main/java/org/tron/core/services/http/Util.java
index 188d7c66675..499e028bd96 100644
--- a/src/main/java/org/tron/core/services/http/Util.java
+++ b/src/main/java/org/tron/core/services/http/Util.java
@@ -8,7 +8,9 @@
import lombok.extern.slf4j.Slf4j;
import org.tron.api.GrpcAPI.BlockList;
import org.tron.api.GrpcAPI.EasyTransferResponse;
+import org.tron.api.GrpcAPI.TransactionExtention;
import org.tron.api.GrpcAPI.TransactionList;
+import org.tron.common.crypto.Hash;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.Sha256Hash;
import org.tron.core.capsule.BlockCapsule;
@@ -41,7 +43,7 @@ public class Util {
public static String printErrorMsg(Exception e) {
JSONObject jsonObject = new JSONObject();
- jsonObject.put("Error", e.getMessage());
+ jsonObject.put("Error", e.getClass() + " : " + e.getMessage());
return jsonObject.toJSONString();
}
@@ -102,6 +104,27 @@ public static String printTransaction(Transaction transaction) {
return printTransactionToJSON(transaction).toJSONString();
}
+ public static String printTransactionExtention(TransactionExtention transactionExtention) {
+ String string = JsonFormat.printToString(transactionExtention);
+ JSONObject jsonObject = JSONObject.parseObject(string);
+ if (transactionExtention.getResult().getResult()) {
+ jsonObject.put("transaction", printTransactionToJSON(transactionExtention.getTransaction()));
+ }
+ return jsonObject.toJSONString();
+ }
+
+ public static byte[] generateContractAddress(Transaction trx, byte[] ownerAddress) {
+ // get tx hash
+ byte[] txRawDataHash = Sha256Hash.of(trx.getRawData().toByteArray()).getBytes();
+
+ // combine
+ byte[] combined = new byte[txRawDataHash.length + ownerAddress.length];
+ System.arraycopy(txRawDataHash, 0, combined, 0, txRawDataHash.length);
+ System.arraycopy(ownerAddress, 0, combined, txRawDataHash.length, ownerAddress.length);
+
+ return Hash.sha3omit12(combined);
+ }
+
public static JSONObject printTransactionToJSON(Transaction transaction) {
JSONObject jsonTransaction = JSONObject.parseObject(JsonFormat.printToString(transaction));
JSONArray contracts = new JSONArray();
@@ -190,6 +213,9 @@ public static JSONObject printTransactionToJSON(Transaction transaction) {
CreateSmartContract deployContract = contractParameter
.unpack(CreateSmartContract.class);
contractJson = JSONObject.parseObject(JsonFormat.printToString(deployContract));
+ byte[] ownerAddress = deployContract.getOwnerAddress().toByteArray();
+ byte[] contractAddress = generateContractAddress(transaction, ownerAddress);
+ jsonTransaction.put("contract_address", ByteArray.toHexString(contractAddress));
break;
case TriggerSmartContract:
TriggerSmartContract triggerSmartContract = contractParameter
@@ -348,6 +374,14 @@ public static Transaction packTransaction(String strTransaction) {
triggerSmartContractBuilder);
any = Any.pack(triggerSmartContractBuilder.build());
break;
+ case "CreateSmartContract":
+ CreateSmartContract.Builder CreateSmartContractBuilder = CreateSmartContract
+ .newBuilder();
+ JsonFormat
+ .merge(parameter.getJSONObject("value").toJSONString(),
+ CreateSmartContractBuilder);
+ any = Any.pack(CreateSmartContractBuilder.build());
+ break;
// todo add other contract
default:
}
diff --git a/src/main/java/org/tron/core/witness/ProposalController.java b/src/main/java/org/tron/core/witness/ProposalController.java
index b4829944a54..1d4e5a9effd 100644
--- a/src/main/java/org/tron/core/witness/ProposalController.java
+++ b/src/main/java/org/tron/core/witness/ProposalController.java
@@ -130,6 +130,14 @@ public void setDynamicParameters(ProposalCapsule proposalCapsule) {
manager.getDynamicPropertiesStore().saveCreateNewAccountBandwidthRate(entry.getValue());
break;
}
+ case (9): {
+ manager.getDynamicPropertiesStore().saveAllowCreationOfContracts(entry.getValue());
+ break;
+ }
+ case (10): {
+ manager.getDynamicPropertiesStore().saveRemoveThePowerOfTheGr(entry.getValue());
+ break;
+ }
default:
break;
}
diff --git a/src/main/java/org/tron/core/witness/WitnessController.java b/src/main/java/org/tron/core/witness/WitnessController.java
index 97aafa39298..697d5442d1d 100644
--- a/src/main/java/org/tron/core/witness/WitnessController.java
+++ b/src/main/java/org/tron/core/witness/WitnessController.java
@@ -23,6 +23,7 @@
import org.tron.core.capsule.VotesCapsule;
import org.tron.core.capsule.WitnessCapsule;
import org.tron.core.config.Parameter.ChainConstant;
+import org.tron.core.config.args.Args;
import org.tron.core.db.AccountStore;
import org.tron.core.db.Manager;
import org.tron.core.db.VotesStore;
@@ -156,6 +157,14 @@ public boolean validateWitnessSchedule(BlockCapsule block) {
if (manager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() == 0) {
return true;
}
+ long blockAbSlot = getAbSlotAtTime(block.getTimeStamp());
+ long headBlockAbSlot = getAbSlotAtTime(
+ manager.getDynamicPropertiesStore().getLatestBlockHeaderTimestamp());
+ if (blockAbSlot <= headBlockAbSlot) {
+ logger.warn("blockAbSlot is equals with headBlockAbSlot[" + blockAbSlot + "]");
+ return false;
+ }
+
long slot = getSlotAtTime(block.getTimeStamp());
final ByteString scheduledWitness = getScheduledWitness(slot);
if (!scheduledWitness.equals(witnessAddress)) {
@@ -297,6 +306,8 @@ public void updateWitness() {
VotesStore votesStore = manager.getVotesStore();
AccountStore accountStore = manager.getAccountStore();
+ tryRemoveThePowerOfTheGr();
+
Map countWitness = countVote(votesStore);
//Only possible during the initialization phase
@@ -366,6 +377,22 @@ public void updateWitness() {
}
}
+ public void tryRemoveThePowerOfTheGr(){
+ if(manager.getDynamicPropertiesStore().getRemoveThePowerOfTheGr() == 1){
+
+ WitnessStore witnessStore = manager.getWitnessStore();
+
+ Args.getInstance().getGenesisBlock().getWitnesses().forEach(witnessInGenesisBlock -> {
+ WitnessCapsule witnessCapsule = witnessStore.get(witnessInGenesisBlock.getAddress());
+ witnessCapsule.setVoteCount(witnessCapsule.getVoteCount() - witnessInGenesisBlock.getVoteCount());
+
+ witnessStore.put(witnessCapsule.createDbKey(), witnessCapsule);
+ });
+
+ manager.getDynamicPropertiesStore().saveRemoveThePowerOfTheGr(-1);
+ }
+ }
+
private static boolean witnessSetChanged(List list1, List list2) {
return !CollectionUtils.isEqualCollection(list1, list2);
}
diff --git a/src/main/java/org/tron/program/FullNode.java b/src/main/java/org/tron/program/FullNode.java
index 1a664713dff..af3b7b9be8b 100644
--- a/src/main/java/org/tron/program/FullNode.java
+++ b/src/main/java/org/tron/program/FullNode.java
@@ -2,13 +2,12 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
+import org.tron.common.application.TronApplicationContext;
import org.tron.core.Constant;
import org.tron.core.config.DefaultConfig;
import org.tron.core.config.args.Args;
-import org.tron.core.db.RevokingDatabase;
import org.tron.core.services.RpcApiService;
import org.tron.core.services.WitnessService;
import org.tron.core.services.http.FullNodeHttpApiService;
@@ -29,21 +28,30 @@ public static void main(String[] args) throws InterruptedException {
return;
}
+ if (Args.getInstance().isDebug()) {
+ logger.info("in debug mode, it won't check energy time");
+ } else {
+ logger.info("not in debug mode, it will check energy time");
+ }
+
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
beanFactory.setAllowCircularReferences(false);
- AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(beanFactory);
+ TronApplicationContext context =
+ new TronApplicationContext(beanFactory);
context.register(DefaultConfig.class);
+
context.refresh();
Application appT = ApplicationFactory.create(context);
shutdown(appT);
- //appT.init(cfgArgs);
+ // grpc api server
RpcApiService rpcApiService = context.getBean(RpcApiService.class);
appT.addService(rpcApiService);
if (cfgArgs.isWitness()) {
appT.addService(new WitnessService(appT, context));
}
- //http
+
+ // http api server
FullNodeHttpApiService httpApiService = context.getBean(FullNodeHttpApiService.class);
appT.addService(httpApiService);
diff --git a/src/main/java/org/tron/program/SolidityNode.java b/src/main/java/org/tron/program/SolidityNode.java
index 3b3730861f8..c940ac6eff4 100644
--- a/src/main/java/org/tron/program/SolidityNode.java
+++ b/src/main/java/org/tron/program/SolidityNode.java
@@ -5,10 +5,10 @@
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.util.StringUtils;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.overlay.client.DatabaseGrpcClient;
import org.tron.common.overlay.discover.DiscoverServer;
import org.tron.common.overlay.discover.node.NodeManager;
@@ -20,7 +20,6 @@
import org.tron.core.config.DefaultConfig;
import org.tron.core.config.args.Args;
import org.tron.core.db.Manager;
-import org.tron.core.db2.core.SnapshotManager;
import org.tron.core.exception.AccountResourceInsufficientException;
import org.tron.core.exception.BadBlockException;
import org.tron.core.exception.BadItemException;
@@ -29,10 +28,14 @@
import org.tron.core.exception.ContractValidateException;
import org.tron.core.exception.DupTransactionException;
import org.tron.core.exception.NonCommonBlockException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.ReceiptException;
import org.tron.core.exception.TaposException;
import org.tron.core.exception.TooBigTransactionException;
import org.tron.core.exception.TransactionExpirationException;
+import org.tron.core.exception.TransactionTraceException;
import org.tron.core.exception.UnLinkedBlockException;
+import org.tron.core.exception.UnsupportVMException;
import org.tron.core.exception.ValidateScheduleException;
import org.tron.core.exception.ValidateSignatureException;
import org.tron.core.services.RpcApiService;
@@ -138,8 +141,16 @@ private void syncSolidityBlock() throws BadBlockException {
throw new BadBlockException("expiration exception");
} catch (BadNumberBlockException e) {
throw new BadBlockException("bad number exception");
+ } catch (ReceiptException e) {
+ throw new BadBlockException("Receipt exception");
} catch (NonCommonBlockException e) {
throw new BadBlockException("non common exception");
+ } catch (TransactionTraceException e) {
+ throw new BadBlockException("TransactionTrace Exception");
+ } catch (OutOfSlotTimeException e) {
+ throw new BadBlockException("OutOfSlotTime Exception");
+ } catch (UnsupportVMException e) {
+ throw new BadBlockException(e.getMessage());
}
} else {
@@ -176,9 +187,7 @@ public static void main(String[] args) throws InterruptedException {
}
cfgArgs.setSolidityNode(true);
- ApplicationContext context = new AnnotationConfigApplicationContext(DefaultConfig.class);
- SnapshotManager snapshotManager = context.getBean(SnapshotManager.class);
- snapshotManager.check();
+ ApplicationContext context = new TronApplicationContext(DefaultConfig.class);
if (cfgArgs.isHelp()) {
logger.info("Here is the help message.");
diff --git a/src/main/protos/api/api.proto b/src/main/protos/api/api.proto
index c657aa469d0..a84e460b38f 100644
--- a/src/main/protos/api/api.proto
+++ b/src/main/protos/api/api.proto
@@ -91,6 +91,11 @@ service Wallet {
}
};
};
+
+ //modify the consume_user_resource_percent
+ rpc UpdateSetting (UpdateSettingContract) returns (TransactionExtention) {
+ };
+
//Use this function instead of VoteWitnessAccount.
rpc VoteWitnessAccount2 (VoteWitnessContract) returns (TransactionExtention) {
};
@@ -250,9 +255,24 @@ service Wallet {
rpc BuyStorage (BuyStorageContract) returns (TransactionExtention) {
}
+ rpc BuyStorageBytes (BuyStorageBytesContract) returns (TransactionExtention) {
+ }
+
rpc SellStorage (SellStorageContract) returns (TransactionExtention) {
}
+ rpc ExchangeCreate (ExchangeCreateContract) returns (TransactionExtention) {
+ }
+
+ rpc ExchangeInject (ExchangeInjectContract) returns (TransactionExtention) {
+ }
+
+ rpc ExchangeWithdraw (ExchangeWithdrawContract) returns (TransactionExtention) {
+ }
+
+ rpc ExchangeTransaction (ExchangeTransactionContract) returns (TransactionExtention) {
+ }
+
rpc ListNodes (EmptyMessage) returns (NodeList) {
option (google.api.http) = {
post: "/wallet/listnodes"
@@ -406,6 +426,26 @@ service Wallet {
};
};
+ rpc ListExchanges (EmptyMessage) returns (ExchangeList) {
+ option (google.api.http) = {
+ post: "/wallet/listexchanges"
+ body: "*"
+ additional_bindings {
+ get: "/wallet/listexchanges"
+ }
+ };
+ };
+
+ rpc GetExchangeById (BytesMessage) returns (Exchange) {
+ option (google.api.http) = {
+ post: "/wallet/getexchangebyid"
+ body: "*"
+ additional_bindings {
+ get: "/wallet/getexchangebyid"
+ }
+ };
+ };
+
rpc GetChainParameters (EmptyMessage) returns (ChainParameters) {
option (google.api.http) = {
post: "/wallet/getchainparameters"
@@ -711,6 +751,9 @@ message WitnessList {
message ProposalList {
repeated Proposal proposals = 1;
}
+message ExchangeList {
+ repeated Exchange exchanges = 1;
+}
message AssetIssueList {
repeated AssetIssueContract assetIssue = 1;
}
@@ -788,10 +831,10 @@ message AccountResourceMessage {
int64 TotalNetLimit = 7;
int64 TotalNetWeight = 8;
- int64 CpuUsed = 13;
- int64 CpuLimit = 14;
- int64 TotalCpuLimit = 15;
- int64 TotalCpuWeight = 16;
+ int64 EnergyUsed = 13;
+ int64 EnergyLimit = 14;
+ int64 TotalEnergyLimit = 15;
+ int64 TotalEnergyWeight = 16;
int64 storageUsed = 21;
int64 storageLimit = 22;
@@ -828,7 +871,8 @@ message AddressPrKeyPairMessage {
message TransactionExtention {
Transaction transaction = 1;
bytes txid = 2; //transaction id = sha256(transaction.rowdata)
- Return result = 3;
+ repeated bytes constant_result = 3;
+ Return result = 4;
}
message BlockExtention {
diff --git a/src/main/protos/core/Contract.proto b/src/main/protos/core/Contract.proto
index 1549273b316..5d5c1421f9a 100644
--- a/src/main/protos/core/Contract.proto
+++ b/src/main/protos/core/Contract.proto
@@ -72,6 +72,12 @@ message VoteWitnessContract {
bool support = 3;
}
+message UpdateSettingContract {
+ bytes owner_address = 1;
+ bytes contract_address = 2;
+ int64 consume_user_resource_percent = 3;
+}
+
message WitnessCreateContract {
bytes owner_address = 1;
bytes url = 2;
@@ -116,7 +122,7 @@ message ParticipateAssetIssueContract {
enum ResourceCode {
BANDWIDTH = 0x00;
- CPU = 0x01;
+ ENERGY = 0x01;
}
message FreezeBalanceContract {
@@ -168,23 +174,13 @@ message ProposalDeleteContract {
message CreateSmartContract {
bytes owner_address = 1;
SmartContract new_contract = 2;
- int64 cpu_limit_in_trx = 3;
- int64 storage_limit_in_trx = 4;
- int64 max_cpu_usage = 15;
- int64 max_net_usage = 16;
- int64 max_storage = 17;
}
message TriggerSmartContract {
bytes owner_address = 1;
bytes contract_address = 2;
- bytes call_value = 3;
+ int64 call_value = 3;
bytes data = 4;
- int64 cpu_limit_in_trx = 5;
- int64 storage_limit_in_trx = 6;
- int64 max_cpu_usage = 17;
- int64 max_net_usage = 18;
- int64 max_storage = 19;
}
message BuyStorageContract {
@@ -192,7 +188,41 @@ message BuyStorageContract {
int64 quant = 2; // trx quantity for buy storage (sun)
}
+message BuyStorageBytesContract {
+ bytes owner_address = 1;
+ int64 bytes = 2; // storage bytes for buy
+}
+
message SellStorageContract {
bytes owner_address = 1;
int64 storage_bytes = 2;
+}
+
+message ExchangeCreateContract {
+ bytes owner_address = 1;
+ bytes first_token_id = 2;
+ int64 first_token_balance = 3;
+ bytes second_token_id = 4;
+ int64 second_token_balance = 5;
+}
+
+message ExchangeInjectContract {
+ bytes owner_address = 1;
+ int64 exchange_id = 2;
+ bytes token_id = 3;
+ int64 quant = 4;
+}
+
+message ExchangeWithdrawContract {
+ bytes owner_address = 1;
+ int64 exchange_id = 2;
+ bytes token_id = 3;
+ int64 quant = 4;
+}
+
+message ExchangeTransactionContract {
+ bytes owner_address = 1;
+ int64 exchange_id = 2;
+ bytes token_id = 3;
+ int64 quant = 4;
}
\ No newline at end of file
diff --git a/src/main/protos/core/Tron.proto b/src/main/protos/core/Tron.proto
index 09c3c7fb758..d568183f911 100644
--- a/src/main/protos/core/Tron.proto
+++ b/src/main/protos/core/Tron.proto
@@ -47,6 +47,17 @@ message Proposal {
State state = 7;
}
+// Exchange
+message Exchange {
+ int64 exchange_id = 1;
+ bytes creator_address = 2;
+ int64 create_time = 3;
+ bytes first_token_id = 6;
+ int64 first_token_balance = 7;
+ bytes second_token_id = 8;
+ int64 second_token_balance = 9;
+}
+
message ChainParameters {
repeated ChainParameter chainParameter = 1;
message ChainParameter {
@@ -105,11 +116,11 @@ message Account {
bytes account_id = 23;
message AccountResource {
- // cpu resource, get from frozen
- int64 cpu_usage = 1;
- // the frozen balance for cpu
- Frozen frozen_balance_for_cpu = 2;
- int64 latest_consume_time_for_cpu = 3;
+ // energy resource, get from frozen
+ int64 energy_usage = 1;
+ // the frozen balance for energy
+ Frozen frozen_balance_for_energy = 2;
+ int64 latest_consume_time_for_energy = 3;
// storage resource, get from market
int64 storage_limit = 6;
@@ -172,12 +183,16 @@ message TXOutputs {
}
message ResourceReceipt {
- int64 cpu_usage = 1;
- int64 cpu_fee = 2;
- int64 net_usage = 3;
- int64 net_fee = 4;
- int64 storage_delta = 5;
- int64 storage_fee = 6;
+ enum code {
+ SUCCESS = 0;
+ FAILED = 1;
+ }
+ int64 energy_usage = 1;
+ int64 energy_fee = 2;
+ int64 origin_energy_usage = 3;
+ int64 energy_usage_total = 4;
+ int64 net_usage = 5;
+ int64 net_fee = 6;
}
message Transaction {
@@ -203,11 +218,17 @@ message Transaction {
ProposalDeleteContract = 18;
SetAccountIdContract = 19;
CustomContract = 20;
- BuyStorageContract = 21;
- SellStorageContract = 23;
+ // BuyStorageContract = 21;
+ // BuyStorageBytesContract = 22;
+ // SellStorageContract = 23;
CreateSmartContract = 30;
TriggerSmartContract = 31;
GetContract = 32;
+ UpdateSettingContract = 33;
+ ExchangeCreateContract = 41;
+ ExchangeInjectContract = 42;
+ ExchangeWithdrawContract = 43;
+ ExchangeTransactionContract = 44;
}
ContractType type = 1;
google.protobuf.Any parameter = 2;
@@ -223,8 +244,9 @@ message Transaction {
}
int64 fee = 1;
code ret = 2;
- bytes constant_result = 3;
- ResourceReceipt receipt = 4;
+
+ int64 withdraw_amount = 15;
+ int64 unfreeze_amount = 16;
}
message raw {
@@ -240,9 +262,7 @@ message Transaction {
// scripts not used
bytes scripts = 12;
int64 timestamp = 14;
- int64 max_cpu_usage = 15;
- int64 max_net_usage = 16;
- int64 max_storage = 17;
+ int64 fee_limit = 18;
}
raw raw_data = 1;
@@ -252,14 +272,28 @@ message Transaction {
}
message TransactionInfo {
+ enum code {
+ SUCESS = 0;
+ FAILED = 1;
+ }
+ message Log {
+ bytes address = 1;
+ repeated bytes topics = 2;
+ bytes data = 3;
+ }
bytes id = 1;
int64 fee = 2;
int64 blockNumber = 3;
int64 blockTimeStamp = 4;
repeated bytes contractResult = 5;
bytes contract_address = 6;
- Transaction.Result result = 7;
- repeated bytes log = 8;
+ ResourceReceipt receipt = 7;
+ repeated Log log = 8;
+ code result = 9;
+ bytes resMessage = 10;
+
+ int64 withdraw_amount = 15;
+ int64 unfreeze_amount = 16;
}
message Transactions {
@@ -281,6 +315,7 @@ message BlockHeader {
int64 number = 7;
int64 witness_id = 8;
bytes witness_address = 9;
+ int32 version = 10;
}
raw raw_data = 1;
bytes witness_signature = 2;
@@ -390,12 +425,6 @@ message HelloMessage {
BlockId headBlockId = 6;
}
-message StorageItem {
- bytes contract_address = 1;
- map items = 2;
-}
-
-
message SmartContract {
message ABI {
message Entry {
@@ -408,8 +437,8 @@ message SmartContract {
}
message Param {
bool indexed = 1;
- bytes name = 2;
- bytes type = 3;
+ string name = 2;
+ string type = 3;
// SolidityType type = 3;
}
enum StateMutabilityType {
@@ -422,23 +451,21 @@ message SmartContract {
bool anonymous = 1;
bool constant = 2;
- bytes name = 3;
+ string name = 3;
repeated Param inputs = 4;
repeated Param outputs = 5;
EntryType type = 6;
bool payable = 7;
StateMutabilityType stateMutability = 8;
}
-
repeated Entry entrys = 1;
}
bytes origin_address = 1;
bytes contract_address = 2;
ABI abi = 3;
bytes bytecode = 4;
- bytes call_value = 5;
- bytes data = 6;
- int64 consume_user_resource_percent = 7;
- bytes name = 8;
+ int64 call_value = 5;
+ int64 consume_user_resource_percent = 6;
+ string name = 7;
}
\ No newline at end of file
diff --git a/src/main/resources/config-localtest.conf b/src/main/resources/config-localtest.conf
index 95187d9937d..060b8a08199 100644
--- a/src/main/resources/config-localtest.conf
+++ b/src/main/resources/config-localtest.conf
@@ -5,7 +5,7 @@ net {
storage {
# Directory for storing persistent data
-
+ db.version = 1,
db.directory = "database",
index.directory = "index",
diff --git a/src/main/resources/config.conf b/src/main/resources/config.conf
index a8c6dbe0750..81f9856ad9a 100644
--- a/src/main/resources/config.conf
+++ b/src/main/resources/config.conf
@@ -90,6 +90,12 @@ node {
minParticipationRate = 15
+ # check the peer data transfer ,disconnect factor
+ disconnectNumberFactor = 0.4
+ maxConnectNumberFactor = 0.8
+ receiveTcpMinDataLength = 2048
+ isOpenFullTcpDisconnect = true
+
p2p {
version = 11111 # 11111: mainnet; 20180622: testnet
}
diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml
index 39fa5b16a4b..0e4c7ff47fa 100644
--- a/src/main/resources/logback.xml
+++ b/src/main/resources/logback.xml
@@ -20,10 +20,10 @@
- ./logs/tron-%d{yyyy-MM-dd}.%i.log.tar.gz
+ ./logs/tron-%d{yyyy-MM-dd}.%i.log.gz
500MB
- 720
+ 30
50GB
@@ -88,6 +88,10 @@
+
+
+
+
diff --git a/src/test/java/org/tron/common/runtime/InheritanceTest.java b/src/test/java/org/tron/common/runtime/InheritanceTest.java
new file mode 100644
index 00000000000..0e256980442
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/InheritanceTest.java
@@ -0,0 +1,141 @@
+package org.tron.common.runtime;
+
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.spongycastle.util.encoders.Hex;
+import org.tron.common.application.TronApplicationContext;
+import org.testng.Assert;
+import org.tron.common.storage.DepositImpl;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.TransactionTraceException;
+import org.tron.protos.Protocol.AccountType;
+
+@Slf4j
+public class InheritanceTest {
+ private static Runtime runtime;
+ private static Manager dbManager;
+ private static TronApplicationContext context;
+ private static DepositImpl deposit;
+ private static final String dbPath = "output_InheritanceTest";
+ private static final String OWNER_ADDRESS;
+
+ static {
+ Args.setParam(new String[]{"--output-directory", dbPath,"--debug"}, Constant.TEST_CONF);
+ context = new TronApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
+ }
+
+ /**
+ * Init data.
+ */
+ @BeforeClass
+ public static void init() {
+ dbManager = context.getBean(Manager.class);
+ deposit = DepositImpl.createRoot(dbManager);
+ deposit.createAccount(Hex.decode(OWNER_ADDRESS),AccountType.Normal);
+ deposit.addBalance(Hex.decode(OWNER_ADDRESS),100000000);
+ }
+
+
+
+ /**
+ * pragma solidity ^0.4.19;
+ *
+ * contract foo {
+ * uint256 public id=10;
+ * function getNumber() returns (uint256){return 100;}
+ * function getName() returns (string){
+ * return "foo";
+ * }
+ * }
+ *
+ * contract bar is foo {
+ * function getName() returns (string) { return "bar"; }
+ * function getId() returns(uint256){return id;}
+ * }
+ */
+ @Test
+ public void inheritanceTest()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ String contractName = "barContract";
+ byte[] callerAddress = Hex.decode(OWNER_ADDRESS);
+ String ABI = "[{\"constant\":false,\"inputs\":[],\"name\":\"getName\",\"outputs\":[{\"name\":\"\",\"type\":\"string\"}],"
+ + "\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],"
+ + "\"name\":\"getId\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\","
+ + "\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"id\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],"
+ + "\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"getNumber\","
+ + "\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]";
+ String code = "6080604052600a60005534801561001557600080fd5b506101f9806100256000396000f300608060405260043610610062576000357c01"
+ + "00000000000000000000000000000000000000000000000000000000900463ffffffff16806317d7de7c146100675780635d1ca631146100f757806"
+ + "3af640d0f14610122578063f2c9ecd81461014d575b600080fd5b34801561007357600080fd5b5061007c610178565b6040518080602001828103825"
+ + "283818151815260200191508051906020019080838360005b838110156100bc5780820151818401526020810190506100a1565b505050509050908101"
+ + "90601f1680156100e95780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b34801561010357600080fd"
+ + "5b5061010c6101b5565b6040518082815260200191505060405180910390f35b34801561012e57600080fd5b506101376101be565b60405180828152602"
+ + "00191505060405180910390f35b34801561015957600080fd5b506101626101c4565b6040518082815260200191505060405180910390f35b6060604080"
+ + "5190810160405280600381526020017f6261720000000000000000000000000000000000000000000000000000000000815250905090565b60008054905"
+ + "090565b60005481565b600060649050905600a165627a7a72305820dfe79cf7f4a8a342b754cad8895b13f85de7daa11803925cf392263397653e7f0029";
+ long value = 0;
+ long fee = 100000000;
+ long consumeUserResourcePercent = 0;
+
+ byte[] contractAddress = TVMTestUtils.deployContractWholeProcessReturnContractAddress(
+ contractName,callerAddress,ABI,code,value,fee,consumeUserResourcePercent,null,deposit,null);
+
+
+ /* =================================== CALL getName() return child value =================================== */
+ byte[] triggerData1 = TVMTestUtils.parseABI("getName()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(callerAddress,contractAddress,triggerData1,
+ 0,1000000,deposit,null);
+
+ //0x20 => pointer position, 0x3 => size, 626172 => "bar"
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),
+ "0000000000000000000000000000000000000000000000000000000000000020"
+ + "0000000000000000000000000000000000000000000000000000000000000003"
+ + "6261720000000000000000000000000000000000000000000000000000000000");
+
+ /* =================================== CALL getNumber() return parent value=================================== */
+ byte[] triggerData2 = TVMTestUtils.parseABI("getNumber()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(callerAddress,contractAddress,triggerData2,
+ 0,1000000,deposit,null);
+
+ //0x64 =>100
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),
+ "0000000000000000000000000000000000000000000000000000000000000064");
+
+ /* =================================== CALL getId() call child function return parent field value=================================== */
+ byte[] triggerData3 = TVMTestUtils.parseABI("getId()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(callerAddress,contractAddress,triggerData3,
+ 0,1000000,deposit,null);
+
+ //0x64 =>100
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),
+ "000000000000000000000000000000000000000000000000000000000000000a");
+ }
+
+
+ /**
+ * Release resources.
+ */
+ @AfterClass
+ public static void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+
+}
diff --git a/src/test/java/org/tron/common/runtime/InternalTransactionComplexTest.java b/src/test/java/org/tron/common/runtime/InternalTransactionComplexTest.java
new file mode 100644
index 00000000000..fd18fe664bb
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/InternalTransactionComplexTest.java
@@ -0,0 +1,178 @@
+package org.tron.common.runtime;
+
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.spongycastle.util.encoders.Hex;
+import org.tron.common.application.TronApplicationContext;
+import org.testng.Assert;
+import org.tron.common.runtime.vm.DataWord;
+import org.tron.common.storage.DepositImpl;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.TransactionTraceException;
+import org.tron.protos.Protocol.AccountType;
+
+@Slf4j
+public class InternalTransactionComplexTest {
+
+ private static Runtime runtime;
+ private static Manager dbManager;
+ private static TronApplicationContext context;
+ private static DepositImpl deposit;
+ private static final String dbPath = "output_InternalTransactionComplexTest";
+ private static final String OWNER_ADDRESS;
+
+ static {
+ Args.setParam(new String[]{"--output-directory", dbPath, "--debug"}, Constant.TEST_CONF);
+ context = new TronApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
+ }
+
+ /**
+ * Init data.
+ */
+ @BeforeClass
+ public static void init() {
+ dbManager = context.getBean(Manager.class);
+ deposit = DepositImpl.createRoot(dbManager);
+ deposit.createAccount(Hex.decode(OWNER_ADDRESS), AccountType.Normal);
+ deposit.addBalance(Hex.decode(OWNER_ADDRESS), 100000000);
+ }
+
+ /**
+ * pragma solidity 0.4.24;
+ *
+ * // this is to test wither the TVM is returning vars from one contract calling another //
+ * contract's functions.
+ *
+ * contract callerContract { // lets set up our instance of the new contract calledContract
+ * CALLED_INSTANCE; // lets set the contract instance address in the constructor
+ * constructor(address _addr) public { CALLED_INSTANCE = calledContract(_addr); } // lets create a
+ * few public vars to store results so we know if we are // getting the callback return struct
+ * SomeStruct { bool someBool; uint256 someUint; bytes32 someBytes32; } SomeStruct public
+ * testCallbackReturns_; // create the function call to external contract. store return in vars
+ * created // above. function makeTheCall() public { // lets call the contract and store returns
+ * in to temp vars (bool _bool, uint256 _uint, bytes32 _bytes32) = CALLED_INSTANCE.testReturns();
+ * // lets write those temp vars to state testCallbackReturns_.someBool = _bool;
+ * testCallbackReturns_.someUint = _uint; testCallbackReturns_.someBytes32 = _bytes32; } }
+ *
+ * contract calledContract { function testReturns() external pure returns(bool, uint256, bytes32)
+ * { return(true, 314159, 0x123456); } }
+ */
+ @Test
+ public void internalTransactionAsInstanceTest()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ byte[] calledContractAddress = deployCalledContractandGetItsAddress();
+ byte[] callerContractAddress = deployCallerContractAndGetItsAddress(calledContractAddress);
+
+ /* =================================== CALL makeTheCall =================================== */
+ byte[] triggerData1 = TVMTestUtils.parseABI("makeTheCall()", "");
+ runtime = TVMTestUtils
+ .triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),
+ callerContractAddress, triggerData1,
+ 0, 100000000, deposit, null);
+
+ /* =================================== CALL testCallbackReturns_ to check data =================================== */
+ byte[] triggerData2 = TVMTestUtils.parseABI("testCallbackReturns_()", "");
+ runtime = TVMTestUtils
+ .triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),
+ callerContractAddress, triggerData2,
+ 0, 100000000, deposit, null);
+
+ // bool true => 0000000000000000000000000000000000000000000000000000000000000001,
+ // uint256 314159 =>000000000000000000000000000000000000000000000000000000000004cb2f,
+ // byte32 0x123456 => 0000000000000000000000000000000000000000000000000000000000123456
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),
+ "0000000000000000000000000000000000000000000000000000000000000001"
+ + "000000000000000000000000000000000000000000000000000000000004cb2f"
+ + "0000000000000000000000000000000000000000000000000000000000123456");
+
+
+ }
+
+
+ // Just for the caller/called example above
+ private byte[] deployCalledContractandGetItsAddress()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ String contractName = "calledContract";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI =
+ "[{\"constant\":true,\"inputs\":[],\"name\":\"testReturns\",\"outputs\":[{\"name\":\"\",\"type\":\"bool\"},"
+ + "{\"name\":\"\",\"type\":\"uint256\"},{\"name\":\"\",\"type\":\"bytes32\"}],\"payable\":false,\"stateMutability\":\"pure\","
+ + "\"type\":\"function\"}]";
+ String code =
+ "608060405234801561001057600080fd5b5060d58061001f6000396000f300608060405260043610603f576000357c0"
+ + "100000000000000000000000000000000000000000000000000000000900463ffffffff1680631a483b8c146044575b600080fd5"
+ + "b348015604f57600080fd5b5060566086565b60405180841515151581526020018381526020018260001916600019168152602001"
+ + "935050505060405180910390f35b600080600060016204cb2f621234568191508060010290509250925092509091925600a165627a"
+ + "7a72305820040808e22827b01e497bf99a0ddd72084c95a3fa9bc8737fb022594c7656f00a0029";
+ long value = 0;
+ long feeLimit = 1000000000;
+ long consumeUserResourcePercent = 0;
+
+ return TVMTestUtils
+ .deployContractWholeProcessReturnContractAddress(contractName, address, ABI, code, value,
+ feeLimit, consumeUserResourcePercent, null,
+ deposit, null);
+ }
+
+ // Just for the caller/called example above
+ private byte[] deployCallerContractAndGetItsAddress(byte[] calledContractAddress)
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ String contractName = "calledContract";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI =
+ "[{\"constant\":false,\"inputs\":[],\"name\":\"makeTheCall\",\"outputs\":[],\"payable\":false,\"stateMutability\":"
+ + "\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"testCallbackReturns_\",\"outputs\":"
+ + "[{\"name\":\"someBool\",\"type\":\"bool\"},{\"name\":\"someUint\",\"type\":\"uint256\"},{\"name\":\"someBytes32\",\"type\":"
+ + "\"bytes32\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"name\":\"_addr\",\"type\":"
+ + "\"address\"}],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]";
+ String code =
+ "608060405234801561001057600080fd5b5060405160208061029983398101806040528101908080519060200190929190505050806000806101"
+ + "000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550506102168"
+ + "06100836000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff"
+ + "1680633855721a14610051578063dda810ec14610068575b600080fd5b34801561005d57600080fd5b506100666100ad565b005b34801561007457600080fd5"
+ + "b5061007d6101c5565b60405180841515151581526020018381526020018260001916600019168152602001935050505060405180910390f35b6000806000806"
+ + "0009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16631a483b8c604051816"
+ + "3ffffffff167c0100000000000000000000000000000000000000000000000000000000028152600401606060405180830381600087803b158015610137576000"
+ + "80fd5b505af115801561014b573d6000803e3d6000fd5b505050506040513d606081101561016157600080fd5b810190808051906020019092919080519060200"
+ + "1909291908051906020019092919050505092509250925082600160000160006101000a81548160ff0219169083151502179055508160018001819055508060016"
+ + "002018160001916905550505050565b60018060000160009054906101000a900460ff169080600101549080600201549050835600a165627a7a72305820afe0957a"
+ + "5188a2329cea5d678a10b01436ab68941b47259fc16ae84985c1abce0029" + Hex
+ .toHexString(new DataWord(calledContractAddress).getData());
+ long value = 0;
+ long feeLimit = 1000000000;
+ long consumeUserResourcePercent = 0;
+
+ return TVMTestUtils
+ .deployContractWholeProcessReturnContractAddress(contractName, address, ABI, code, value,
+ feeLimit, consumeUserResourcePercent, null,
+ deposit, null);
+ }
+
+
+ /**
+ * Release resources.
+ */
+ @AfterClass
+ public static void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+
+}
diff --git a/src/test/java/org/tron/common/runtime/RuntimeTransferComplexTest.java b/src/test/java/org/tron/common/runtime/RuntimeTransferComplexTest.java
new file mode 100644
index 00000000000..580dc6c7dd2
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/RuntimeTransferComplexTest.java
@@ -0,0 +1,179 @@
+package org.tron.common.runtime;
+
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.spongycastle.util.encoders.Hex;
+import org.tron.common.application.TronApplicationContext;
+import org.testng.Assert;
+import org.tron.common.storage.DepositImpl;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.TransactionTraceException;
+import org.tron.protos.Protocol.AccountType;
+import org.tron.protos.Protocol.Transaction;
+
+@Slf4j
+public class RuntimeTransferComplexTest {
+ private static Runtime runtime;
+ private static Manager dbManager;
+ private static TronApplicationContext context;
+ private static DepositImpl deposit;
+ private static final String dbPath = "output_RuntimeTransferComplexTest";
+ private static final String OWNER_ADDRESS;
+ private static final String TRANSFER_TO;
+
+ static {
+ Args.setParam(new String[]{"--output-directory", dbPath, "--debug"}, Constant.TEST_CONF);
+ context = new TronApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
+ TRANSFER_TO = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
+ }
+
+ /**
+ * Init data.
+ */
+ @BeforeClass
+ public static void init() {
+ dbManager = context.getBean(Manager.class);
+ deposit = DepositImpl.createRoot(dbManager);
+ deposit.createAccount(Hex.decode(OWNER_ADDRESS),AccountType.Normal);
+ deposit.addBalance(Hex.decode(OWNER_ADDRESS),100000000);
+ deposit.createAccount(Hex.decode(TRANSFER_TO),AccountType.Normal);
+ deposit.addBalance(Hex.decode(TRANSFER_TO),10);
+ }
+
+
+ /**
+ *
+ * Test constructor Transfer
+ * pragma solidity ^0.4.16;
+ * contract transferWhenDeploy {
+ * constructor () payable{}
+ * }
+ */
+ @Test
+ public void TransferTrxToContractAccountWhenDeployAContract()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+
+ String contractName = "TransferWhenDeployContract";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI = "[{\"inputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"constructor\"}]";
+ String code = "608060405260358060116000396000f3006080604052600080fd00a165627a7a72305820d3b0de5bdc00ebe85619d50b72b29d30bd00dd233e8849402671979de0e9e73b0029";
+ long value = 100;
+ long fee = 100000000;
+ long consumeUserResourcePercent = 0;
+
+
+ Transaction trx = TVMTestUtils.generateDeploySmartContractAndGetTransaction(
+ contractName,address,ABI,code,value,fee,consumeUserResourcePercent,null);
+ byte[] contractAddress = Wallet.generateContractAddress(trx);
+ runtime = TVMTestUtils.processTransactionAndReturnRuntime(trx, deposit, null);
+ Assert.assertNull(runtime.getRuntimeError());
+ Assert.assertEquals(dbManager.getAccountStore().get(contractAddress).getBalance(),100);
+ }
+
+ /**
+ *
+ * Test constructor Transfer
+ * pragma solidity ^0.4.16;
+ * contract transferWhenDeploy {
+ * constructor () {}
+ * }
+ */
+
+ @Test
+ public void TransferTrxToContractAccountFailIfNotPayable()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+
+ String contractName = "TransferWhenDeployContract";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI = "[{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]";
+ String code = "6080604052348015600f57600080fd5b50603580601d6000396000f3006080604052600080fd00a165627a7a72305820f5dc348e1c7dc90f9996a05c69dc9d060b6d356a1ed570ce3cd89570dc4ce6440029";
+ long value = 100;
+ long fee = 100000000;
+ long consumeUserResourcePercent = 0;
+
+
+ Transaction trx = TVMTestUtils.generateDeploySmartContractAndGetTransaction(
+ contractName,address,ABI,code,value,fee,consumeUserResourcePercent,null);
+ byte[] contractAddress = Wallet.generateContractAddress(trx);
+ runtime = TVMTestUtils.processTransactionAndReturnRuntime(trx, deposit, null);
+ Assert.assertNotNull(runtime.getRuntimeError().contains("REVERT"));
+ Assert.assertNull(dbManager.getAccountStore().get(contractAddress));
+ }
+
+
+ /**
+ * pragma solidity ^0.4.16;
+ * contract transferWhenTriggerContract {
+ * constructor () {}
+ * function transferTo(address toAddress) public payable{
+ * toAddress.transfer(5);
+ * }
+ * }
+ */
+ @Test
+ public void TransferTrxToContractAccountWhenTriggerAContract()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+
+ String contractName = "TransferWhenDeployContract";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"toAddress\",\"type\":\"address\"}],"
+ + "\"name\":\"transferTo\",\"outputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"function\"},"
+ + "{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]";
+ String code = "608060405234801561001057600080fd5b5060ee8061001f6000396000f300608060405260043610603f576000357c01"
+ + "00000000000000000000000000000000000000000000000000000000900463ffffffff168063a03fa7e3146044575b600080fd5b607"
+ + "6600480360381019080803573ffffffffffffffffffffffffffffffffffffffff1690602001909291905050506078565b005b8073"
+ + "ffffffffffffffffffffffffffffffffffffffff166108fc60059081150290604051600060405180830381858888f1935050505015801560be573d"
+ + "6000803e3d6000fd5b50505600a165627a7a723058209b248b5be19bae77660cdc92b0a141f279dc4746d858d9d7d270a22d014eb97a0029";
+ long value = 0;
+ long feeLimit = 100000000;
+ long consumeUserResourcePercent = 0;
+
+ byte[] contractAddress = TVMTestUtils.deployContractWholeProcessReturnContractAddress(contractName,address,ABI,code,value,feeLimit,consumeUserResourcePercent,null,
+ deposit,null);
+
+
+
+ String selectorStr = "transferTo(address)";
+ String params = "000000000000000000000000548794500882809695a8a687866e76d4271a1abc"; //TRANSFER_TO
+ byte[] triggerData = TVMTestUtils.parseABI(selectorStr,params);
+
+ long triggerCallValue =100;
+
+ Transaction transaction = TVMTestUtils.generateTriggerSmartContractAndGetTransaction(address,contractAddress,triggerData,triggerCallValue,feeLimit);
+ runtime = TVMTestUtils.processTransactionAndReturnRuntime(transaction, deposit, null);
+ Assert.assertNull(runtime.getRuntimeError());
+ Assert.assertEquals(dbManager.getAccountStore().get(contractAddress).getBalance(),100 - 5);
+ Assert.assertEquals(dbManager.getAccountStore().get(Hex.decode(TRANSFER_TO)).getBalance(),10 + 5);
+ }
+
+
+
+
+ /**
+ * Release resources.
+ */
+ @AfterClass
+ public static void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+
+
+}
diff --git a/src/test/java/org/tron/common/runtime/TVMTestResult.java b/src/test/java/org/tron/common/runtime/TVMTestResult.java
new file mode 100644
index 00000000000..7b34114ce6e
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/TVMTestResult.java
@@ -0,0 +1,46 @@
+package org.tron.common.runtime;
+
+import lombok.extern.slf4j.Slf4j;
+import org.tron.core.capsule.ReceiptCapsule;
+
+@Slf4j
+public class TVMTestResult {
+
+ private Runtime runtime;
+ private ReceiptCapsule receipt;
+ private byte[] contractAddress;
+
+ public byte[] getContractAddress() {
+ return contractAddress;
+ }
+
+ public TVMTestResult setContractAddress(byte[] contractAddress) {
+ this.contractAddress = contractAddress;
+ return this;
+ }
+
+ public Runtime getRuntime() {
+ return runtime;
+ }
+
+ public TVMTestResult setRuntime(Runtime runtime) {
+ this.runtime = runtime;
+ return this;
+ }
+
+ public ReceiptCapsule getReceipt() {
+ return receipt;
+ }
+
+ public TVMTestResult setReceipt(ReceiptCapsule receipt) {
+ this.receipt = receipt;
+ return this;
+ }
+
+ public TVMTestResult(Runtime runtime, ReceiptCapsule receipt, byte[] contractAddress) {
+ this.runtime = runtime;
+ this.receipt = receipt;
+ this.contractAddress = contractAddress;
+ }
+
+}
diff --git a/src/test/java/org/tron/common/runtime/TVMTestUtils.java b/src/test/java/org/tron/common/runtime/TVMTestUtils.java
new file mode 100644
index 00000000000..42acf9ee2fd
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/TVMTestUtils.java
@@ -0,0 +1,394 @@
+package org.tron.common.runtime;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import com.google.protobuf.ByteString;
+import java.io.UnsupportedEncodingException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import lombok.extern.slf4j.Slf4j;
+import org.spongycastle.util.encoders.Hex;
+import org.tron.common.crypto.Hash;
+import org.tron.common.runtime.vm.program.invoke.ProgramInvokeFactoryImpl;
+import org.tron.common.storage.DepositImpl;
+import org.tron.core.Wallet;
+import org.tron.core.capsule.TransactionCapsule;
+import org.tron.core.db.TransactionTrace;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.TransactionTraceException;
+import org.tron.protos.Contract;
+import org.tron.protos.Contract.CreateSmartContract;
+import org.tron.protos.Contract.TriggerSmartContract;
+import org.tron.protos.Protocol.Block;
+import org.tron.protos.Protocol.SmartContract;
+import org.tron.protos.Protocol.Transaction;
+import org.tron.protos.Protocol.Transaction.Contract.ContractType;
+import stest.tron.wallet.common.client.WalletClient;
+
+
+/**
+ * Below functions mock the process to deploy, trigger a contract. Not consider of the transaction process on real chain(such as db revoke...).
+ * Just use them to execute runtime actions and vm commands.
+ */
+@Slf4j
+public class TVMTestUtils {
+
+ public static byte[] deployContractWholeProcessReturnContractAddress(String contractName,
+ byte[] callerAddress,
+ String ABI, String code, long value, long feeLimit, long consumeUserResourcePercent,
+ String libraryAddressPair,DepositImpl deposit, Block block)
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ Transaction trx = generateDeploySmartContractAndGetTransaction(contractName,callerAddress,ABI,code,value,feeLimit,consumeUserResourcePercent,libraryAddressPair);
+ processTransactionAndReturnRuntime(trx,deposit,block);
+ return Wallet.generateContractAddress(trx);
+ }
+
+ public static Runtime triggerContractWholeProcessReturnContractAddress(byte[] callerAddress,
+ byte[] contractAddress, byte[] data, long callValue, long feeLimit,DepositImpl deposit, Block block)
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ Transaction trx = generateTriggerSmartContractAndGetTransaction(callerAddress,contractAddress,data,callValue,feeLimit);
+ return processTransactionAndReturnRuntime(trx, deposit, block);
+ }
+
+ /**
+ * return generated smart contract Transaction, just before we use it to broadcast and push transaction
+ * @param contractName
+ * @param callerAddress
+ * @param ABI
+ * @param code
+ * @param value
+ * @param feeLimit
+ * @param consumeUserResourcePercent
+ * @param libraryAddressPair
+ * @return
+ */
+ public static Transaction generateDeploySmartContractAndGetTransaction(String contractName,
+ byte[] callerAddress,
+ String ABI, String code, long value, long feeLimit, long consumeUserResourcePercent,
+ String libraryAddressPair) {
+
+ CreateSmartContract contract = buildCreateSmartContract(contractName,callerAddress,ABI,code,value,consumeUserResourcePercent,libraryAddressPair);
+ TransactionCapsule trxCapWithoutFeeLimit = new TransactionCapsule(contract,ContractType.CreateSmartContract);
+ Transaction.Builder transactionBuilder = trxCapWithoutFeeLimit.getInstance().toBuilder();
+ Transaction.raw.Builder rawBuilder = trxCapWithoutFeeLimit.getInstance().getRawData().toBuilder();
+ rawBuilder.setFeeLimit(feeLimit);
+ transactionBuilder.setRawData(rawBuilder);
+ Transaction trx = transactionBuilder.build();
+ return trx;
+ }
+
+ /**
+ * use given input Transaction,deposit,block and execute TVM (for both Deploy and Trigger contracts)
+ * @param trx
+ * @param deposit
+ * @param block
+ * @return
+ * @throws TransactionTraceException
+ * @throws ContractExeException
+ * @throws ContractValidateException
+ * @throws OutOfSlotTimeException
+ */
+
+ public static Runtime processTransactionAndReturnRuntime(Transaction trx,
+ DepositImpl deposit, Block block)
+ throws TransactionTraceException, ContractExeException, ContractValidateException, OutOfSlotTimeException {
+ TransactionCapsule trxCap = new TransactionCapsule(trx);
+ TransactionTrace trace = new TransactionTrace(trxCap, deposit.getDbManager());
+ Runtime runtime = new Runtime(trace, block,deposit,
+ new ProgramInvokeFactoryImpl());
+
+ // init
+ trace.init();
+ //exec
+ trace.exec(runtime);
+
+ return runtime;
+ }
+
+
+ public static TVMTestResult deployContractAndReturnTVMTestResult(String contractName,
+ byte[] callerAddress,
+ String ABI, String code, long value, long feeLimit, long consumeUserResourcePercent,
+ String libraryAddressPair, DepositImpl deposit, Block block)
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ Transaction trx = generateDeploySmartContractAndGetTransaction(contractName, callerAddress, ABI,
+ code, value, feeLimit, consumeUserResourcePercent, libraryAddressPair);
+
+ byte[] contractAddress = Wallet.generateContractAddress(trx);
+
+ return processTransactionAndReturnTVMTestResult(trx, deposit, block)
+ .setContractAddress(Wallet.generateContractAddress(trx));
+ }
+
+ public static TVMTestResult triggerContractAndReturnTVMTestResult(byte[] callerAddress,
+ byte[] contractAddress, byte[] data, long callValue, long feeLimit, DepositImpl deposit,
+ Block block)
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ Transaction trx = generateTriggerSmartContractAndGetTransaction(callerAddress, contractAddress,
+ data, callValue, feeLimit);
+ return processTransactionAndReturnTVMTestResult(trx, deposit, block)
+ .setContractAddress(contractAddress);
+ }
+
+
+ public static TVMTestResult processTransactionAndReturnTVMTestResult(Transaction trx,
+ DepositImpl deposit, Block block)
+ throws TransactionTraceException, ContractExeException, ContractValidateException, OutOfSlotTimeException {
+ TransactionCapsule trxCap = new TransactionCapsule(trx);
+ TransactionTrace trace = new TransactionTrace(trxCap, deposit.getDbManager());
+ Runtime runtime = new Runtime(trace, block, deposit,
+ new ProgramInvokeFactoryImpl());
+
+ // init
+ trace.init();
+ //exec
+ trace.exec(runtime);
+
+ trace.pay();
+
+ return new TVMTestResult(runtime, trace.getReceipt(), null);
+ }
+
+
+
+ /**
+ * create the Contract Instance for smart contract.
+ *
+ * @param contractName
+ * @param address
+ * @param ABI
+ * @param code
+ * @param value
+ * @param consumeUserResourcePercent
+ * @param libraryAddressPair
+ * @return
+ */
+ public static CreateSmartContract buildCreateSmartContract(String contractName,
+ byte[] address,
+ String ABI, String code, long value, long consumeUserResourcePercent,
+ String libraryAddressPair){
+ SmartContract.ABI abi = jsonStr2ABI(ABI);
+ if (abi == null) {
+ logger.error("abi is null");
+ return null;
+ }
+
+ SmartContract.Builder builder = SmartContract.newBuilder();
+ builder.setName(contractName);
+ builder.setOriginAddress(ByteString.copyFrom(address));
+ builder.setAbi(abi);
+ builder.setConsumeUserResourcePercent(consumeUserResourcePercent);
+
+ if (value != 0) {
+ builder.setCallValue(value);
+ }
+ byte[] byteCode;
+ if (null != libraryAddressPair) {
+ byteCode = replaceLibraryAddress(code, libraryAddressPair);
+ } else {
+ byteCode = Hex.decode(code);
+ }
+
+ builder.setBytecode(ByteString.copyFrom(byteCode));
+ return CreateSmartContract.newBuilder().setOwnerAddress(ByteString.copyFrom(address)).
+ setNewContract(builder.build()).build();
+ }
+
+
+
+
+ public static Transaction generateTriggerSmartContractAndGetTransaction(
+ byte[] callerAddress, byte[] contractAddress, byte[] data,long callValue, long feeLimit) {
+
+ TriggerSmartContract contract = buildTriggerSmartContract(callerAddress,contractAddress,data,callValue);
+ TransactionCapsule trxCapWithoutFeeLimit = new TransactionCapsule(contract,ContractType.TriggerSmartContract);
+ Transaction.Builder transactionBuilder = trxCapWithoutFeeLimit.getInstance().toBuilder();
+ Transaction.raw.Builder rawBuilder = trxCapWithoutFeeLimit.getInstance().getRawData().toBuilder();
+ rawBuilder.setFeeLimit(feeLimit);
+ transactionBuilder.setRawData(rawBuilder);
+ Transaction trx = transactionBuilder.build();
+ return trx;
+ }
+
+
+ public static TriggerSmartContract buildTriggerSmartContract(byte[] address,byte[] contractAddress, byte[] data, long callValue){
+ Contract.TriggerSmartContract.Builder builder = Contract.TriggerSmartContract.newBuilder();
+ builder.setOwnerAddress(ByteString.copyFrom(address));
+ builder.setContractAddress(ByteString.copyFrom(contractAddress));
+ builder.setData(ByteString.copyFrom(data));
+ builder.setCallValue(callValue);
+ return builder.build();
+ }
+
+ private static byte[] replaceLibraryAddress(String code, String libraryAddressPair) {
+
+ String[] libraryAddressList = libraryAddressPair.split("[,]");
+
+ for (int i = 0; i < libraryAddressList.length; i++) {
+ String cur = libraryAddressList[i];
+
+ int lastPosition = cur.lastIndexOf(":");
+ if (-1 == lastPosition) {
+ throw new RuntimeException("libraryAddress delimit by ':'");
+ }
+ String libraryName = cur.substring(0, lastPosition);
+ String addr = cur.substring(lastPosition + 1);
+ String libraryAddressHex;
+ try {
+ libraryAddressHex = (new String(Hex.encode(WalletClient.decodeFromBase58Check(addr)),
+ "US-ASCII")).substring(2);
+ } catch (UnsupportedEncodingException e) {
+ throw new RuntimeException(e); // now ignore
+ }
+ String repeated = new String(new char[40 - libraryName.length() - 2]).replace("\0", "_");
+ String beReplaced = "__" + libraryName + repeated;
+ Matcher m = Pattern.compile(beReplaced).matcher(code);
+ code = m.replaceAll(libraryAddressHex);
+ }
+
+ return Hex.decode(code);
+ }
+
+ private static SmartContract.ABI.Entry.EntryType getEntryType(String type) {
+ switch (type) {
+ case "constructor":
+ return SmartContract.ABI.Entry.EntryType.Constructor;
+ case "function":
+ return SmartContract.ABI.Entry.EntryType.Function;
+ case "event":
+ return SmartContract.ABI.Entry.EntryType.Event;
+ case "fallback":
+ return SmartContract.ABI.Entry.EntryType.Fallback;
+ default:
+ return SmartContract.ABI.Entry.EntryType.UNRECOGNIZED;
+ }
+ }
+
+ private static SmartContract.ABI.Entry.StateMutabilityType getStateMutability(
+ String stateMutability) {
+ switch (stateMutability) {
+ case "pure":
+ return SmartContract.ABI.Entry.StateMutabilityType.Pure;
+ case "view":
+ return SmartContract.ABI.Entry.StateMutabilityType.View;
+ case "nonpayable":
+ return SmartContract.ABI.Entry.StateMutabilityType.Nonpayable;
+ case "payable":
+ return SmartContract.ABI.Entry.StateMutabilityType.Payable;
+ default:
+ return SmartContract.ABI.Entry.StateMutabilityType.UNRECOGNIZED;
+ }
+ }
+
+ private static SmartContract.ABI jsonStr2ABI(String jsonStr) {
+ if (jsonStr == null) {
+ return null;
+ }
+
+ JsonParser jsonParser = new JsonParser();
+ JsonElement jsonElementRoot = jsonParser.parse(jsonStr);
+ JsonArray jsonRoot = jsonElementRoot.getAsJsonArray();
+ SmartContract.ABI.Builder abiBuilder = SmartContract.ABI.newBuilder();
+ for (int index = 0; index < jsonRoot.size(); index++) {
+ JsonElement abiItem = jsonRoot.get(index);
+ boolean anonymous = abiItem.getAsJsonObject().get("anonymous") != null &&
+ abiItem.getAsJsonObject().get("anonymous").getAsBoolean();
+ boolean constant = abiItem.getAsJsonObject().get("constant") != null &&
+ abiItem.getAsJsonObject().get("constant").getAsBoolean();
+ String name = abiItem.getAsJsonObject().get("name") != null ?
+ abiItem.getAsJsonObject().get("name").getAsString() : null;
+ JsonArray inputs = abiItem.getAsJsonObject().get("inputs") != null ?
+ abiItem.getAsJsonObject().get("inputs").getAsJsonArray() : null;
+ JsonArray outputs = abiItem.getAsJsonObject().get("outputs") != null ?
+ abiItem.getAsJsonObject().get("outputs").getAsJsonArray() : null;
+ String type = abiItem.getAsJsonObject().get("type") != null ?
+ abiItem.getAsJsonObject().get("type").getAsString() : null;
+ boolean payable = abiItem.getAsJsonObject().get("payable") != null &&
+ abiItem.getAsJsonObject().get("payable").getAsBoolean();
+ String stateMutability = abiItem.getAsJsonObject().get("stateMutability") != null ?
+ abiItem.getAsJsonObject().get("stateMutability").getAsString() : null;
+ if (type == null) {
+ logger.error("No type!");
+ return null;
+ }
+ if (!type.equalsIgnoreCase("fallback") && null == inputs) {
+ logger.error("No inputs!");
+ return null;
+ }
+
+ SmartContract.ABI.Entry.Builder entryBuilder = SmartContract.ABI.Entry.newBuilder();
+ entryBuilder.setAnonymous(anonymous);
+ entryBuilder.setConstant(constant);
+ if (name != null) {
+ entryBuilder.setName(name);
+ }
+
+ /* { inputs : optional } since fallback function not requires inputs*/
+ if (null != inputs) {
+ for (int j = 0; j < inputs.size(); j++) {
+ JsonElement inputItem = inputs.get(j);
+ if (inputItem.getAsJsonObject().get("name") == null ||
+ inputItem.getAsJsonObject().get("type") == null) {
+ logger.error("Input argument invalid due to no name or no type!");
+ return null;
+ }
+ String inputName = inputItem.getAsJsonObject().get("name").getAsString();
+ String inputType = inputItem.getAsJsonObject().get("type").getAsString();
+ SmartContract.ABI.Entry.Param.Builder paramBuilder = SmartContract.ABI.Entry.Param
+ .newBuilder();
+ paramBuilder.setIndexed(false);
+ paramBuilder.setName(inputName);
+ paramBuilder.setType(inputType);
+ entryBuilder.addInputs(paramBuilder.build());
+ }
+ }
+
+ /* { outputs : optional } */
+ if (outputs != null) {
+ for (int k = 0; k < outputs.size(); k++) {
+ JsonElement outputItem = outputs.get(k);
+ if (outputItem.getAsJsonObject().get("name") == null ||
+ outputItem.getAsJsonObject().get("type") == null) {
+ logger.error("Output argument invalid due to no name or no type!");
+ return null;
+ }
+ String outputName = outputItem.getAsJsonObject().get("name").getAsString();
+ String outputType = outputItem.getAsJsonObject().get("type").getAsString();
+ SmartContract.ABI.Entry.Param.Builder paramBuilder = SmartContract.ABI.Entry.Param
+ .newBuilder();
+ paramBuilder.setIndexed(false);
+ paramBuilder.setName(outputName);
+ paramBuilder.setType(outputType);
+ entryBuilder.addOutputs(paramBuilder.build());
+ }
+ }
+
+ entryBuilder.setType(getEntryType(type));
+ entryBuilder.setPayable(payable);
+ if (stateMutability != null) {
+ entryBuilder.setStateMutability(getStateMutability(stateMutability));
+ }
+
+ abiBuilder.addEntrys(entryBuilder.build());
+ }
+
+ return abiBuilder.build();
+ }
+
+
+
+
+ public static byte[] parseABI(String selectorStr, String params){
+ if(params == null){
+ params = "";
+ }
+ byte[] selector = new byte[4];
+ System.arraycopy(Hash.sha3(selectorStr.getBytes()), 0, selector,0, 4);
+ byte[] triggerData = Hex.decode(Hex.toHexString(selector) + params);
+ return triggerData;
+ }
+
+}
diff --git a/src/test/java/org/tron/common/runtime/vm/CPUEnergyTest.java b/src/test/java/org/tron/common/runtime/vm/CPUEnergyTest.java
new file mode 100644
index 00000000000..ed69a47ba8a
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/vm/CPUEnergyTest.java
@@ -0,0 +1,244 @@
+package org.tron.common.runtime.vm;
+
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.spongycastle.util.encoders.Hex;
+import org.tron.common.application.TronApplicationContext;
+import org.testng.Assert;
+import org.tron.common.runtime.TVMTestResult;
+import org.tron.common.runtime.TVMTestUtils;
+import org.tron.common.storage.DepositImpl;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.TransactionTraceException;
+import org.tron.protos.Protocol.AccountType;
+
+@Slf4j
+public class CPUEnergyTest {
+
+ private Manager dbManager;
+ private TronApplicationContext context;
+ private DepositImpl deposit;
+ private String dbPath = "output_CPUEnergyTest";
+ private String OWNER_ADDRESS;
+
+
+ /**
+ * Init data.
+ */
+ @Before
+ public void init() {
+ Args.setParam(new String[]{"--output-directory", dbPath, "--debug"}, Constant.TEST_CONF);
+ context = new TronApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
+ dbManager = context.getBean(Manager.class);
+ deposit = DepositImpl.createRoot(dbManager);
+ deposit.createAccount(Hex.decode(OWNER_ADDRESS), AccountType.Normal);
+ deposit.addBalance(Hex.decode(OWNER_ADDRESS), 30000000000000L);
+ }
+
+ // solidity for callValueTest
+ // pragma solidity ^0.4.0;
+ //
+ // contract SubContract {
+ //
+ // constructor () payable {}
+ // mapping(uint256=>uint256) map;
+ //
+ // function doSimple() public payable returns (uint ret) {
+ // return 42;
+ // }
+ //
+ // function doComplex() public payable returns (uint ret) {
+ // for (uint i = 0; i < 10; i++) {
+ // map[i] = i;
+ // }
+ // }
+ //
+ // }
+ //
+ // contract TestForValueGasFunction {
+ //
+ // SubContract subContract;
+ //
+ // constructor () payable {
+ // subContract = new SubContract();
+ // }
+ //
+ // function simpleCall() public { subContract.doSimple.value(10).gas(3)(); }
+ //
+ // function complexCall() public { subContract.doComplex.value(10).gas(3)(); }
+ //
+ // }
+
+ @Test
+ @Ignore
+ public void callValueTest()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+
+ long value = 10000000L;
+ long feeLimit = 20000000000000L; // sun
+ long consumeUserResourcePercent = 100;
+ TVMTestResult result = deployCallValueTestContract(value, feeLimit,
+ consumeUserResourcePercent);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 52439);
+ byte[] contractAddress = result.getContractAddress();
+
+ /* =================================== CALL simpleCall() =================================== */
+ byte[] triggerData = TVMTestUtils.parseABI("simpleCall()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 7370);
+
+ /* =================================== CALL complexCall() =================================== */
+ triggerData = TVMTestUtils.parseABI("complexCall()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 9459);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), true);
+ }
+
+ // solidity for sendTest and transferTest
+ // pragma solidity ^0.4.0;
+ //
+ // contract SubContract {
+ //
+ // constructor () payable {}
+ // mapping(uint256=>uint256) map;
+ //
+ // function () payable {
+ // map[1] = 1;
+ // }
+ // }
+ //
+ // contract TestForSendAndTransfer {
+ //
+ // SubContract subContract;
+ //
+ // constructor () payable {
+ // subContract = new SubContract();
+ // }
+ //
+ //
+ // function doSend() public { address(subContract).send(10 ether); }
+ //
+ // function doTransfer() public { address(subContract).transfer(10 ether); }
+ //
+ // function getBalance() public view returns(uint256 balance){
+ // balance = address(this).balance;
+ // }
+ //
+ // }
+
+
+
+ @Test
+ public void sendTest()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+
+ long value = 10000000L;
+ long feeLimit = 20000000000000L; // sun
+ long consumeUserResourcePercent = 100;
+ TVMTestResult result = deploySendAndTransferTestContract(value, feeLimit,
+ consumeUserResourcePercent);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 52400);
+ byte[] contractAddress = result.getContractAddress();
+ Assert.assertEquals(deposit.getAccount(contractAddress).getBalance(), 10000000L);
+
+ /* =================================== CALL doSend() =================================== */
+ byte[] triggerData = TVMTestUtils.parseABI("doSend()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 9325);
+ Assert.assertEquals(result.getRuntime().getResult().getException(), null);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertEquals(deposit.getAccount(contractAddress).getBalance(), 10000000L);
+ }
+
+ @Test
+ public void transferTest()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+
+ long value = 10000000L;
+ long feeLimit = 20000000000000L; // sun
+ long consumeUserResourcePercent = 100;
+ TVMTestResult result = deploySendAndTransferTestContract(value, feeLimit,
+ consumeUserResourcePercent);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 52400);
+ byte[] contractAddress = result.getContractAddress();
+ Assert.assertEquals(deposit.getAccount(contractAddress).getBalance(), 10000000L);
+
+ /* =================================== CALL doSend() =================================== */
+ byte[] triggerData = TVMTestUtils.parseABI("doTransfer()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 9330);
+ Assert.assertEquals(result.getRuntime().getResult().getException(), null);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), true);
+ Assert.assertEquals(deposit.getAccount(contractAddress).getBalance(), 10000000L);
+ }
+
+ public TVMTestResult deployCallValueTestContract(long value, long feeLimit,
+ long consumeUserResourcePercent)
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ String contractName = "TestForCallValue";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI = "[{\"constant\":false,\"inputs\":[],\"name\":\"complexCall\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"simpleCall\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"constructor\"}]";
+ String code = "608060405261000c61004e565b604051809103906000f080158015610028573d6000803e3d6000fd5b5060008054600160a060020a031916600160a060020a039290921691909117905561005d565b60405160d68061020b83390190565b61019f8061006c6000396000f3006080604052600436106100325763ffffffff60e060020a60003504166306ce93af811461003757806340de221c1461004e575b600080fd5b34801561004357600080fd5b5061004c610063565b005b34801561005a57600080fd5b5061004c610103565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663cd95478c600a6003906040518363ffffffff1660e060020a0281526004016020604051808303818589803b1580156100d357600080fd5b5088f11580156100e7573d6000803e3d6000fd5b5050505050506040513d60208110156100ff57600080fd5b5050565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1663b993e5e2600a6003906040518363ffffffff1660e060020a0281526004016020604051808303818589803b1580156100d357600080fd00a165627a7a72305820cb5f172ca9f81235a8b33ee1ddef9dd1b398644cf61228569356ff051bfaf3d10029608060405260c4806100126000396000f30060806040526004361060485763ffffffff7c0100000000000000000000000000000000000000000000000000000000600035041663b993e5e28114604d578063cd95478c146065575b600080fd5b6053606b565b60408051918252519081900360200190f35b60536070565b602a90565b6000805b600a81101560945760008181526020819052604090208190556001016074565b50905600a165627a7a723058205ded543feb546472be4e116e713a2d46b8dafc823ca31256e67a1be92a6752730029";
+ String libraryAddressPair = null;
+
+ return TVMTestUtils
+ .deployContractAndReturnTVMTestResult(contractName, address, ABI, code,
+ value,
+ feeLimit, consumeUserResourcePercent, libraryAddressPair,
+ deposit, null);
+ }
+
+ public TVMTestResult deploySendAndTransferTestContract(long value, long feeLimit,
+ long consumeUserResourcePercent)
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ String contractName = "TestForSendAndTransfer";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"getBalance\",\"outputs\":[{\"name\":\"balance\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"doTransfer\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"doSend\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":true,\"stateMutability\":\"payable\",\"type\":\"constructor\"}]";
+ String code = "608060405261000c61004e565b604051809103906000f080158015610028573d6000803e3d6000fd5b5060008054600160a060020a031916600160a060020a039290921691909117905561005d565b604051606f806101d183390190565b6101658061006c6000396000f3006080604052600436106100565763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166312065fe0811461005b57806333182e8f14610082578063e3d237f914610099575b600080fd5b34801561006757600080fd5b506100706100ae565b60408051918252519081900360200190f35b34801561008e57600080fd5b506100976100b3565b005b3480156100a557600080fd5b506100976100ff565b303190565b6000805460405173ffffffffffffffffffffffffffffffffffffffff9091169190678ac7230489e800009082818181858883f193505050501580156100fc573d6000803e3d6000fd5b50565b6000805460405173ffffffffffffffffffffffffffffffffffffffff9091169190678ac7230489e800009082818181858883f150505050505600a165627a7a723058201c038c3f247a923f3cb38ac9d3e0f2804c483ae86e67e3578d8839b39a71d2f900296080604052605e8060116000396000f3006080604052600160008181526020527fada5013122d395ba3c54772283fb069b10426056ef8ca54750cb9bb552a59e7d550000a165627a7a723058206850a348611e816bc7d1acd245e900cdde8ce98252ccc01d424d78bfd12eb6ed0029";
+ String libraryAddressPair = null;
+
+ return TVMTestUtils
+ .deployContractAndReturnTVMTestResult(contractName, address, ABI, code,
+ value,
+ feeLimit, consumeUserResourcePercent, libraryAddressPair,
+ deposit, null);
+ }
+
+ /**
+ * Release resources.
+ */
+ @After
+ public void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+}
diff --git a/src/test/java/org/tron/common/runtime/vm/CPUEnergyWhenAssertStyleTest.java b/src/test/java/org/tron/common/runtime/vm/CPUEnergyWhenAssertStyleTest.java
new file mode 100644
index 00000000000..71de78262f9
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/vm/CPUEnergyWhenAssertStyleTest.java
@@ -0,0 +1,225 @@
+package org.tron.common.runtime.vm;
+
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.spongycastle.util.encoders.Hex;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.testng.Assert;
+import org.tron.common.application.TronApplicationContext;
+import org.tron.common.runtime.TVMTestResult;
+import org.tron.common.runtime.TVMTestUtils;
+import org.tron.common.runtime.vm.program.Program.IllegalOperationException;
+import org.tron.common.storage.DepositImpl;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.TransactionTraceException;
+import org.tron.protos.Protocol.AccountType;
+
+
+@Slf4j
+@Ignore
+public class CPUEnergyWhenAssertStyleTest {
+
+ private Manager dbManager;
+ private AnnotationConfigApplicationContext context;
+ private DepositImpl deposit;
+ private String dbPath = "output_CPUEnergyWhenAssertStyleTest";
+ private String OWNER_ADDRESS;
+
+
+ /**
+ * Init data.
+ */
+ @Before
+ public void init() {
+ Args.setParam(new String[]{"--output-directory", dbPath, "--debug"}, Constant.TEST_CONF);
+ // context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
+ dbManager = context.getBean(Manager.class);
+ deposit = DepositImpl.createRoot(dbManager);
+ deposit.createAccount(Hex.decode(OWNER_ADDRESS), AccountType.Normal);
+ deposit.addBalance(Hex.decode(OWNER_ADDRESS), 30000000000000L);
+ }
+
+ // solidity for CPUEnergyWhenAssertStyleTest
+ // pragma solidity ^0.4.0;
+ //
+ // An assert-style exception is generated in the following situations:
+ //
+ // If you access an array at a too large or negative index (i.e. x[i] where i >= x.length or i < 0).
+ // If you access a fixed-length bytesN at a too large or negative index.
+ // If you divide or modulo by zero (e.g. 5 / 0 or 23 % 0).
+ // If you shift by a negative amount.
+ // If you convert a value too big or negative into an enum type.
+ // If you call a zero-initialized variable of internal function type.
+ // If you call assert with an argument that evaluates to false.
+
+ // contract TestAssertStyleContract{
+ //
+ // enum fortest {one, second, third}
+ //
+ // function testOutOfIndex() public {
+ // uint256[] memory a = new uint256[](10);
+ // a[10] = 10;
+ // }
+ //
+ // function testbytesN() public {
+ // bytes16 a = 0x12345;
+ // uint c = 20;
+ // uint b = uint256(a[c]);
+ // }
+ //
+ // function testDivZero() public {
+ // uint256 a = 0;
+ // uint256 b = 10 / a;
+ // }
+ //
+ // function testShiftByNegative() public {
+ // int256 shift = -10;
+ // int256 a = 1024 >> shift;
+ // }
+ //
+ // function testEnumType() public {
+ // fortest a = fortest(10);
+ //
+ // }
+ //
+ // function testFunctionPointer() public {
+ // function (int) internal pure returns (int) funcPtr;
+ // funcPtr(1);
+ // }
+ //
+ // function testAssert(){
+ // assert(1==2);
+ // }
+ //
+ // }
+
+ @Test
+ public void whenAssertStyleTest()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+
+ long value = 0;
+ long feeLimit = 20000000000000L; // sun
+ long consumeUserResourcePercent = 100;
+ TVMTestResult result = deployWhenAssertStyleTestContract(value, feeLimit,
+ consumeUserResourcePercent);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 135);
+ byte[] contractAddress = result.getContractAddress();
+
+ /* =================================== CALL testOutOfIndex() =================================== */
+ byte[] triggerData = TVMTestUtils.parseABI("testOutOfIndex()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testbytesN() =================================== */
+ triggerData = TVMTestUtils.parseABI("testbytesN()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testDivZero() =================================== */
+ triggerData = TVMTestUtils.parseABI("testDivZero()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testShiftByNegative() =================================== */
+ triggerData = TVMTestUtils.parseABI("testShiftByNegative()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testEnumType() =================================== */
+ triggerData = TVMTestUtils.parseABI("testEnumType()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testFunctionPointer() =================================== */
+ triggerData = TVMTestUtils.parseABI("testFunctionPointer()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testAssert() =================================== */
+ triggerData = TVMTestUtils.parseABI("testAssert()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ }
+
+ public TVMTestResult deployWhenAssertStyleTestContract(long value, long feeLimit,
+ long consumeUserResourcePercent)
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ String contractName = "test";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI = "[{\"constant\":false,\"inputs\":[],\"name\":\"testbytesN\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testAssert\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testEnumType\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testOutOfIndex\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testDivZero\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testShiftByNegative\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testFunctionPointer\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]";
+ String code = "608060405234801561001057600080fd5b506101d7806100206000396000f3006080604052600436106100825763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631e76e10781146100875780632b813bc01461009e5780635a43cddc146100b35780639a4e1fa0146100c8578063b87d948d146100dd578063e88e362a146100f2578063e9ad8ee714610107575b600080fd5b34801561009357600080fd5b5061009c61011c565b005b3480156100aa57600080fd5b5061009c610138565b3480156100bf57600080fd5b5061009c61013a565b3480156100d457600080fd5b5061009c610140565b3480156100e957600080fd5b5061009c610183565b3480156100fe57600080fd5b5061009c61018b565b34801561011357600080fd5b5061009c610196565b7201234500000000000000000000000000000000601460008282fe5bfe5b6000600afe5b60408051600a80825261016082019092526060916020820161014080388339019050509050600a81600a81518110151561017657fe5b6020908102909101015250565b60008080600afe5b600919600081610400fe5b6101386101a760018263ffffffff16565b50505600a165627a7a72305820155b43453889c7c579af81c62359ac291bb44abe0ab5c6772971f69745a4cfc20029";
+ String libraryAddressPair = null;
+
+ return TVMTestUtils
+ .deployContractAndReturnTVMTestResult(contractName, address, ABI, code,
+ value,
+ feeLimit, consumeUserResourcePercent, libraryAddressPair,
+ deposit, null);
+ }
+
+ /**
+ * Release resources.
+ */
+ @After
+ public void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+}
+
diff --git a/src/test/java/org/tron/common/runtime/vm/CPUEnergyWhenRevertStyleTest.java b/src/test/java/org/tron/common/runtime/vm/CPUEnergyWhenRevertStyleTest.java
new file mode 100644
index 00000000000..0db91cc83ad
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/vm/CPUEnergyWhenRevertStyleTest.java
@@ -0,0 +1,224 @@
+package org.tron.common.runtime.vm;
+
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.spongycastle.util.encoders.Hex;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.testng.Assert;
+import org.tron.common.application.TronApplicationContext;
+import org.tron.common.runtime.TVMTestResult;
+import org.tron.common.runtime.TVMTestUtils;
+import org.tron.common.runtime.vm.program.Program.IllegalOperationException;
+import org.tron.common.storage.DepositImpl;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.TransactionTraceException;
+import org.tron.protos.Protocol.AccountType;
+
+@Slf4j
+@Ignore
+public class CPUEnergyWhenRevertStyleTest {
+
+ private Manager dbManager;
+ private AnnotationConfigApplicationContext context;
+ private DepositImpl deposit;
+ private String dbPath = "output_CPUEnergyWhenAssertStyleTest";
+ private String OWNER_ADDRESS;
+
+
+ /**
+ * Init data.
+ */
+ @Before
+ public void init() {
+ Args.setParam(new String[]{"--output-directory", dbPath, "--debug"}, Constant.TEST_CONF);
+ // context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
+ dbManager = context.getBean(Manager.class);
+ deposit = DepositImpl.createRoot(dbManager);
+ deposit.createAccount(Hex.decode(OWNER_ADDRESS), AccountType.Normal);
+ deposit.addBalance(Hex.decode(OWNER_ADDRESS), 30000000000000L);
+ }
+
+ // solidity for CPUEnergyWhenAssertStyleTest
+ // pragma solidity ^0.4.0;
+ //
+ // An assert-style exception is generated in the following situations:
+ //
+ // If you access an array at a too large or negative index (i.e. x[i] where i >= x.length or i < 0).
+ // If you access a fixed-length bytesN at a too large or negative index.
+ // If you divide or modulo by zero (e.g. 5 / 0 or 23 % 0).
+ // If you shift by a negative amount.
+ // If you convert a value too big or negative into an enum type.
+ // If you call a zero-initialized variable of internal function type.
+ // If you call assert with an argument that evaluates to false.
+
+ // contract TestAssertStyleContract{
+ //
+ // enum fortest {one, second, third}
+ //
+ // function testOutOfIndex() public {
+ // uint256[] memory a = new uint256[](10);
+ // a[10] = 10;
+ // }
+ //
+ // function testbytesN() public {
+ // bytes16 a = 0x12345;
+ // uint c = 20;
+ // uint b = uint256(a[c]);
+ // }
+ //
+ // function testDivZero() public {
+ // uint256 a = 0;
+ // uint256 b = 10 / a;
+ // }
+ //
+ // function testShiftByNegative() public {
+ // int256 shift = -10;
+ // int256 a = 1024 >> shift;
+ // }
+ //
+ // function testEnumType() public {
+ // fortest a = fortest(10);
+ //
+ // }
+ //
+ // function testFunctionPointer() public {
+ // function (int) internal pure returns (int) funcPtr;
+ // funcPtr(1);
+ // }
+ //
+ // function testAssert(){
+ // assert(1==2);
+ // }
+ //
+ // }
+
+ @Test
+ public void whenAssertStyleTest()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+
+ long value = 0;
+ long feeLimit = 20000000000000L; // sun
+ long consumeUserResourcePercent = 100;
+ TVMTestResult result = deployWhenAssertStyleTestContract(value, feeLimit,
+ consumeUserResourcePercent);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 135);
+ byte[] contractAddress = result.getContractAddress();
+
+ /* =================================== CALL testOutOfIndex() =================================== */
+ byte[] triggerData = TVMTestUtils.parseABI("testOutOfIndex()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testbytesN() =================================== */
+ triggerData = TVMTestUtils.parseABI("testbytesN()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testDivZero() =================================== */
+ triggerData = TVMTestUtils.parseABI("testDivZero()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testShiftByNegative() =================================== */
+ triggerData = TVMTestUtils.parseABI("testShiftByNegative()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testEnumType() =================================== */
+ triggerData = TVMTestUtils.parseABI("testEnumType()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testFunctionPointer() =================================== */
+ triggerData = TVMTestUtils.parseABI("testFunctionPointer()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ /* =================================== CALL testAssert() =================================== */
+ triggerData = TVMTestUtils.parseABI("testAssert()", null);
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, 0, feeLimit, deposit, null);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 200000000000L);
+ Assert.assertEquals(result.getRuntime().getResult().isRevert(), false);
+ Assert.assertTrue(
+ result.getRuntime().getResult().getException() instanceof IllegalOperationException);
+
+ }
+
+ public TVMTestResult deployWhenAssertStyleTestContract(long value, long feeLimit,
+ long consumeUserResourcePercent)
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ String contractName = "test";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI = "[{\"constant\":false,\"inputs\":[],\"name\":\"testbytesN\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testAssert\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testEnumType\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testOutOfIndex\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testDivZero\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testShiftByNegative\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[],\"name\":\"testFunctionPointer\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]";
+ String code = "608060405234801561001057600080fd5b506101d7806100206000396000f3006080604052600436106100825763ffffffff7c01000000000000000000000000000000000000000000000000000000006000350416631e76e10781146100875780632b813bc01461009e5780635a43cddc146100b35780639a4e1fa0146100c8578063b87d948d146100dd578063e88e362a146100f2578063e9ad8ee714610107575b600080fd5b34801561009357600080fd5b5061009c61011c565b005b3480156100aa57600080fd5b5061009c610138565b3480156100bf57600080fd5b5061009c61013a565b3480156100d457600080fd5b5061009c610140565b3480156100e957600080fd5b5061009c610183565b3480156100fe57600080fd5b5061009c61018b565b34801561011357600080fd5b5061009c610196565b7201234500000000000000000000000000000000601460008282fe5bfe5b6000600afe5b60408051600a80825261016082019092526060916020820161014080388339019050509050600a81600a81518110151561017657fe5b6020908102909101015250565b60008080600afe5b600919600081610400fe5b6101386101a760018263ffffffff16565b50505600a165627a7a72305820155b43453889c7c579af81c62359ac291bb44abe0ab5c6772971f69745a4cfc20029";
+ String libraryAddressPair = null;
+
+ return TVMTestUtils
+ .deployContractAndReturnTVMTestResult(contractName, address, ABI, code,
+ value,
+ feeLimit, consumeUserResourcePercent, libraryAddressPair,
+ deposit, null);
+ }
+
+ /**
+ * Release resources.
+ */
+ @After
+ public void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+}
+
diff --git a/src/test/java/org/tron/common/runtime/vm/CPUTimeTest.java b/src/test/java/org/tron/common/runtime/vm/CPUTimeTest.java
new file mode 100644
index 00000000000..c7e818ad978
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/vm/CPUTimeTest.java
@@ -0,0 +1,138 @@
+package org.tron.common.runtime.vm;
+
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.spongycastle.util.encoders.Hex;
+import org.tron.common.application.TronApplicationContext;
+import org.testng.Assert;
+import org.tron.common.runtime.TVMTestResult;
+import org.tron.common.runtime.TVMTestUtils;
+import org.tron.common.runtime.vm.program.Program.OutOfEnergyException;
+import org.tron.common.storage.DepositImpl;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.TransactionTraceException;
+import org.tron.protos.Protocol.AccountType;
+
+@Slf4j
+@Ignore
+public class CPUTimeTest {
+
+ private Manager dbManager;
+ private TronApplicationContext context;
+ private DepositImpl deposit;
+ private String dbPath = "output_CPUTimeTest";
+ private String OWNER_ADDRESS;
+
+
+ /**
+ * Init data.
+ */
+ @Before
+ public void init() {
+ Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
+ context = new TronApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
+ dbManager = context.getBean(Manager.class);
+ deposit = DepositImpl.createRoot(dbManager);
+ deposit.createAccount(Hex.decode(OWNER_ADDRESS), AccountType.Normal);
+ deposit.addBalance(Hex.decode(OWNER_ADDRESS), 30000000000000L);
+ }
+
+ // solidity for endlessLoopTest
+ // pragma solidity ^0.4.0;
+ //
+ // contract TestForEndlessLoop {
+ //
+ // uint256 vote;
+ // constructor () public {
+ // vote = 0;
+ // }
+ //
+ // function getVote() public constant returns (uint256 _vote) {
+ // _vote = vote;
+ // }
+ //
+ // function setVote(uint256 _vote) public {
+ // vote = _vote;
+ // while(true)
+ // {
+ // vote += 1;
+ // }
+ // }
+ // }
+
+ @Test
+ public void endlessLoopTest()
+ throws ContractExeException, TransactionTraceException, ContractValidateException, OutOfSlotTimeException {
+
+ long value = 0;
+ long feeLimit = 20000000000000L;
+ long consumeUserResourcePercent = 0;
+ TVMTestResult result = deployEndlessLoopContract(value, feeLimit,
+ consumeUserResourcePercent);
+ Assert.assertEquals(result.getReceipt().getEnergyUsage(), 0);
+ Assert.assertEquals(result.getReceipt().getEnergyUsageTotal(), 5107);
+ Assert.assertEquals(result.getReceipt().getOriginEnergyUsage(), 0);
+
+ byte[] contractAddress = result.getContractAddress();
+
+ /* =================================== CALL setVote(uint256) =================================== */
+ String params = "0000000000000000000000000000000000000000000000000000000000000003";
+ byte[] triggerData = TVMTestUtils.parseABI("setVote(uint256)", params);
+ boolean haveException = false;
+ try {
+ result = TVMTestUtils
+ .triggerContractAndReturnTVMTestResult(Hex.decode(OWNER_ADDRESS),
+ contractAddress, triggerData, value, feeLimit, deposit, null);
+ Exception exception = result.getRuntime().getResult().getException();
+ Assert.assertTrue(exception instanceof OutOfEnergyException);
+ haveException = true;
+ } catch (Exception e) {
+ haveException = true;
+ Assert.assertTrue(e instanceof OutOfSlotTimeException);
+ }
+ Assert.assertTrue(haveException);
+ }
+
+ public TVMTestResult deployEndlessLoopContract(long value, long feeLimit,
+ long consumeUserResourcePercent)
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ String contractName = "EndlessLoopContract";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI = "[{\"constant\":true,\"inputs\":[],\"name\":\"getVote\",\"outputs\":[{\"name\":\"_vote\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"_vote\",\"type\":\"uint256\"}],\"name\":\"setVote\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"}]";
+ String code = "608060405234801561001057600080fd5b506000808190555060fa806100266000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630242f35114604e578063230796ae146076575b600080fd5b348015605957600080fd5b50606060a0565b6040518082815260200191505060405180910390f35b348015608157600080fd5b50609e6004803603810190808035906020019092919050505060a9565b005b60008054905090565b806000819055505b60011560cb576001600080828254019250508190555060b1565b505600a165627a7a72305820290a38c9bbafccaf6c7f752ab56d229e354da767efb72715ee9fdb653b9f4b6c0029";
+ String libraryAddressPair = null;
+
+ return TVMTestUtils
+ .deployContractAndReturnTVMTestResult(contractName, address, ABI, code,
+ value,
+ feeLimit, consumeUserResourcePercent, libraryAddressPair,
+ deposit, null);
+ }
+
+ /**
+ * Release resources.
+ */
+ @After
+ public void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+}
diff --git a/src/test/java/org/tron/common/runtime/vm/DataWordTest.java b/src/test/java/org/tron/common/runtime/vm/DataWordTest.java
new file mode 100644
index 00000000000..3388dfab36a
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/vm/DataWordTest.java
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) [2016] [ ]
+ * This file is part of the ethereumJ library.
+ *
+ * The ethereumJ library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The ethereumJ library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ethereumJ library. If not, see .
+ */
+package org.tron.common.runtime.vm;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigInteger;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Test;
+import org.spongycastle.util.encoders.Hex;
+
+@Slf4j
+public class DataWordTest {
+
+ @Test
+ public void testAddPerformance() {
+ boolean enabled = false;
+
+ if (enabled) {
+ byte[] one = new byte[]{0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54,
+ 0x41, 0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54, 0x41, 0x01,
+ 0x31, 0x54, 0x41, 0x01, 0x31, 0x54, 0x41, 0x01, 0x31, 0x54,
+ 0x41, 0x01, 0x31, 0x54, 0x41}; // Random value
+
+ int ITERATIONS = 10000000;
+
+ long now1 = System.currentTimeMillis();
+ for (int i = 0; i < ITERATIONS; i++) {
+ DataWord x = new DataWord(one);
+ x.add(x);
+ }
+ System.out.println("Add1: " + (System.currentTimeMillis() - now1) + "ms");
+
+ long now2 = System.currentTimeMillis();
+ for (int i = 0; i < ITERATIONS; i++) {
+ DataWord x = new DataWord(one);
+ x.add2(x);
+ }
+ System.out.println("Add2: " + (System.currentTimeMillis() - now2) + "ms");
+ } else {
+ System.out.println("ADD performance test is disabled.");
+ }
+ }
+
+ @Test
+ public void testAdd2() {
+ byte[] two = new byte[32];
+ two[31] = (byte) 0xff; // 0x000000000000000000000000000000000000000000000000000000000000ff
+
+ DataWord x = new DataWord(two);
+ x.add(new DataWord(two));
+ System.out.println(Hex.toHexString(x.getData()));
+
+ DataWord y = new DataWord(two);
+ y.add2(new DataWord(two));
+ System.out.println(Hex.toHexString(y.getData()));
+ }
+
+ @Test
+ public void testAdd3() {
+ byte[] three = new byte[32];
+ for (int i = 0; i < three.length; i++) {
+ three[i] = (byte) 0xff;
+ }
+
+ DataWord x = new DataWord(three);
+ x.add(new DataWord(three));
+ assertEquals(32, x.getData().length);
+ System.out.println(Hex.toHexString(x.getData()));
+
+ // FAIL
+// DataWord y = new DataWord(three);
+// y.add2(new DataWord(three));
+// System.out.println(Hex.toHexString(y.getData()));
+ }
+
+ @Test
+ public void testMod() {
+ String expected = "000000000000000000000000000000000000000000000000000000000000001a";
+
+ byte[] one = new byte[32];
+ one[31] = 0x1e; // 0x000000000000000000000000000000000000000000000000000000000000001e
+
+ byte[] two = new byte[32];
+ for (int i = 0; i < two.length; i++) {
+ two[i] = (byte) 0xff;
+ }
+ two[31] = 0x56; // 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff56
+
+ DataWord x = new DataWord(one);// System.out.println(x.value());
+ DataWord y = new DataWord(two);// System.out.println(y.value());
+ y.mod(x);
+ assertEquals(32, y.getData().length);
+ assertEquals(expected, Hex.toHexString(y.getData()));
+ }
+
+ @Test
+ public void testMul() {
+ byte[] one = new byte[32];
+ one[31] = 0x1; // 0x0000000000000000000000000000000000000000000000000000000000000001
+
+ byte[] two = new byte[32];
+ two[11] = 0x1; // 0x0000000000000000000000010000000000000000000000000000000000000000
+
+ DataWord x = new DataWord(one);// System.out.println(x.value());
+ DataWord y = new DataWord(two);// System.out.println(y.value());
+ x.mul(y);
+ assertEquals(32, y.getData().length);
+ assertEquals("0000000000000000000000010000000000000000000000000000000000000000", Hex.toHexString(y.getData()));
+ }
+
+ @Test
+ public void testMulOverflow() {
+
+ byte[] one = new byte[32];
+ one[30] = 0x1; // 0x0000000000000000000000000000000000000000000000000000000000000100
+
+ byte[] two = new byte[32];
+ two[0] = 0x1; // 0x1000000000000000000000000000000000000000000000000000000000000000
+
+ DataWord x = new DataWord(one);// System.out.println(x.value());
+ DataWord y = new DataWord(two);// System.out.println(y.value());
+ x.mul(y);
+ assertEquals(32, y.getData().length);
+ assertEquals("0100000000000000000000000000000000000000000000000000000000000000", Hex.toHexString(y.getData()));
+ }
+
+ @Test
+ public void testDiv() {
+ byte[] one = new byte[32];
+ one[30] = 0x01;
+ one[31] = 0x2c; // 0x000000000000000000000000000000000000000000000000000000000000012c
+
+ byte[] two = new byte[32];
+ two[31] = 0x0f; // 0x000000000000000000000000000000000000000000000000000000000000000f
+
+ DataWord x = new DataWord(one);
+ DataWord y = new DataWord(two);
+ x.div(y);
+
+ assertEquals(32, x.getData().length);
+ assertEquals("0000000000000000000000000000000000000000000000000000000000000014", Hex.toHexString(x.getData()));
+ }
+
+ @Test
+ public void testDivZero() {
+ byte[] one = new byte[32];
+ one[30] = 0x05; // 0x0000000000000000000000000000000000000000000000000000000000000500
+
+ byte[] two = new byte[32];
+
+ DataWord x = new DataWord(one);
+ DataWord y = new DataWord(two);
+ x.div(y);
+
+ assertEquals(32, x.getData().length);
+ assertTrue(x.isZero());
+ }
+
+ @Test
+ public void testSDivNegative() {
+
+ // one is -300 as 256-bit signed integer:
+ byte[] one = Hex.decode("fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffed4");
+
+ byte[] two = new byte[32];
+ two[31] = 0x0f;
+
+ DataWord x = new DataWord(one);
+ DataWord y = new DataWord(two);
+ x.sDiv(y);
+
+ assertEquals(32, x.getData().length);
+ assertEquals("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec", x.toString());
+ }
+
+ @Test
+ public void testPow() {
+
+ BigInteger x = BigInteger.valueOf(Integer.MAX_VALUE);
+ BigInteger y = BigInteger.valueOf(1000);
+
+ BigInteger result1 = x.modPow(x, y);
+ BigInteger result2 = pow(x, y);
+ System.out.println(result1);
+ System.out.println(result2);
+ }
+
+ @Test
+ public void testSignExtend1() {
+
+ DataWord x = new DataWord(Hex.decode("f2"));
+ byte k = 0;
+ String expected = "fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2";
+
+ x.signExtend(k);
+ System.out.println(x.toString());
+ assertEquals(expected, x.toString());
+ }
+
+ @Test
+ public void testSignExtend2() {
+ DataWord x = new DataWord(Hex.decode("f2"));
+ byte k = 1;
+ String expected = "00000000000000000000000000000000000000000000000000000000000000f2";
+
+ x.signExtend(k);
+ System.out.println(x.toString());
+ assertEquals(expected, x.toString());
+ }
+
+ @Test
+ public void testSignExtend3() {
+
+ byte k = 1;
+ DataWord x = new DataWord(Hex.decode("0f00ab"));
+ String expected = "00000000000000000000000000000000000000000000000000000000000000ab";
+
+ x.signExtend(k);
+ System.out.println(x.toString());
+ assertEquals(expected, x.toString());
+ }
+
+ @Test
+ public void testSignExtend4() {
+
+ byte k = 1;
+ DataWord x = new DataWord(Hex.decode("ffff"));
+ String expected = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
+
+ x.signExtend(k);
+ System.out.println(x.toString());
+ assertEquals(expected, x.toString());
+ }
+
+ @Test
+ public void testSignExtend5() {
+
+ byte k = 3;
+ DataWord x = new DataWord(Hex.decode("ffffffff"));
+ String expected = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff";
+
+ x.signExtend(k);
+ System.out.println(x.toString());
+ assertEquals(expected, x.toString());
+ }
+
+ @Test
+ public void testSignExtend6() {
+
+ byte k = 3;
+ DataWord x = new DataWord(Hex.decode("ab02345678"));
+ String expected = "0000000000000000000000000000000000000000000000000000000002345678";
+
+ x.signExtend(k);
+ System.out.println(x.toString());
+ assertEquals(expected, x.toString());
+ }
+
+ @Test
+ public void testSignExtend7() {
+
+ byte k = 3;
+ DataWord x = new DataWord(Hex.decode("ab82345678"));
+ String expected = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffff82345678";
+
+ x.signExtend(k);
+ System.out.println(x.toString());
+ assertEquals(expected, x.toString());
+ }
+
+ @Test
+ public void testSignExtend8() {
+
+ byte k = 30;
+ DataWord x = new DataWord(Hex.decode("ff34567882345678823456788234567882345678823456788234567882345678"));
+ String expected = "0034567882345678823456788234567882345678823456788234567882345678";
+
+ x.signExtend(k);
+ System.out.println(x.toString());
+ assertEquals(expected, x.toString());
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testSignExtendException1() {
+
+ byte k = -1;
+ DataWord x = new DataWord();
+
+ x.signExtend(k); // should throw an exception
+ }
+
+ @Test(expected = IndexOutOfBoundsException.class)
+ public void testSignExtendException2() {
+
+ byte k = 32;
+ DataWord x = new DataWord();
+
+ x.signExtend(k); // should throw an exception
+ }
+
+ @Test
+ public void testAddModOverflow() {
+ testAddMod("9999999999999999999999999999999999999999999999999999999999999999",
+ "8888888888888888888888888888888888888888888888888888888888888888",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ testAddMod("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
+ }
+
+ private void testAddMod(String v1, String v2, String v3) {
+ DataWord dv1 = new DataWord(Hex.decode(v1));
+ DataWord dv2 = new DataWord(Hex.decode(v2));
+ DataWord dv3 = new DataWord(Hex.decode(v3));
+ BigInteger bv1 = new BigInteger(v1, 16);
+ BigInteger bv2 = new BigInteger(v2, 16);
+ BigInteger bv3 = new BigInteger(v3, 16);
+
+ dv1.addmod(dv2, dv3);
+ BigInteger br = bv1.add(bv2).mod(bv3);
+ assertEquals(dv1.value(), br);
+ }
+
+ @Test
+ public void testMulMod1() {
+ DataWord wr = new DataWord(Hex.decode("9999999999999999999999999999999999999999999999999999999999999999"));
+ DataWord w1 = new DataWord(Hex.decode("01"));
+ DataWord w2 = new DataWord(Hex.decode("9999999999999999999999999999999999999999999999999999999999999998"));
+
+ wr.mulmod(w1, w2);
+
+ assertEquals(32, wr.getData().length);
+ assertEquals("0000000000000000000000000000000000000000000000000000000000000001", Hex.toHexString(wr.getData()));
+ }
+
+ @Test
+ public void testMulMod2() {
+ DataWord wr = new DataWord(Hex.decode("9999999999999999999999999999999999999999999999999999999999999999"));
+ DataWord w1 = new DataWord(Hex.decode("01"));
+ DataWord w2 = new DataWord(Hex.decode("9999999999999999999999999999999999999999999999999999999999999999"));
+
+ wr.mulmod(w1, w2);
+
+ assertEquals(32, wr.getData().length);
+ assertTrue(wr.isZero());
+ }
+
+ @Test
+ public void testMulModZero() {
+ DataWord wr = new DataWord(Hex.decode("00"));
+ DataWord w1 = new DataWord(Hex.decode("9999999999999999999999999999999999999999999999999999999999999999"));
+ DataWord w2 = new DataWord(Hex.decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
+
+ wr.mulmod(w1, w2);
+
+ assertEquals(32, wr.getData().length);
+ assertTrue(wr.isZero());
+ }
+
+ @Test
+ public void testMulModZeroWord1() {
+ DataWord wr = new DataWord(Hex.decode("9999999999999999999999999999999999999999999999999999999999999999"));
+ DataWord w1 = new DataWord(Hex.decode("00"));
+ DataWord w2 = new DataWord(Hex.decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
+
+ wr.mulmod(w1, w2);
+
+ assertEquals(32, wr.getData().length);
+ assertTrue(wr.isZero());
+ }
+
+ @Test
+ public void testMulModZeroWord2() {
+ DataWord wr = new DataWord(Hex.decode("9999999999999999999999999999999999999999999999999999999999999999"));
+ DataWord w1 = new DataWord(Hex.decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
+ DataWord w2 = new DataWord(Hex.decode("00"));
+
+ wr.mulmod(w1, w2);
+
+ assertEquals(32, wr.getData().length);
+ assertTrue(wr.isZero());
+ }
+
+ @Test
+ public void testMulModOverflow() {
+ DataWord wr = new DataWord(Hex.decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
+ DataWord w1 = new DataWord(Hex.decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
+ DataWord w2 = new DataWord(Hex.decode("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"));
+
+ wr.mulmod(w1, w2);
+
+ assertEquals(32, wr.getData().length);
+ assertTrue(wr.isZero());
+ }
+
+ private static BigInteger pow(BigInteger x, BigInteger y) {
+ if (y.compareTo(BigInteger.ZERO) < 0)
+ throw new IllegalArgumentException();
+ BigInteger z = x; // z will successively become x^2, x^4, x^8, x^16,
+ // x^32...
+ BigInteger result = BigInteger.ONE;
+ byte[] bytes = y.toByteArray();
+ for (int i = bytes.length - 1; i >= 0; i--) {
+ byte bits = bytes[i];
+ for (int j = 0; j < 8; j++) {
+ if ((bits & 1) != 0)
+ result = result.multiply(z);
+ // short cut out if there are no more bits to handle:
+ if ((bits >>= 1) == 0 && i == 0)
+ return result;
+ z = z.multiply(z);
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/test/java/org/tron/common/runtime/vm/InternalTransactionCallTest.java b/src/test/java/org/tron/common/runtime/vm/InternalTransactionCallTest.java
new file mode 100644
index 00000000000..0c333ce4d56
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/vm/InternalTransactionCallTest.java
@@ -0,0 +1,309 @@
+package org.tron.common.runtime.vm;
+
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.spongycastle.util.encoders.Hex;
+import org.tron.common.application.TronApplicationContext;
+import org.testng.Assert;
+import org.tron.common.runtime.Runtime;
+import org.tron.common.runtime.TVMTestUtils;
+import org.tron.common.storage.DepositImpl;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.TransactionTraceException;
+import org.tron.protos.Protocol.AccountType;
+
+@Slf4j
+public class InternalTransactionCallTest {
+ private Runtime runtime;
+ private Manager dbManager;
+ private TronApplicationContext context;
+ private DepositImpl deposit;
+ private String dbPath = "output_InternalTransactionCallTest";
+ private String OWNER_ADDRESS;
+
+
+ /**
+ * Init data.
+ */
+ @Before
+ public void init() {
+ Args.setParam(new String[]{"--output-directory", dbPath, "--debug"}, Constant.TEST_CONF);
+ context = new TronApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
+ dbManager = context.getBean(Manager.class);
+ deposit = DepositImpl.createRoot(dbManager);
+ deposit.createAccount(Hex.decode(OWNER_ADDRESS),AccountType.Normal);
+ deposit.addBalance(Hex.decode(OWNER_ADDRESS),100000000);
+ }
+
+
+ /**
+ * contract A {
+ * uint256 public numberForB;
+ * address public senderForB;
+ * function callTest(address bAddress, uint256 _number) {
+ * bAddress.call(bytes4(sha3("setValue(uint256)")), _number); // B's storage is set, A is not modified
+ * }
+ *
+ * function callcodeTest(address bAddress, uint256 _number) {
+ * bAddress.callcode(bytes4(sha3("setValue(uint256)")), _number); // A's storage is set, B is not modified
+ * }
+ *
+ * function delegatecallTest(address bAddress, uint256 _number) {
+ * bAddress.delegatecall(bytes4(sha3("setValue(uint256)")), _number); // A's storage is set, B is not modified
+ * }
+ * }
+ *
+ * contract B {
+ * uint256 public numberForB;
+ * address public senderForB;
+ *
+ * function setValue(uint256 _number) {
+ * numberForB = _number;
+ * senderForB = msg.sender;
+ * // senderForB is A if invoked by A's callTest. B's storage will be updated
+ * // senderForB is A if invoked by A's callcodeTest. None of B's storage is updated
+ * // senderForB is OWNER if invoked by A's delegatecallTest. None of B's storage is updated
+ * }
+ * }
+ */
+
+
+ /*
+ A call B, anything belongs to A should not be changed, B should be changed.
+ msg.sender for contractB should be A's address.
+ */
+
+
+ @Test
+ public void callTest()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ byte[] contractBAddress = deployBContractAndGetItsAddress();
+ byte[] contractAAddress =deployAContractandGetItsAddress();
+
+ /* =================================== CALL callTest() to change B storage =================================== */
+ String params = Hex.toHexString(new DataWord(new DataWord(contractBAddress).getLast20Bytes()).getData()) + "0000000000000000000000000000000000000000000000000000000000000003";
+ byte[] triggerData = TVMTestUtils.parseABI("callTest(address,uint256)",params);
+ TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractAAddress,triggerData,
+ 0,1000000000,deposit,null);
+
+ /* =================================== CALL numberForB() to check A's numberForB =================================== */
+ byte[] triggerData2 = TVMTestUtils.parseABI("numberForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractAAddress,triggerData2,
+ 0,1000000000,deposit,null);
+ // A should not be changed
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),"0000000000000000000000000000000000000000000000000000000000000000");
+
+ /* =================================== CALL senderForB() to check A's senderForB =================================== */
+ byte[] triggerData3 = TVMTestUtils.parseABI("senderForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractAAddress,triggerData3,
+ 0,1000000000,deposit,null);
+ // A should be changed
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),"0000000000000000000000000000000000000000000000000000000000000000");
+
+ /* =================================== CALL numberForB() to check B's numberForB =================================== */
+ byte[] triggerData4 = TVMTestUtils.parseABI("numberForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractBAddress,triggerData4,
+ 0,1000000000,deposit,null);
+ // B's numberForB should be changed to 3
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),"0000000000000000000000000000000000000000000000000000000000000003");
+
+ /* =================================== CALL senderForB() to check B's senderForB =================================== */
+ byte[] triggerData5 = TVMTestUtils.parseABI("senderForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractBAddress,triggerData5,
+ 0,1000000000,deposit,null);
+ // B 's senderForB should be A
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),Hex.toHexString(new DataWord(new DataWord(contractAAddress).getLast20Bytes()).getData()));
+ }
+
+ /*
+ A delegatecall B, A should be changed, anything belongs to B should not be changed.
+ msg.sender for contractB should be Caller(OWNER_ADDRESS), but this value will not be effected in B's senderForB since we use delegatecall.
+ We store it in A's senderForB.
+ */
+ @Test
+ public void delegateCallTest()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ byte[] contractBAddress = deployBContractAndGetItsAddress();
+ byte[] contractAAddress =deployAContractandGetItsAddress();
+ /* =================================== CALL delegatecallTest() to change B storage =================================== */
+ String params = Hex.toHexString(new DataWord(new DataWord(contractBAddress).getLast20Bytes()).getData()) + "0000000000000000000000000000000000000000000000000000000000000003";
+ byte[] triggerData = TVMTestUtils.parseABI("delegatecallTest(address,uint256)",params);
+ TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractAAddress,triggerData,
+ 0,1000000000,deposit,null);
+
+ /* =================================== CALL numberForB() to check A's numberForB =================================== */
+ byte[] triggerData2 = TVMTestUtils.parseABI("numberForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractAAddress,triggerData2,
+ 0,1000000000,deposit,null);
+ // A should be changed to 3
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),"0000000000000000000000000000000000000000000000000000000000000003");
+
+ /* =================================== CALL senderForB() to check A's senderForB =================================== */
+ byte[] triggerData3 = TVMTestUtils.parseABI("senderForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractAAddress,triggerData3,
+ 0,1000000000,deposit,null);
+ // A's senderForB should be changed to caller's contract Address (OWNER_ADDRESS)
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),Hex.toHexString(new DataWord(new DataWord(OWNER_ADDRESS).getLast20Bytes()).getData()));
+
+ /* =================================== CALL numberForB() to check B's numberForB =================================== */
+ byte[] triggerData4 = TVMTestUtils.parseABI("numberForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractBAddress,triggerData4,
+ 0,1000000000,deposit,null);
+ // B's numberForB should not be changed
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),"0000000000000000000000000000000000000000000000000000000000000000");
+
+ /* =================================== CALL senderForB() to check B's senderForB =================================== */
+ byte[] triggerData5 = TVMTestUtils.parseABI("senderForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractBAddress,triggerData5,
+ 0,1000000000,deposit,null);
+ // B 's senderForB should not be changed
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),"0000000000000000000000000000000000000000000000000000000000000000");
+
+ }
+
+ /*
+ A callcode B, A should be changed, anything belongs to B should not be changed.
+ msg.sender for contractB should be A, but this value will not be effected in B's senderForB since we use callcode.
+ We store it in A's senderForB.
+ */
+ @Test
+ public void callCodeTest()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ byte[] contractBAddress = deployBContractAndGetItsAddress();
+ byte[] contractAAddress =deployAContractandGetItsAddress();
+ /* =================================== CALL callcodeTest() to change B storage =================================== */
+ String params = Hex.toHexString(new DataWord(new DataWord(contractBAddress).getLast20Bytes()).getData()) + "0000000000000000000000000000000000000000000000000000000000000003";
+ byte[] triggerData = TVMTestUtils.parseABI("callcodeTest(address,uint256)",params);
+ TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractAAddress,triggerData,
+ 0,1000000000,deposit,null);
+
+ /* =================================== CALL numberForB() to check A's numberForB =================================== */
+ byte[] triggerData2 = TVMTestUtils.parseABI("numberForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractAAddress,triggerData2,
+ 0,1000000000,deposit,null);
+ // A should be changed to 3
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),"0000000000000000000000000000000000000000000000000000000000000003");
+
+ /* =================================== CALL senderForB() to check A's senderForB =================================== */
+ byte[] triggerData3 = TVMTestUtils.parseABI("senderForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractAAddress,triggerData3,
+ 0,1000000000,deposit,null);
+ // A's senderForB should be changed to A's contract Address
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),Hex.toHexString(new DataWord(new DataWord(contractAAddress).getLast20Bytes()).getData()));
+
+ /* =================================== CALL numberForB() to check B's numberForB =================================== */
+ byte[] triggerData4 = TVMTestUtils.parseABI("numberForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractBAddress,triggerData4,
+ 0,1000000000,deposit,null);
+ // B's numberForB should not be changed
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),"0000000000000000000000000000000000000000000000000000000000000000");
+
+ /* =================================== CALL senderForB() to check B's senderForB =================================== */
+ byte[] triggerData5 = TVMTestUtils.parseABI("senderForB()","");
+ runtime = TVMTestUtils.triggerContractWholeProcessReturnContractAddress(Hex.decode(OWNER_ADDRESS),contractBAddress,triggerData5,
+ 0,1000000000,deposit,null);
+ // B 's senderForB should not be changed
+ Assert.assertEquals(Hex.toHexString(runtime.getResult().getHReturn()),"0000000000000000000000000000000000000000000000000000000000000000");
+ }
+
+ @Test
+ public void staticCallTest(){
+ //TODO: need to implement this
+ }
+
+
+ // Just for the AB example above
+ public byte[] deployAContractandGetItsAddress()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ String contractName = "AContract";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"bAddress\",\"type\":\"address\"},{\"name\":\"_number\",\"type\":\"uint256\"}],"
+ + "\"name\":\"delegatecallTest\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant"
+ + "\":false,\"inputs\":[{\"name\":\"bAddress\",\"type\":\"address\"},{\"name\":\"_number\",\"type\":\"uint256\"}],\"name\":\"callTest\","
+ + "\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":"
+ + "\"senderForB\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":"
+ + "\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"bAddress\",\"type\":\"address\"},{\"name\":\"_number\",\"type\":\"uint256\"}],"
+ + "\"name\":\"callcodeTest\",\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,"
+ + "\"inputs\":[],\"name\":\"numberForB\",\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\","
+ + "\"type\":\"function\"}]";
+ String code = "608060405234801561001057600080fd5b506102d4806100206000396000f3006080604052600436106100535763ffffffff60e060020a6000350"
+ + "416633da5d187811461005857806343c3a43a1461007e578063b053ebd4146100a2578063d7d21f5b146100d3578063dd92afef146100f7575b600080fd5b"
+ + "34801561006457600080fd5b5061007c600160a060020a036004351660243561011e565b005b34801561008a57600080fd5b5061007c600160a060020a036"
+ + "0043516602435610199565b3480156100ae57600080fd5b506100b7610216565b60408051600160a060020a039092168252519081900360200190f35b3480"
+ + "156100df57600080fd5b5061007c600160a060020a0360043516602435610225565b34801561010357600080fd5b5061010c6102a2565b604080519182525"
+ + "19081900360200190f35b81600160a060020a031660405180807f73657456616c75652875696e743235362900000000000000000000000000000081525060"
+ + "11019050604051809103902060e060020a9004826040518263ffffffff1660e060020a02815260040180828152602001915050600060405180830381865af4"
+ + "505050505050565b81600160a060020a031660405180807f73657456616c75652875696e743235362900000000000000000000000000000081525060110190"
+ + "50604051809103902060e060020a9004826040518263ffffffff1660e060020a028152600401808281526020019150506000604051808303816000875af150"
+ + "5050505050565b600154600160a060020a031681565b81600160a060020a031660405180807f73657456616c75652875696e74323536290000000000000000"
+ + "000000000000008152506011019050604051809103902060e060020a9004826040518263ffffffff1660e060020a0281526004018082815260200191505060"
+ + "00604051808303816000875af2505050505050565b600054815600a165627a7a723058206d36ef7c6f6d387ad915f299e715c9b360f3719843a1113badb28b"
+ + "6595e66c1e0029";
+ long value = 0;
+ long feeLimit = 1000000000;
+ long consumeUserResourcePercent = 0;
+ String libraryAddressPair=null;
+
+ byte[] contractAddress = TVMTestUtils
+ .deployContractWholeProcessReturnContractAddress(contractName,address,ABI,code,value,feeLimit,consumeUserResourcePercent,libraryAddressPair,
+ deposit,null);
+ return contractAddress;
+ }
+
+ // Just for the AB example above
+ public byte[] deployBContractAndGetItsAddress()
+ throws ContractExeException, OutOfSlotTimeException, TransactionTraceException, ContractValidateException {
+ String contractName = "BContract";
+ byte[] address = Hex.decode(OWNER_ADDRESS);
+ String ABI = "[{\"constant\":false,\"inputs\":[{\"name\":\"_number\",\"type\":\"uint256\"}],\"name\":\"setValue\","
+ + "\"outputs\":[],\"payable\":false,\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"constant\":true,"
+ + "\"inputs\":[],\"name\":\"senderForB\",\"outputs\":[{\"name\":\"\",\"type\":\"address\"}],\"payable\":false,"
+ + "\"stateMutability\":\"view\",\"type\":\"function\"},{\"constant\":true,\"inputs\":[],\"name\":\"numberForB\","
+ + "\"outputs\":[{\"name\":\"\",\"type\":\"uint256\"}],\"payable\":false,\"stateMutability\":\"view\",\"type\":"
+ + "\"function\"}]";
+ String code = "608060405234801561001057600080fd5b5061014c806100206000396000f3006080604052600436106100565763ffffffff7"
+ + "c010000000000000000000000000000000000000000000000000000000060003504166355241077811461005b578063b053ebd4146100"
+ + "75578063dd92afef146100b3575b600080fd5b34801561006757600080fd5b506100736004356100da565b005b34801561008157600080"
+ + "fd5b5061008a6100fe565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b348015"
+ + "6100bf57600080fd5b506100c861011a565b60408051918252519081900360200190f35b6000556001805473ffffffffffffffffffffff"
+ + "ffffffffffffffffff191633179055565b60015473ffffffffffffffffffffffffffffffffffffffff1681565b600054815600a165627a7"
+ + "a72305820e2c513cf46bb32018879ec48f8fe264c985b6d2c7a853a578f4f56583fe1ffb80029";
+ long value = 0;
+ long feeLimit = 1000000000;
+ long consumeUserResourcePercent = 0;
+ String libraryAddressPair=null;
+
+ byte[] contractAddress = TVMTestUtils.deployContractWholeProcessReturnContractAddress(contractName,address,ABI,code,value,feeLimit,consumeUserResourcePercent,libraryAddressPair,
+ deposit,null);
+ return contractAddress;
+ }
+
+
+ /**
+ * Release resources.
+ */
+ @After
+ public void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+}
diff --git a/src/test/java/org/tron/common/runtime/vm/InterpreterTest.java b/src/test/java/org/tron/common/runtime/vm/InterpreterTest.java
new file mode 100644
index 00000000000..67b5419276c
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/vm/InterpreterTest.java
@@ -0,0 +1,59 @@
+/*
+ * java-tron is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * java-tron is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.tron.common.runtime.vm;
+
+import static org.junit.Assert.assertTrue;
+
+import lombok.extern.slf4j.Slf4j;
+import org.junit.Test;
+import java.io.*;
+import org.tron.protos.Protocol.Transaction;
+import org.tron.common.runtime.vm.program.InternalTransaction;
+import org.tron.common.runtime.vm.VM;
+import org.tron.common.runtime.vm.program.Program;
+import org.tron.common.runtime.vm.program.invoke.ProgramInvokeMockImpl;
+
+@Slf4j
+public class InterpreterTest {
+
+ private ProgramInvokeMockImpl invoke;
+ private Program program;
+
+ @Test
+ public void testVMException() {
+ VM vm = new VM();
+ invoke = new ProgramInvokeMockImpl();
+ byte[] op = { 0x5b, 0x60, 0x00, 0x56 };
+ // 0x5b - JUMPTEST
+ // 0x60 0x00 - PUSH 0x00
+ // 0x56 - JUMP to 0
+ Transaction trx = Transaction.getDefaultInstance();
+ InternalTransaction interTrx = new InternalTransaction(trx);
+ program = new Program(op, invoke, interTrx);
+
+ boolean result = false;
+
+ try {
+ while (!program.isStopped()) {
+ vm.step(program);
+ }
+ } catch (Exception e) {
+ result = true;
+ }
+
+ assertTrue(result);
+ }
+}
diff --git a/src/test/java/org/tron/common/runtime/vm/MemoryTest.java b/src/test/java/org/tron/common/runtime/vm/MemoryTest.java
new file mode 100644
index 00000000000..a161515e86a
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/vm/MemoryTest.java
@@ -0,0 +1,534 @@
+/*
+ * Copyright (c) [2016] [ ]
+ * This file is part of the ethereumJ library.
+ *
+ * The ethereumJ library is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * The ethereumJ library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with the ethereumJ library. If not, see .
+ */
+package org.tron.common.runtime.vm;
+
+import static java.lang.Math.ceil;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import lombok.extern.slf4j.Slf4j;
+import org.testng.Assert;
+import org.tron.common.runtime.vm.program.Memory;
+import org.junit.Test;
+import org.spongycastle.util.encoders.Hex;
+
+@Slf4j
+public class MemoryTest {
+
+ private static final int WORD_SIZE = 32;
+ private static final int CHUNK_SIZE = 1024;
+
+ @Test
+ public void testExtend() {
+ checkMemoryExtend(0);
+ checkMemoryExtend(1);
+ checkMemoryExtend(WORD_SIZE);
+ checkMemoryExtend(WORD_SIZE * 2);
+ checkMemoryExtend(CHUNK_SIZE - 1);
+ checkMemoryExtend(CHUNK_SIZE);
+ checkMemoryExtend(CHUNK_SIZE + 1);
+ checkMemoryExtend(2000);
+ }
+
+ private static void checkMemoryExtend(int dataSize) {
+ Memory memory = new Memory();
+ memory.extend(0, dataSize);
+ Assert.assertEquals(calcSize(dataSize, CHUNK_SIZE), memory.internalSize());
+ Assert.assertEquals(calcSize(dataSize, WORD_SIZE), memory.size());
+ }
+
+ private static int calcSize(int dataSize, int chunkSize) {
+ return (int) ceil((double) dataSize / chunkSize) * chunkSize;
+ }
+
+ @Test
+ public void memorySave_1() {
+
+ Memory memoryBuffer = new Memory();
+ byte[] data = {1, 1, 1, 1};
+
+ memoryBuffer.write(0, data, data.length, false);
+
+ assertTrue(1 == memoryBuffer.getChunks().size());
+
+ byte[] chunk = memoryBuffer.getChunks().get(0);
+ assertTrue(chunk[0] == 1);
+ assertTrue(chunk[1] == 1);
+ assertTrue(chunk[2] == 1);
+ assertTrue(chunk[3] == 1);
+ assertTrue(chunk[4] == 0);
+
+ assertTrue(memoryBuffer.size() == 32);
+ }
+
+ @Test
+ public void memorySave_2() {
+
+ Memory memoryBuffer = new Memory();
+ byte[] data = Hex.decode("0101010101010101010101010101010101010101010101010101010101010101");
+
+ memoryBuffer.write(0, data, data.length, false);
+
+ assertTrue(1 == memoryBuffer.getChunks().size());
+
+ byte[] chunk = memoryBuffer.getChunks().get(0);
+ assertTrue(chunk[0] == 1);
+ assertTrue(chunk[1] == 1);
+
+ assertTrue(chunk[30] == 1);
+ assertTrue(chunk[31] == 1);
+ assertTrue(chunk[32] == 0);
+
+ assertTrue(memoryBuffer.size() == 32);
+ }
+
+ @Test
+ public void memorySave_3() {
+
+ Memory memoryBuffer = new Memory();
+ byte[] data = Hex.decode("010101010101010101010101010101010101010101010101010101010101010101");
+
+ memoryBuffer.write(0, data, data.length, false);
+
+ assertTrue(1 == memoryBuffer.getChunks().size());
+
+ byte[] chunk = memoryBuffer.getChunks().get(0);
+ assertTrue(chunk[0] == 1);
+ assertTrue(chunk[1] == 1);
+
+ assertTrue(chunk[30] == 1);
+ assertTrue(chunk[31] == 1);
+ assertTrue(chunk[32] == 1);
+ assertTrue(chunk[33] == 0);
+
+ assertTrue(memoryBuffer.size() == 64);
+ }
+
+ @Test
+ public void memorySave_4() {
+
+ Memory memoryBuffer = new Memory();
+ byte[] data = new byte[1024];
+ Arrays.fill(data, (byte) 1);
+
+ memoryBuffer.write(0, data, data.length, false);
+
+ assertTrue(1 == memoryBuffer.getChunks().size());
+
+ byte[] chunk = memoryBuffer.getChunks().get(0);
+ assertTrue(chunk[0] == 1);
+ assertTrue(chunk[1] == 1);
+
+ assertTrue(chunk[1022] == 1);
+ assertTrue(chunk[1023] == 1);
+
+ assertTrue(memoryBuffer.size() == 1024);
+ }
+
+ @Test
+ public void memorySave_5() {
+
+ Memory memoryBuffer = new Memory();
+
+ byte[] data = new byte[1025];
+ Arrays.fill(data, (byte) 1);
+
+ memoryBuffer.write(0, data, data.length, false);
+
+ assertTrue(2 == memoryBuffer.getChunks().size());
+
+ byte[] chunk1 = memoryBuffer.getChunks().get(0);
+ assertTrue(chunk1[0] == 1);
+ assertTrue(chunk1[1] == 1);
+
+ assertTrue(chunk1[1022] == 1);
+ assertTrue(chunk1[1023] == 1);
+
+ byte[] chunk2 = memoryBuffer.getChunks().get(1);
+ assertTrue(chunk2[0] == 1);
+ assertTrue(chunk2[1] == 0);
+
+ assertTrue(memoryBuffer.size() == 1056);
+ }
+
+ @Test
+ public void memorySave_6() {
+
+ Memory memoryBuffer = new Memory();
+
+ byte[] data1 = new byte[1024];
+ Arrays.fill(data1, (byte) 1);
+
+ byte[] data2 = new byte[1024];
+ Arrays.fill(data2, (byte) 2);
+
+ memoryBuffer.write(0, data1, data1.length, false);
+ memoryBuffer.write(1024, data2, data2.length, false);
+
+ assertTrue(2 == memoryBuffer.getChunks().size());
+
+ byte[] chunk1 = memoryBuffer.getChunks().get(0);
+ assertTrue(chunk1[0] == 1);
+ assertTrue(chunk1[1] == 1);
+
+ assertTrue(chunk1[1022] == 1);
+ assertTrue(chunk1[1023] == 1);
+
+ byte[] chunk2 = memoryBuffer.getChunks().get(1);
+ assertTrue(chunk2[0] == 2);
+ assertTrue(chunk2[1] == 2);
+
+ assertTrue(chunk2[1022] == 2);
+ assertTrue(chunk2[1023] == 2);
+
+ assertTrue(memoryBuffer.size() == 2048);
+ }
+
+ @Test
+ public void memorySave_7() {
+
+ Memory memoryBuffer = new Memory();
+
+ byte[] data1 = new byte[1024];
+ Arrays.fill(data1, (byte) 1);
+
+ byte[] data2 = new byte[1024];
+ Arrays.fill(data2, (byte) 2);
+
+ byte[] data3 = new byte[1];
+ Arrays.fill(data3, (byte) 3);
+
+ memoryBuffer.write(0, data1, data1.length, false);
+ memoryBuffer.write(1024, data2, data2.length, false);
+ memoryBuffer.write(2048, data3, data3.length, false);
+
+ assertTrue(3 == memoryBuffer.getChunks().size());
+
+ byte[] chunk1 = memoryBuffer.getChunks().get(0);
+ assertTrue(chunk1[0] == 1);
+ assertTrue(chunk1[1] == 1);
+
+ assertTrue(chunk1[1022] == 1);
+ assertTrue(chunk1[1023] == 1);
+
+ byte[] chunk2 = memoryBuffer.getChunks().get(1);
+ assertTrue(chunk2[0] == 2);
+ assertTrue(chunk2[1] == 2);
+
+ assertTrue(chunk2[1022] == 2);
+ assertTrue(chunk2[1023] == 2);
+
+ byte[] chunk3 = memoryBuffer.getChunks().get(2);
+ assertTrue(chunk3[0] == 3);
+
+ assertTrue(memoryBuffer.size() == 2080);
+ }
+
+ @Test
+ public void memorySave_8() {
+
+ Memory memoryBuffer = new Memory();
+
+ byte[] data1 = new byte[128];
+ Arrays.fill(data1, (byte) 1);
+
+ memoryBuffer.extendAndWrite(0, 256, data1);
+
+ int ones = 0; int zeroes = 0;
+ for (int i = 0; i < memoryBuffer.size(); ++i){
+ if (memoryBuffer.readByte(i) == 1) ++ones;
+ if (memoryBuffer.readByte(i) == 0) ++zeroes;
+ }
+
+ assertTrue(ones == zeroes);
+ assertTrue(256 == memoryBuffer.size());
+ }
+
+
+
+ @Test
+ public void memoryLoad_1() {
+
+ Memory memoryBuffer = new Memory();
+ DataWord value = memoryBuffer.readWord(100);
+ assertTrue(value.intValue() == 0);
+ assertTrue(memoryBuffer.getChunks().size() == 1);
+ assertTrue(memoryBuffer.size() == 32 * 5);
+ }
+
+ @Test
+ public void memoryLoad_2() {
+
+ Memory memoryBuffer = new Memory();
+ DataWord value = memoryBuffer.readWord(2015);
+ assertTrue(value.intValue() == 0);
+ assertTrue(memoryBuffer.getChunks().size() == 2);
+ assertTrue(memoryBuffer.size() == 2048);
+ }
+
+ @Test
+ public void memoryLoad_3() {
+
+ Memory memoryBuffer = new Memory();
+ DataWord value = memoryBuffer.readWord(2016);
+ assertTrue(value.intValue() == 0);
+ assertTrue(memoryBuffer.getChunks().size() == 2);
+ assertTrue(memoryBuffer.size() == 2048);
+ }
+
+ @Test
+ public void memoryLoad_4() {
+
+ Memory memoryBuffer = new Memory();
+ DataWord value = memoryBuffer.readWord(2017);
+ assertTrue(value.intValue() == 0);
+ assertTrue(memoryBuffer.getChunks().size() == 3);
+ assertTrue(memoryBuffer.size() == 2080);
+ }
+
+ @Test
+ public void memoryLoad_5() {
+
+ Memory memoryBuffer = new Memory();
+
+ byte[] data1 = new byte[1024];
+ Arrays.fill(data1, (byte) 1);
+
+ byte[] data2 = new byte[1024];
+ Arrays.fill(data2, (byte) 2);
+
+ memoryBuffer.write(0, data1, data1.length, false);
+ memoryBuffer.write(1024, data2, data2.length, false);
+
+ assertTrue(memoryBuffer.getChunks().size() == 2);
+ assertTrue(memoryBuffer.size() == 2048);
+
+ DataWord val1 = memoryBuffer.readWord(0x3df);
+ DataWord val2 = memoryBuffer.readWord(0x3e0);
+ DataWord val3 = memoryBuffer.readWord(0x3e1);
+
+ assertArrayEquals(
+ Hex.decode("0101010101010101010101010101010101010101010101010101010101010101"),
+ val1.getData());
+
+ assertArrayEquals(
+ Hex.decode("0101010101010101010101010101010101010101010101010101010101010101"),
+ val2.getData());
+
+ assertArrayEquals(
+ Hex.decode("0101010101010101010101010101010101010101010101010101010101010102"),
+ val3.getData());
+ assertTrue(memoryBuffer.size() == 2048);
+ }
+
+
+ @Test
+ public void memoryChunk_1(){
+ Memory memoryBuffer = new Memory();
+
+ byte[] data1 = new byte[32];
+ Arrays.fill(data1, (byte) 1);
+
+ byte[] data2 = new byte[32];
+ Arrays.fill(data2, (byte) 2);
+
+ memoryBuffer.write(0, data1, data1.length, false);
+ memoryBuffer.write(32, data2, data2.length, false);
+
+ byte[] data = memoryBuffer.read(0, 64);
+
+ assertArrayEquals(
+ Hex.decode("0101010101010101010101010101010101010101010101010101010101010101" +
+ "0202020202020202020202020202020202020202020202020202020202020202"),
+ data
+ );
+
+ Assert.assertEquals(64, memoryBuffer.size());
+ }
+
+
+ @Test
+ public void memoryChunk_2(){
+ Memory memoryBuffer = new Memory();
+
+ byte[] data1 = new byte[32];
+ Arrays.fill(data1, (byte) 1);
+
+ memoryBuffer.write(0, data1, data1.length, false);
+ assertTrue(32 == memoryBuffer.size());
+
+ byte[] data = memoryBuffer.read(0, 64);
+
+ assertArrayEquals(
+ Hex.decode("0101010101010101010101010101010101010101010101010101010101010101" +
+ "0000000000000000000000000000000000000000000000000000000000000000"),
+ data
+ );
+
+ Assert.assertEquals(64, memoryBuffer.size());
+ }
+
+ @Test
+ public void memoryChunk_3(){
+
+ Memory memoryBuffer = new Memory();
+
+ byte[] data1 = new byte[1024];
+ Arrays.fill(data1, (byte) 1);
+
+ byte[] data2 = new byte[1024];
+ Arrays.fill(data2, (byte) 2);
+
+ memoryBuffer.write(0, data1, data1.length, false);
+ memoryBuffer.write(1024, data2, data2.length, false);
+
+ byte[] data = memoryBuffer.read(0, 2048);
+
+ int ones = 0; int twos = 0;
+ for (int i = 0; i < data.length; ++i){
+ if (data[i] == 1) ++ones;
+ if (data[i] == 2) ++twos;
+ }
+
+ assertTrue(ones == twos);
+ assertTrue(2048 == memoryBuffer.size());
+ }
+
+ @Test
+ public void memoryChunk_4(){
+
+ Memory memoryBuffer = new Memory();
+
+ byte[] data1 = new byte[1024];
+ Arrays.fill(data1, (byte) 1);
+
+ byte[] data2 = new byte[1024];
+ Arrays.fill(data2, (byte) 2);
+
+ memoryBuffer.write(0, data1, data1.length, false);
+ memoryBuffer.write(1024, data2, data2.length, false);
+
+ byte[] data = memoryBuffer.read(0, 2049);
+
+ int ones = 0; int twos = 0; int zero = 0;
+ for (int i = 0; i < data.length; ++i){
+ if (data[i] == 1) ++ones;
+ if (data[i] == 2) ++twos;
+ if (data[i] == 0) ++zero;
+ }
+
+ assertTrue(zero == 1);
+ assertTrue(ones == twos);
+ assertTrue(2080 == memoryBuffer.size());
+ }
+
+
+ @Test
+ public void memoryWriteLimited_1(){
+
+ Memory memoryBuffer = new Memory();
+ memoryBuffer.extend(0, 3072);
+
+ byte[] data1 = new byte[6272];
+ Arrays.fill(data1, (byte) 1);
+
+ memoryBuffer.write(2720, data1, data1.length, true);
+
+ byte lastZero = memoryBuffer.readByte(2719);
+ byte firstOne = memoryBuffer.readByte(2721);
+
+ assertTrue(memoryBuffer.size() == 3072);
+ assertTrue(lastZero == 0);
+ assertTrue(firstOne == 1);
+
+ byte[] data = memoryBuffer.read(2720, 352);
+
+ int ones = 0; int zero = 0;
+ for (int i = 0; i < data.length; ++i){
+ if (data[i] == 1) ++ones;
+ if (data[i] == 0) ++zero;
+ }
+
+ assertTrue(ones == data.length);
+ assertTrue(zero == 0);
+ }
+
+ @Test
+ public void memoryWriteLimited_2(){
+
+ Memory memoryBuffer = new Memory();
+ memoryBuffer.extend(0, 3072);
+
+ byte[] data1 = new byte[6272];
+ Arrays.fill(data1, (byte) 1);
+
+ memoryBuffer.write(2720, data1, 300, true);
+
+ byte lastZero = memoryBuffer.readByte(2719);
+ byte firstOne = memoryBuffer.readByte(2721);
+
+ assertTrue(memoryBuffer.size() == 3072);
+ assertTrue(lastZero == 0);
+ assertTrue(firstOne == 1);
+
+ byte[] data = memoryBuffer.read(2720, 352);
+
+ int ones = 0; int zero = 0;
+ for (int i = 0; i < data.length; ++i){
+ if (data[i] == 1) ++ones;
+ if (data[i] == 0) ++zero;
+ }
+
+ assertTrue(ones == 300);
+ assertTrue(zero == 52);
+ }
+
+ @Test
+ public void memoryWriteLimited_3(){
+
+ Memory memoryBuffer = new Memory();
+ memoryBuffer.extend(0, 128);
+
+ byte[] data1 = new byte[20];
+ Arrays.fill(data1, (byte) 1);
+
+ memoryBuffer.write(10, data1, 40, true);
+
+ byte lastZero = memoryBuffer.readByte(9);
+ byte firstOne = memoryBuffer.readByte(10);
+
+ assertTrue(memoryBuffer.size() == 128);
+ assertTrue(lastZero == 0);
+ assertTrue(firstOne == 1);
+
+ byte[] data = memoryBuffer.read(10, 30);
+
+ int ones = 0; int zero = 0;
+ for (int i = 0; i < data.length; ++i){
+ if (data[i] == 1) ++ones;
+ if (data[i] == 0) ++zero;
+ }
+
+ assertTrue(ones == 20);
+ assertTrue(zero == 10);
+ }
+
+
+
+}
\ No newline at end of file
diff --git a/src/test/java/org/tron/common/runtime/vm/PrecompiledContractsTest.java b/src/test/java/org/tron/common/runtime/vm/PrecompiledContractsTest.java
new file mode 100644
index 00000000000..8431097be09
--- /dev/null
+++ b/src/test/java/org/tron/common/runtime/vm/PrecompiledContractsTest.java
@@ -0,0 +1,322 @@
+package org.tron.common.runtime.vm;
+
+
+import static junit.framework.TestCase.fail;
+import static org.tron.common.runtime.utils.MUtil.convertToTronAddress;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import java.io.File;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.spongycastle.util.Arrays;
+import org.spongycastle.util.encoders.Hex;
+import org.tron.common.application.TronApplicationContext;
+import org.tron.common.runtime.vm.PrecompiledContracts.PrecompiledContract;
+import org.tron.common.runtime.vm.program.ProgramResult;
+import org.tron.common.storage.DepositImpl;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.ByteUtil;
+import org.tron.common.utils.FileUtil;
+import org.tron.common.utils.StringUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.actuator.FreezeBalanceActuator;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.capsule.ProposalCapsule;
+import org.tron.core.capsule.TransactionResultCapsule;
+import org.tron.core.capsule.WitnessCapsule;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.BalanceInsufficientException;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.ItemNotFoundException;
+import org.tron.protos.Contract;
+import org.tron.protos.Protocol.AccountType;
+import org.tron.protos.Protocol.Proposal.State;
+
+@Slf4j
+public class PrecompiledContractsTest {
+
+ // common
+ private static final DataWord voteContractAddr = new DataWord(
+ "0000000000000000000000000000000000000000000000000000000000010001");
+// private static final DataWord freezeBalanceAddr = new DataWord(
+// "0000000000000000000000000000000000000000000000000000000000010002");
+// private static final DataWord unFreezeBalanceAddr = new DataWord(
+// "0000000000000000000000000000000000000000000000000000000000010003");
+ private static final DataWord withdrawBalanceAddr = new DataWord(
+ "0000000000000000000000000000000000000000000000000000000000010004");
+ private static final DataWord proposalApproveAddr = new DataWord(
+ "0000000000000000000000000000000000000000000000000000000000010005");
+ private static final DataWord proposalCreateAddr = new DataWord(
+ "0000000000000000000000000000000000000000000000000000000000010006");
+ private static final DataWord proposalDeleteAddr = new DataWord(
+ "0000000000000000000000000000000000000000000000000000000000010007");
+ private static final DataWord convertFromTronBytesAddressAddr = new DataWord(
+ "0000000000000000000000000000000000000000000000000000000000010008");
+ private static final DataWord convertFromTronBase58AddressAddr = new DataWord(
+ "0000000000000000000000000000000000000000000000000000000000010009");
+
+ private static TronApplicationContext context;
+ private static Manager dbManager;
+ private static final String dbPath = "output_PrecompiledContracts_test";
+ private static final String ACCOUNT_NAME = "account";
+ private static final String OWNER_ADDRESS;
+ private static final String WITNESS_NAME = "witness";
+ private static final String WITNESS_ADDRESS;
+ private static final String WITNESS_ADDRESS_BASE = "548794500882809695a8a687866e76d4271a1abc" ;
+ private static final String URL = "https://tron.network";
+
+ // withdraw
+ private static final long initBalance = 10_000_000_000L;
+ private static final long allowance = 32_000_000L;
+
+ static {
+ Args.setParam(new String[]{"--output-directory", dbPath, "--debug"}, Constant.TEST_CONF);
+ context = new TronApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
+ WITNESS_ADDRESS = Wallet.getAddressPreFixString() + WITNESS_ADDRESS_BASE;
+
+ }
+
+
+ /**
+ * Init data.
+ */
+ @BeforeClass
+ public static void init() {
+ dbManager = context.getBean(Manager.class);
+ }
+
+ /**
+ * create temp Capsule test need.
+ */
+ @Before
+ public void createCapsule() {
+ // witness: witnessCapsule
+ WitnessCapsule witnessCapsule =
+ new WitnessCapsule(
+ StringUtil.hexString2ByteString(WITNESS_ADDRESS),
+ 10L,
+ URL);
+ // witness: AccountCapsule
+ AccountCapsule witnessAccountCapsule =
+ new AccountCapsule(
+ ByteString.copyFromUtf8(WITNESS_NAME),
+ StringUtil.hexString2ByteString(WITNESS_ADDRESS),
+ AccountType.Normal,
+ initBalance);
+ // some normal account
+ AccountCapsule ownerAccountFirstCapsule =
+ new AccountCapsule(
+ ByteString.copyFromUtf8(ACCOUNT_NAME),
+ StringUtil.hexString2ByteString(OWNER_ADDRESS),
+ AccountType.Normal,
+ 10_000_000_000_000L);
+
+ dbManager.getAccountStore()
+ .put(witnessAccountCapsule.getAddress().toByteArray(), witnessAccountCapsule);
+ dbManager.getAccountStore()
+ .put(ownerAccountFirstCapsule.getAddress().toByteArray(), ownerAccountFirstCapsule);
+ dbManager.getWitnessStore().put(witnessCapsule.getAddress().toByteArray(), witnessCapsule);
+
+ dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(1000000);
+ dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderNumber(10);
+ dbManager.getDynamicPropertiesStore().saveNextMaintenanceTime(2000000);
+ }
+
+
+ private Any getFreezeContract(String ownerAddress, long frozenBalance, long duration) {
+ return Any.pack(
+ Contract.FreezeBalanceContract.newBuilder()
+ .setOwnerAddress(StringUtil.hexString2ByteString(ownerAddress))
+ .setFrozenBalance(frozenBalance)
+ .setFrozenDuration(duration)
+ .build());
+ }
+
+ private PrecompiledContract createPrecompiledContract(DataWord addr, String ownerAddress) {
+ PrecompiledContract contract = PrecompiledContracts.getContractForAddress(addr);
+ contract.setCallerAddress(convertToTronAddress(Hex.decode(ownerAddress)));
+ contract.setDeposit(DepositImpl.createRoot(dbManager));
+ ProgramResult programResult = new ProgramResult();
+ contract.setResult(programResult);
+ return contract;
+ }
+
+ @Test
+ public void voteWitnessNativeTest()
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, ContractValidateException, ContractExeException {
+ PrecompiledContract contract = createPrecompiledContract(voteContractAddr, OWNER_ADDRESS);
+ byte[] witnessAddressBytes = new byte[32];
+ byte[] witnessAddressBytes21 = Hex.decode(WITNESS_ADDRESS);
+ System.arraycopy(witnessAddressBytes21, 0, witnessAddressBytes,
+ witnessAddressBytes.length - witnessAddressBytes21.length, witnessAddressBytes21.length);
+
+ DataWord voteCount = new DataWord(
+ "0000000000000000000000000000000000000000000000000000000000000001");
+ byte[] voteCountBytes = voteCount.getData();
+ byte[] data = new byte[witnessAddressBytes.length + voteCountBytes.length];
+ System.arraycopy(witnessAddressBytes, 0, data, 0, witnessAddressBytes.length);
+ System.arraycopy(voteCountBytes, 0, data, witnessAddressBytes.length, voteCountBytes.length);
+
+ long frozenBalance = 1_000_000_000_000L;
+ long duration = 3;
+ Any freezeContract = getFreezeContract(OWNER_ADDRESS, frozenBalance, duration);
+ Constructor constructor =
+ FreezeBalanceActuator.class
+ .getDeclaredConstructor(Any.class, dbManager.getClass());
+ constructor.setAccessible(true);
+ FreezeBalanceActuator freezeBalanceActuator = constructor
+ .newInstance(freezeContract, dbManager);
+
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+ freezeBalanceActuator.validate();
+ freezeBalanceActuator.execute(ret);
+
+ Boolean result = contract.execute(data).getLeft();
+ Assert.assertEquals(1,
+ dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS)).getVotesList()
+ .get(0).getVoteCount());
+ Assert.assertArrayEquals(ByteArray.fromHexString(WITNESS_ADDRESS),
+ dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS)).getVotesList()
+ .get(0).getVoteAddress().toByteArray());
+ Assert.assertEquals(true, result);
+ }
+
+ @Test
+ public void withdrawBalanceNativeTest() {
+ PrecompiledContract contract = createPrecompiledContract(withdrawBalanceAddr, WITNESS_ADDRESS);
+
+ long now = System.currentTimeMillis();
+ dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(now);
+ byte[] address = ByteArray.fromHexString(WITNESS_ADDRESS);
+ try {
+ dbManager.adjustAllowance(address, allowance);
+ } catch (BalanceInsufficientException e) {
+ fail("BalanceInsufficientException");
+ }
+ AccountCapsule accountCapsule = dbManager.getAccountStore().get(address);
+ Assert.assertEquals(allowance, accountCapsule.getAllowance());
+ Assert.assertEquals(0, accountCapsule.getLatestWithdrawTime());
+
+ WitnessCapsule witnessCapsule = new WitnessCapsule(ByteString.copyFrom(address),
+ 100, "http://baidu.com");
+ dbManager.getWitnessStore().put(address, witnessCapsule);
+
+ contract.execute(new byte[0]);
+ AccountCapsule witnessAccount =
+ dbManager.getAccountStore().get(ByteArray.fromHexString(WITNESS_ADDRESS));
+ Assert.assertEquals(initBalance + allowance, witnessAccount.getBalance());
+ Assert.assertEquals(0, witnessAccount.getAllowance());
+ Assert.assertNotEquals(0, witnessAccount.getLatestWithdrawTime());
+ }
+
+
+ @Test
+ public void proposalTest() {
+
+ try {
+ /*
+ * create proposal Test
+ */
+ DataWord key = new DataWord(
+ "0000000000000000000000000000000000000000000000000000000000000000");
+ // 1000000 == 0xF4240
+ DataWord value = new DataWord(
+ "00000000000000000000000000000000000000000000000000000000000F4240");
+ byte[] data4Create = new byte[64];
+ System.arraycopy(key.getData(),0,data4Create,0,key.getData().length);
+ System.arraycopy(value.getData(),0,data4Create,key.getData().length,value.getData().length);
+
+ PrecompiledContract createContract = createPrecompiledContract(proposalCreateAddr,WITNESS_ADDRESS);
+
+ Assert.assertEquals(0, dbManager.getDynamicPropertiesStore().getLatestProposalNum());
+ ProposalCapsule proposalCapsule;
+ byte[] idBytes = createContract.execute(data4Create).getRight();
+ long id = ByteUtil.byteArrayToLong(idBytes);
+ proposalCapsule = dbManager.getProposalStore().get(ByteArray.fromLong(id));
+ Assert.assertNotNull(proposalCapsule);
+ Assert.assertEquals(1, dbManager.getDynamicPropertiesStore().getLatestProposalNum());
+ Assert.assertEquals(0, proposalCapsule.getApprovals().size());
+ Assert.assertEquals(1000000, proposalCapsule.getCreateTime());
+ Assert.assertEquals(261200000, proposalCapsule.getExpirationTime()
+ ); // 2000000 + 3 * 4 * 21600000
+
+
+
+ /*
+ * approve proposal Test
+ */
+
+ byte[] data4Approve = new byte[64];
+ DataWord isApprove = new DataWord("0000000000000000000000000000000000000000000000000000000000000001");
+ System.arraycopy(idBytes,0,data4Approve,0,idBytes.length);
+ System.arraycopy(isApprove.getData(),0,data4Approve,idBytes.length,isApprove.getData().length);
+ PrecompiledContract approveContract = createPrecompiledContract(proposalApproveAddr,WITNESS_ADDRESS);
+ approveContract.execute(data4Approve);
+ proposalCapsule = dbManager.getProposalStore().get(ByteArray.fromLong(id));
+ Assert.assertEquals(1,proposalCapsule.getApprovals().size());
+ Assert.assertEquals(ByteString.copyFrom(ByteArray.fromHexString(WITNESS_ADDRESS)),
+ proposalCapsule.getApprovals().get(0));
+
+ /*
+ * delete proposal Test
+ */
+ PrecompiledContract deleteContract = createPrecompiledContract(proposalDeleteAddr,WITNESS_ADDRESS);
+ deleteContract.execute(idBytes);
+ proposalCapsule = dbManager.getProposalStore().get(ByteArray.fromLong(id));
+ Assert.assertEquals(State.CANCELED, proposalCapsule.getState());
+
+ } catch (ItemNotFoundException e) {
+ Assert.fail();
+ }
+ }
+
+
+ @Test
+ public void convertFromTronBytesAddressNativeTest() {
+ PrecompiledContract contract = createPrecompiledContract(convertFromTronBytesAddressAddr, WITNESS_ADDRESS);
+ byte[] solidityAddress = contract.execute(Hex.decode(WITNESS_ADDRESS)).getRight();
+ Assert.assertArrayEquals(solidityAddress,new DataWord(Hex.decode(WITNESS_ADDRESS_BASE)).getData());
+ }
+
+ @Test
+ public void convertFromTronBase58AddressNative() {
+ // 27WnTihwXsqCqpiNedWvtKCZHsLjDt4Hfmf TestNet address
+ DataWord word1 = new DataWord("3237576e54696877587371437170694e65645776744b435a48734c6a44743448");
+ DataWord word2 = new DataWord("666d660000000000000000000000000000000000000000000000000000000000");
+
+ byte[] data = new byte[35];
+ System.arraycopy(word1.getData(),0,data,0, word1.getData().length);
+ System.arraycopy(Arrays.copyOfRange(word2.getData(), 0, 3),0,data,word1.getData().length,3);
+ PrecompiledContract contract = createPrecompiledContract(convertFromTronBase58AddressAddr, WITNESS_ADDRESS);
+
+ byte[] solidityAddress = contract.execute(data).getRight();
+ Assert.assertArrayEquals(solidityAddress,new DataWord(Hex.decode(WITNESS_ADDRESS_BASE)).getData());
+ }
+
+ /**
+ * Release resources.
+ */
+ @AfterClass
+ public static void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+
+}
diff --git a/src/test/java/org/tron/core/BandwidthProcessorTest.java b/src/test/java/org/tron/core/BandwidthProcessorTest.java
index bdf9f60eac5..611af7d88cf 100755
--- a/src/test/java/org/tron/core/BandwidthProcessorTest.java
+++ b/src/test/java/org/tron/core/BandwidthProcessorTest.java
@@ -9,7 +9,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.capsule.AccountCapsule;
@@ -20,6 +20,7 @@
import org.tron.core.config.args.Args;
import org.tron.core.db.BandwidthProcessor;
import org.tron.core.db.Manager;
+import org.tron.core.db.TransactionTrace;
import org.tron.protos.Contract;
import org.tron.protos.Contract.AssetIssueContract;
import org.tron.protos.Contract.TransferAssetContract;
@@ -31,7 +32,7 @@ public class BandwidthProcessorTest {
private static Manager dbManager;
private static final String dbPath = "bandwidth_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static final String ASSET_NAME;
private static final String OWNER_ADDRESS;
private static final String ASSET_ADDRESS;
@@ -39,7 +40,7 @@ public class BandwidthProcessorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
ASSET_NAME = "test_token";
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
TO_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
@@ -174,7 +175,9 @@ public void testFree() throws Exception {
dbManager.getAccountStore().put(ownerCapsule.getAddress().toByteArray(), ownerCapsule);
TransactionResultCapsule ret = new TransactionResultCapsule();
- dbManager.consumeBandwidth(trx, ret);
+ TransactionTrace trace = new TransactionTrace(trx, dbManager);
+
+ dbManager.consumeBandwidth(trx, ret, trace);
AccountCapsule ownerCapsuleNew = dbManager.getAccountStore()
.get(ByteArray.fromHexString(OWNER_ADDRESS));
@@ -188,11 +191,11 @@ public void testFree() throws Exception {
dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(1526691038000L); // + 12h
- dbManager.consumeBandwidth(trx, ret);
+ dbManager.consumeBandwidth(trx, ret, trace);
ownerCapsuleNew = dbManager.getAccountStore()
.get(ByteArray.fromHexString(OWNER_ADDRESS));
- Assert.assertEquals(61L + 122L, ownerCapsuleNew.getFreeNetUsage());
+ Assert.assertEquals(61L + 122, ownerCapsuleNew.getFreeNetUsage());
Assert.assertEquals(508897012L,
ownerCapsuleNew.getLatestConsumeFreeTime()); // 508882612L + 28800L/2
Assert.assertEquals(1526691038000L, ownerCapsuleNew.getLatestOperationTime());
@@ -220,7 +223,8 @@ public void testConsumeAssetAccount() throws Exception {
dbManager.getAccountStore().put(assetCapsule.getAddress().toByteArray(), assetCapsule);
TransactionResultCapsule ret = new TransactionResultCapsule();
- dbManager.consumeBandwidth(trx, ret);
+ TransactionTrace trace = new TransactionTrace(trx, dbManager);
+ dbManager.consumeBandwidth(trx, ret, trace);
AccountCapsule ownerCapsuleNew = dbManager.getAccountStore()
.get(ByteArray.fromHexString(OWNER_ADDRESS));
@@ -236,7 +240,7 @@ public void testConsumeAssetAccount() throws Exception {
dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(1526691038000L); // + 12h
- dbManager.consumeBandwidth(trx, ret);
+ dbManager.consumeBandwidth(trx, ret, trace);
ownerCapsuleNew = dbManager.getAccountStore()
.get(ByteArray.fromHexString(OWNER_ADDRESS));
@@ -268,7 +272,8 @@ public void testConsumeOwner() throws Exception {
dbManager.getAccountStore().put(ownerCapsule.getAddress().toByteArray(), ownerCapsule);
TransactionResultCapsule ret = new TransactionResultCapsule();
- dbManager.consumeBandwidth(trx, ret);
+ TransactionTrace trace = new TransactionTrace(trx, dbManager);
+ dbManager.consumeBandwidth(trx, ret, trace);
AccountCapsule ownerCapsuleNew = dbManager.getAccountStore()
.get(ByteArray.fromHexString(OWNER_ADDRESS));
@@ -283,7 +288,7 @@ public void testConsumeOwner() throws Exception {
dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(1526691038000L); // + 12h
- dbManager.consumeBandwidth(trx, ret);
+ dbManager.consumeBandwidth(trx, ret, trace);
ownerCapsuleNew = dbManager.getAccountStore()
.get(ByteArray.fromHexString(OWNER_ADDRESS));
@@ -322,12 +327,13 @@ public void testUsingFee() throws Exception {
dbManager.getAccountStore().put(ownerCapsule.getAddress().toByteArray(), ownerCapsule);
TransactionResultCapsule ret = new TransactionResultCapsule();
- dbManager.consumeBandwidth(trx, ret);
+ TransactionTrace trace = new TransactionTrace(trx, dbManager);
+ dbManager.consumeBandwidth(trx, ret, trace);
AccountCapsule ownerCapsuleNew = dbManager.getAccountStore()
.get(ByteArray.fromHexString(OWNER_ADDRESS));
- long transactionFee = 122L * dbManager.getDynamicPropertiesStore().getTransactionFee();
+ long transactionFee = (122L) * dbManager.getDynamicPropertiesStore().getTransactionFee();
Assert.assertEquals(transactionFee,
dbManager.getDynamicPropertiesStore().getTotalTransactionCost());
Assert.assertEquals(
@@ -336,7 +342,7 @@ public void testUsingFee() throws Exception {
Assert.assertEquals(transactionFee, ret.getFee());
dbManager.getAccountStore().delete(ByteArray.fromHexString(TO_ADDRESS));
- dbManager.consumeBandwidth(trx, ret);
+ dbManager.consumeBandwidth(trx, ret, trace);
// long createAccountFee = dbManager.getDynamicPropertiesStore().getCreateAccountFee();
// ownerCapsuleNew = dbManager.getAccountStore()
diff --git a/src/test/java/org/tron/core/CpuProcessorTest.java b/src/test/java/org/tron/core/EnergyProcessorTest.java
similarity index 77%
rename from src/test/java/org/tron/core/CpuProcessorTest.java
rename to src/test/java/org/tron/core/EnergyProcessorTest.java
index 341d09ae5c3..89c72927985 100755
--- a/src/test/java/org/tron/core/CpuProcessorTest.java
+++ b/src/test/java/org/tron/core/EnergyProcessorTest.java
@@ -8,34 +8,31 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.capsule.AccountCapsule;
-import org.tron.core.capsule.TransactionCapsule;
-import org.tron.core.capsule.TransactionResultCapsule;
import org.tron.core.config.DefaultConfig;
import org.tron.core.config.args.Args;
-import org.tron.core.db.CpuProcessor;
+import org.tron.core.db.EnergyProcessor;
import org.tron.core.db.Manager;
import org.tron.protos.Contract;
import org.tron.protos.Contract.AssetIssueContract;
-import org.tron.protos.Contract.TransferAssetContract;
import org.tron.protos.Protocol.AccountType;
@Slf4j
-public class CpuProcessorTest {
+public class EnergyProcessorTest {
private static Manager dbManager;
- private static final String dbPath = "CpuProcessorTest";
- private static AnnotationConfigApplicationContext context;
+ private static final String dbPath = "EnergyProcessorTest";
+ private static TronApplicationContext context;
private static final String ASSET_NAME;
private static final String CONTRACT_PROVIDER_ADDRESS;
private static final String USER_ADDRESS;
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
ASSET_NAME = "test_token";
CONTRACT_PROVIDER_ADDRESS =
Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
@@ -103,31 +100,32 @@ private AssetIssueContract getAssetIssueContract() {
}
@Test
- public void testUseContractCreatorCpu() throws Exception {
+ public void testUseContractCreatorEnergy() throws Exception {
dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(1526647838000L);
- dbManager.getDynamicPropertiesStore().saveTotalCpuWeight(10_000_000L);
+ dbManager.getDynamicPropertiesStore().saveTotalEnergyWeight(10_000_000L);
AccountCapsule ownerCapsule = dbManager.getAccountStore()
.get(ByteArray.fromHexString(CONTRACT_PROVIDER_ADDRESS));
dbManager.getAccountStore().put(ownerCapsule.getAddress().toByteArray(), ownerCapsule);
- CpuProcessor processor = new CpuProcessor(dbManager);
- long cpuTime = 10000;
+ EnergyProcessor processor = new EnergyProcessor(dbManager);
+ long energy = 10000;
long now = 1526647838000L;
- boolean result = processor.useCpu(ownerCapsule, cpuTime, now);
+ boolean result = processor.useEnergy(ownerCapsule, energy, now);
Assert.assertEquals(false, result);
- ownerCapsule.setFrozenForCpu(10_000_000L, 0L);
- result = processor.useCpu(ownerCapsule, cpuTime, now);
+ ownerCapsule.setFrozenForEnergy(10_000_000L, 0L);
+ result = processor.useEnergy(ownerCapsule, energy, now);
Assert.assertEquals(true, result);
AccountCapsule ownerCapsuleNew = dbManager.getAccountStore()
.get(ByteArray.fromHexString(CONTRACT_PROVIDER_ADDRESS));
Assert.assertEquals(1526647838000L, ownerCapsuleNew.getLatestOperationTime());
- Assert.assertEquals(1526647838000L, ownerCapsuleNew.getAccountResource().getLatestConsumeTimeForCpu());
- Assert.assertEquals(10000L, ownerCapsuleNew.getAccountResource().getCpuUsage());
+ Assert.assertEquals(1526647838000L,
+ ownerCapsuleNew.getAccountResource().getLatestConsumeTimeForEnergy());
+ Assert.assertEquals(10000L, ownerCapsuleNew.getAccountResource().getEnergyUsage());
}
diff --git a/src/test/java/org/tron/core/StorageMarketTest.java b/src/test/java/org/tron/core/StorageMarketTest.java
new file mode 100644
index 00000000000..710ba5876f3
--- /dev/null
+++ b/src/test/java/org/tron/core/StorageMarketTest.java
@@ -0,0 +1,293 @@
+package org.tron.core;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.tron.common.application.TronApplicationContext;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.Parameter.ChainConstant;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.db.StorageMarket;
+import org.tron.protos.Contract;
+import org.tron.protos.Protocol.AccountType;
+
+@Slf4j
+public class StorageMarketTest {
+
+ private static Manager dbManager;
+ private static StorageMarket storageMarket;
+ private static final String dbPath = "output_buy_storage_test";
+ private static TronApplicationContext context;
+ private static final String OWNER_ADDRESS;
+ private static final String OWNER_ADDRESS_INVALID = "aaaa";
+ private static final String OWNER_ACCOUNT_INVALID;
+ private static final long initBalance = 10_000_000_000_000_000L;
+
+ static {
+ Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
+ context = new TronApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
+ OWNER_ACCOUNT_INVALID =
+ Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a3456";
+ }
+
+ /**
+ * Init data.
+ */
+ @BeforeClass
+ public static void init() {
+ dbManager = context.getBean(Manager.class);
+ storageMarket = new StorageMarket(dbManager);
+ // Args.setParam(new String[]{"--output-directory", dbPath},
+ // "config-junit.conf");
+ // dbManager = new Manager();
+ // dbManager.init();
+ }
+
+ /**
+ * Release resources.
+ */
+ @AfterClass
+ public static void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+
+ /**
+ * create temp Capsule test need.
+ */
+ @Before
+ public void createAccountCapsule() {
+ AccountCapsule ownerCapsule =
+ new AccountCapsule(
+ ByteString.copyFromUtf8("owner"),
+ ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)),
+ AccountType.Normal,
+ initBalance);
+ dbManager.getAccountStore().put(ownerCapsule.getAddress().toByteArray(), ownerCapsule);
+
+ dbManager.getDynamicPropertiesStore().saveTotalStorageReserved(
+ 128L * 1024 * 1024 * 1024);
+ dbManager.getDynamicPropertiesStore().saveTotalStoragePool(100_000_000_000000L);
+ dbManager.getDynamicPropertiesStore().saveTotalStorageTax(0);
+
+ dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(0);
+ }
+
+ private Any getContract(String ownerAddress, long quant) {
+ return Any.pack(
+ Contract.BuyStorageContract.newBuilder()
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(ownerAddress)))
+ .setQuant(quant)
+ .build());
+ }
+
+ @Test
+ public void testBuyStorage() {
+ long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+ long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+ Assert.assertEquals(currentPool, 100_000_000_000000L);
+ Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+
+ AccountCapsule owner =
+ dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+
+ long quant = 2_000_000_000_000L; // 2 million trx
+ storageMarket.buyStorage(owner, quant);
+
+ Assert.assertEquals(owner.getBalance(), initBalance - quant
+ - ChainConstant.TRANSFER_FEE);
+ Assert.assertEquals(2694881440L, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - 2694881440L,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + quant,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ }
+
+ @Test
+ public void testBuyStorage2() {
+ long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+ long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+ Assert.assertEquals(currentPool, 100_000_000_000000L);
+ Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+
+ AccountCapsule owner =
+ dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+
+ long quant = 1_000_000_000_000L; // 1 million trx
+
+ storageMarket.buyStorage(owner, quant);
+
+ Assert.assertEquals(owner.getBalance(), initBalance - quant
+ - ChainConstant.TRANSFER_FEE);
+ Assert.assertEquals(1360781717L, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - 1360781717L,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + quant,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ storageMarket.buyStorage(owner, quant);
+
+ Assert.assertEquals(owner.getBalance(), initBalance - 2 * quant
+ - ChainConstant.TRANSFER_FEE);
+ Assert.assertEquals(2694881439L, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - 2694881439L,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + 2 * quant,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ }
+
+
+ @Test
+ public void testBuyStorageBytes() {
+ long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+ long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+ Assert.assertEquals(currentPool, 100_000_000_000000L);
+ Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+
+ AccountCapsule owner =
+ dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+
+ long bytes = 2694881440L; // 2 million trx
+ storageMarket.buyStorageBytes(owner, bytes);
+
+ Assert.assertEquals(owner.getBalance(), initBalance - 2_000_000_000_000L
+ - ChainConstant.TRANSFER_FEE);
+ Assert.assertEquals(bytes, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - bytes,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + 2_000_000_000_000L,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ }
+
+ @Test
+ public void testBuyStorageBytes2() {
+ long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+ long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+ Assert.assertEquals(currentPool, 100_000_000_000000L);
+ Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+
+ AccountCapsule owner =
+ dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+
+ long bytes1 = 1360781717L;
+
+ storageMarket.buyStorageBytes(owner, bytes1);
+
+ Assert.assertEquals(owner.getBalance(), initBalance - 1_000_000_000_000L
+ - ChainConstant.TRANSFER_FEE);
+ Assert.assertEquals(bytes1, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - bytes1,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + 1_000_000_000_000L,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ long bytes2 = 1334099723L;
+ storageMarket.buyStorageBytes(owner, bytes2);
+ Assert.assertEquals(owner.getBalance(), initBalance - 2 * 1_000_000_000_000L
+ - ChainConstant.TRANSFER_FEE);
+ Assert.assertEquals(bytes1 + bytes2, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - (bytes1 + bytes2),
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + 2 * 1_000_000_000_000L,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ }
+
+ @Test
+ public void testSellStorage() {
+ long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+ long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+ Assert.assertEquals(currentPool, 100_000_000_000000L);
+ Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+
+ AccountCapsule owner =
+ dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+
+ long quant = 2_000_000_000_000L; // 2 million trx
+ storageMarket.buyStorage(owner, quant);
+
+ Assert.assertEquals(owner.getBalance(), initBalance - quant
+ - ChainConstant.TRANSFER_FEE);
+ Assert.assertEquals(2694881440L, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - 2694881440L,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + quant,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ long bytes = 2694881440L;
+ storageMarket.sellStorage(owner, bytes);
+
+ Assert.assertEquals(owner.getBalance(), initBalance);
+ Assert.assertEquals(0, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(100_000_000_000_000L,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ }
+
+ @Test
+ public void testSellStorage2() {
+ long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+ long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+ Assert.assertEquals(currentPool, 100_000_000_000000L);
+ Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+
+ AccountCapsule owner =
+ dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+
+ long quant = 2_000_000_000_000L; // 2 million trx
+ storageMarket.buyStorage(owner, quant);
+
+ Assert.assertEquals(owner.getBalance(), initBalance - quant
+ - ChainConstant.TRANSFER_FEE);
+ Assert.assertEquals(2694881440L, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - 2694881440L,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + quant,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ long bytes1 = 2694881440L - 1360781717L; // 1 million trx
+ long bytes2 = 1360781717L; // 1 million trx
+
+ storageMarket.sellStorage(owner, bytes1);
+
+ Assert.assertEquals(owner.getBalance(), initBalance - 1_000_000_000_000L);
+ Assert.assertEquals(1360781717L, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - 1360781717L,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + 1_000_000_000_000L,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ storageMarket.sellStorage(owner, bytes2);
+
+ Assert.assertEquals(owner.getBalance(), initBalance);
+ Assert.assertEquals(0, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ }
+
+
+}
diff --git a/src/test/java/org/tron/core/WalletTest.java b/src/test/java/org/tron/core/WalletTest.java
index 18ccd0d057d..f5bd1476cf1 100644
--- a/src/test/java/org/tron/core/WalletTest.java
+++ b/src/test/java/org/tron/core/WalletTest.java
@@ -32,7 +32,7 @@
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.api.GrpcAPI.AssetIssueList;
import org.tron.api.GrpcAPI.BlockList;
import org.tron.common.crypto.ECKey;
@@ -57,7 +57,7 @@
@Slf4j
public class WalletTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Wallet wallet;
private static Manager manager;
private static String dbPath = "output_wallet_test";
@@ -100,7 +100,7 @@ public class WalletTest {
static {
Args.setParam(new String[]{"-d", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@BeforeClass
diff --git a/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java b/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java
index 39c39e519b7..bb2e07e464f 100755
--- a/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/AssetIssueActuatorTest.java
@@ -14,7 +14,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -35,7 +35,7 @@
@Slf4j
public class AssetIssueActuatorTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static final String dbPath = "output_assetIssue_test";
private static final String OWNER_ADDRESS;
@@ -53,7 +53,7 @@ public class AssetIssueActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049150";
OWNER_ADDRESS_SECOND =
Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
@@ -922,7 +922,7 @@ public void descriptionTest() {
.setTrxNum(TRX_NUM).setNum(NUM)
.setStartTime(nowTime)
.setEndTime(nowTime + 24 * 3600 * 1000)
- .setDescription(ByteString.copyFromUtf8(description200Bytes+"0"))
+ .setDescription(ByteString.copyFromUtf8(description200Bytes + "0"))
.setUrl(ByteString.copyFromUtf8(URL))
.build());
@@ -1329,24 +1329,21 @@ public void frozenTest() {
}
/**
- * 1. start time should not be null
- * 2. end time should not be null
- * 3. start time >= getHeadBlockTimeStamp
- * 4. start time < end time
- *
+ * 1. start time should not be null 2. end time should not be null 3. start time >=
+ * getHeadBlockTimeStamp 4. start time < end time
*/
@Test
public void issueTimeTest() {
//empty start time will throw exception
Any contract = Any.pack(Contract.AssetIssueContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
- .setName(ByteString.copyFromUtf8(NAME))
- .setTotalSupply(TOTAL_SUPPLY)
- .setTrxNum(TRX_NUM).setNum(NUM)
- .setEndTime(endTime)
- .setDescription(ByteString.copyFromUtf8("description"))
- .setUrl(ByteString.copyFromUtf8(URL))
- .build());
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
+ .setName(ByteString.copyFromUtf8(NAME))
+ .setTotalSupply(TOTAL_SUPPLY)
+ .setTrxNum(TRX_NUM).setNum(NUM)
+ .setEndTime(endTime)
+ .setDescription(ByteString.copyFromUtf8("description"))
+ .setUrl(ByteString.copyFromUtf8(URL))
+ .build());
AssetIssueActuator actuator = new AssetIssueActuator(contract, dbManager);
TransactionResultCapsule ret = new TransactionResultCapsule();
try {
@@ -1364,14 +1361,14 @@ public void issueTimeTest() {
//empty end time will throw exception
contract = Any.pack(Contract.AssetIssueContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
- .setName(ByteString.copyFromUtf8(NAME))
- .setTotalSupply(TOTAL_SUPPLY)
- .setTrxNum(TRX_NUM).setNum(NUM)
- .setStartTime(startTime)
- .setDescription(ByteString.copyFromUtf8("description"))
- .setUrl(ByteString.copyFromUtf8(URL))
- .build());
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
+ .setName(ByteString.copyFromUtf8(NAME))
+ .setTotalSupply(TOTAL_SUPPLY)
+ .setTrxNum(TRX_NUM).setNum(NUM)
+ .setStartTime(startTime)
+ .setDescription(ByteString.copyFromUtf8("description"))
+ .setUrl(ByteString.copyFromUtf8(URL))
+ .build());
actuator = new AssetIssueActuator(contract, dbManager);
ret = new TransactionResultCapsule();
try {
@@ -1389,15 +1386,15 @@ public void issueTimeTest() {
//startTime == now, throw exception
contract = Any.pack(Contract.AssetIssueContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
- .setName(ByteString.copyFromUtf8(NAME))
- .setTotalSupply(TOTAL_SUPPLY)
- .setTrxNum(TRX_NUM).setNum(NUM)
- .setStartTime(now)
- .setEndTime(endTime)
- .setDescription(ByteString.copyFromUtf8("description"))
- .setUrl(ByteString.copyFromUtf8(URL))
- .build());
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
+ .setName(ByteString.copyFromUtf8(NAME))
+ .setTotalSupply(TOTAL_SUPPLY)
+ .setTrxNum(TRX_NUM).setNum(NUM)
+ .setStartTime(now)
+ .setEndTime(endTime)
+ .setDescription(ByteString.copyFromUtf8("description"))
+ .setUrl(ByteString.copyFromUtf8(URL))
+ .build());
actuator = new AssetIssueActuator(contract, dbManager);
ret = new TransactionResultCapsule();
try {
@@ -1415,15 +1412,15 @@ public void issueTimeTest() {
//startTime < now, throw exception
contract = Any.pack(Contract.AssetIssueContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
- .setName(ByteString.copyFromUtf8(NAME))
- .setTotalSupply(TOTAL_SUPPLY)
- .setTrxNum(TRX_NUM).setNum(NUM)
- .setStartTime(now - 1)
- .setEndTime(endTime)
- .setDescription(ByteString.copyFromUtf8("description"))
- .setUrl(ByteString.copyFromUtf8(URL))
- .build());
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
+ .setName(ByteString.copyFromUtf8(NAME))
+ .setTotalSupply(TOTAL_SUPPLY)
+ .setTrxNum(TRX_NUM).setNum(NUM)
+ .setStartTime(now - 1)
+ .setEndTime(endTime)
+ .setDescription(ByteString.copyFromUtf8("description"))
+ .setUrl(ByteString.copyFromUtf8(URL))
+ .build());
actuator = new AssetIssueActuator(contract, dbManager);
ret = new TransactionResultCapsule();
try {
@@ -1441,15 +1438,15 @@ public void issueTimeTest() {
//endTime == startTime, throw exception
contract = Any.pack(Contract.AssetIssueContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
- .setName(ByteString.copyFromUtf8(NAME))
- .setTotalSupply(TOTAL_SUPPLY)
- .setTrxNum(TRX_NUM).setNum(NUM)
- .setStartTime(startTime)
- .setEndTime(startTime)
- .setDescription(ByteString.copyFromUtf8("description"))
- .setUrl(ByteString.copyFromUtf8(URL))
- .build());
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
+ .setName(ByteString.copyFromUtf8(NAME))
+ .setTotalSupply(TOTAL_SUPPLY)
+ .setTrxNum(TRX_NUM).setNum(NUM)
+ .setStartTime(startTime)
+ .setEndTime(startTime)
+ .setDescription(ByteString.copyFromUtf8("description"))
+ .setUrl(ByteString.copyFromUtf8(URL))
+ .build());
actuator = new AssetIssueActuator(contract, dbManager);
ret = new TransactionResultCapsule();
try {
@@ -1467,15 +1464,15 @@ public void issueTimeTest() {
//endTime < startTime, throw exception
contract = Any.pack(Contract.AssetIssueContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
- .setName(ByteString.copyFromUtf8(NAME))
- .setTotalSupply(TOTAL_SUPPLY)
- .setTrxNum(TRX_NUM).setNum(NUM)
- .setStartTime(endTime)
- .setEndTime(startTime)
- .setDescription(ByteString.copyFromUtf8("description"))
- .setUrl(ByteString.copyFromUtf8(URL))
- .build());
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
+ .setName(ByteString.copyFromUtf8(NAME))
+ .setTotalSupply(TOTAL_SUPPLY)
+ .setTrxNum(TRX_NUM).setNum(NUM)
+ .setStartTime(endTime)
+ .setEndTime(startTime)
+ .setDescription(ByteString.copyFromUtf8("description"))
+ .setUrl(ByteString.copyFromUtf8(URL))
+ .build());
actuator = new AssetIssueActuator(contract, dbManager);
ret = new TransactionResultCapsule();
try {
@@ -1493,21 +1490,22 @@ public void issueTimeTest() {
//right issue, will not throw exception
contract = Any.pack(Contract.AssetIssueContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
- .setName(ByteString.copyFromUtf8(NAME))
- .setTotalSupply(TOTAL_SUPPLY)
- .setTrxNum(TRX_NUM).setNum(NUM)
- .setStartTime(startTime)
- .setEndTime(endTime)
- .setDescription(ByteString.copyFromUtf8("description"))
- .setUrl(ByteString.copyFromUtf8(URL))
- .build());
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
+ .setName(ByteString.copyFromUtf8(NAME))
+ .setTotalSupply(TOTAL_SUPPLY)
+ .setTrxNum(TRX_NUM).setNum(NUM)
+ .setStartTime(startTime)
+ .setEndTime(endTime)
+ .setDescription(ByteString.copyFromUtf8("description"))
+ .setUrl(ByteString.copyFromUtf8(URL))
+ .build());
actuator = new AssetIssueActuator(contract, dbManager);
ret = new TransactionResultCapsule();
try {
actuator.validate();
actuator.execute(ret);
- AccountCapsule account = dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+ AccountCapsule account = dbManager.getAccountStore()
+ .get(ByteArray.fromHexString(OWNER_ADDRESS));
Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS);
Assert.assertEquals(account.getAssetIssuedName().toStringUtf8(), NAME);
Assert.assertEquals(account.getAssetMap().size(), 1);
@@ -1526,50 +1524,50 @@ public void issueTimeTest() {
@Test
public void assetIssueNameTest() {
Any contract = Any.pack(Contract.AssetIssueContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
- .setName(ByteString.copyFromUtf8(NAME))
- .setTotalSupply(TOTAL_SUPPLY)
- .setTrxNum(TRX_NUM).setNum(NUM)
- .setStartTime(startTime)
- .setEndTime(endTime)
- .setDescription(ByteString.copyFromUtf8("description"))
- .setUrl(ByteString.copyFromUtf8(URL))
- .build());
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
+ .setName(ByteString.copyFromUtf8(NAME))
+ .setTotalSupply(TOTAL_SUPPLY)
+ .setTrxNum(TRX_NUM).setNum(NUM)
+ .setStartTime(startTime)
+ .setEndTime(endTime)
+ .setDescription(ByteString.copyFromUtf8("description"))
+ .setUrl(ByteString.copyFromUtf8(URL))
+ .build());
AssetIssueActuator actuator = new AssetIssueActuator(contract, dbManager);
TransactionResultCapsule ret = new TransactionResultCapsule();
try {
- actuator.validate();
- actuator.execute(ret);
+ actuator.validate();
+ actuator.execute(ret);
} catch (ContractValidateException e) {
- Assert.assertFalse(e instanceof ContractValidateException);
+ Assert.assertFalse(e instanceof ContractValidateException);
} catch (ContractExeException e) {
- Assert.assertFalse(e instanceof ContractExeException);
+ Assert.assertFalse(e instanceof ContractExeException);
}
contract = Any.pack(Contract.AssetIssueContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
- .setName(ByteString.copyFromUtf8(ASSET_NAME_SECOND))
- .setTotalSupply(TOTAL_SUPPLY)
- .setTrxNum(TRX_NUM).setNum(NUM)
- .setStartTime(startTime)
- .setEndTime(endTime)
- .setDescription(ByteString.copyFromUtf8("description"))
- .setUrl(ByteString.copyFromUtf8(URL))
- .build());
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
+ .setName(ByteString.copyFromUtf8(ASSET_NAME_SECOND))
+ .setTotalSupply(TOTAL_SUPPLY)
+ .setTrxNum(TRX_NUM).setNum(NUM)
+ .setStartTime(startTime)
+ .setEndTime(endTime)
+ .setDescription(ByteString.copyFromUtf8("description"))
+ .setUrl(ByteString.copyFromUtf8(URL))
+ .build());
actuator = new AssetIssueActuator(contract, dbManager);
ret = new TransactionResultCapsule();
try {
- actuator.validate();
- actuator.execute(ret);
- Assert.assertTrue(false);
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.assertTrue(false);
} catch (ContractValidateException e) {
- Assert.assertTrue(e instanceof ContractValidateException);
- Assert.assertEquals("An account can only issue one asset", e.getMessage());
+ Assert.assertTrue(e instanceof ContractValidateException);
+ Assert.assertEquals("An account can only issue one asset", e.getMessage());
} catch (ContractExeException e) {
- Assert.assertFalse(e instanceof ContractExeException);
+ Assert.assertFalse(e instanceof ContractExeException);
} finally {
- dbManager.getAssetIssueStore().delete(ByteArray.fromString(NAME));
- dbManager.getAssetIssueStore().delete(ByteArray.fromString(ASSET_NAME_SECOND));
+ dbManager.getAssetIssueStore().delete(ByteArray.fromString(NAME));
+ dbManager.getAssetIssueStore().delete(ByteArray.fromString(ASSET_NAME_SECOND));
}
}
@@ -1577,24 +1575,25 @@ public void assetIssueNameTest() {
public void frozenListSizeTest() {
this.dbManager.getDynamicPropertiesStore().saveMaxFrozenSupplyNumber(3);
List frozenList = new ArrayList();
- for (int i = 0; i < this.dbManager.getDynamicPropertiesStore().getMaxFrozenSupplyNumber() + 2; i++) {
+ for (int i = 0; i < this.dbManager.getDynamicPropertiesStore().getMaxFrozenSupplyNumber() + 2;
+ i++) {
frozenList.add(FrozenSupply.newBuilder()
- .setFrozenAmount(10)
- .setFrozenDays(3)
- .build());
+ .setFrozenAmount(10)
+ .setFrozenDays(3)
+ .build());
}
Any contract = Any.pack(Contract.AssetIssueContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
- .setName(ByteString.copyFromUtf8(NAME))
- .setTotalSupply(TOTAL_SUPPLY)
- .setTrxNum(TRX_NUM).setNum(NUM)
- .setStartTime(startTime)
- .setEndTime(endTime)
- .setDescription(ByteString.copyFromUtf8("description"))
- .setUrl(ByteString.copyFromUtf8(URL))
- .addAllFrozenSupply(frozenList)
- .build());
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
+ .setName(ByteString.copyFromUtf8(NAME))
+ .setTotalSupply(TOTAL_SUPPLY)
+ .setTrxNum(TRX_NUM).setNum(NUM)
+ .setStartTime(startTime)
+ .setEndTime(endTime)
+ .setDescription(ByteString.copyFromUtf8("description"))
+ .setUrl(ByteString.copyFromUtf8(URL))
+ .addAllFrozenSupply(frozenList)
+ .build());
AssetIssueActuator actuator = new AssetIssueActuator(contract, dbManager);
TransactionResultCapsule ret = new TransactionResultCapsule();
try {
@@ -1616,20 +1615,20 @@ public void frozenSupplyMoreThanTotalSupplyTest() {
this.dbManager.getDynamicPropertiesStore().saveMaxFrozenSupplyNumber(3);
List frozenList = new ArrayList();
frozenList.add(FrozenSupply.newBuilder()
- .setFrozenAmount(TOTAL_SUPPLY + 1)
- .setFrozenDays(3)
- .build());
+ .setFrozenAmount(TOTAL_SUPPLY + 1)
+ .setFrozenDays(3)
+ .build());
Any contract = Any.pack(Contract.AssetIssueContract.newBuilder()
- .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
- .setName(ByteString.copyFromUtf8(NAME))
- .setTotalSupply(TOTAL_SUPPLY)
- .setTrxNum(TRX_NUM).setNum(NUM)
- .setStartTime(startTime)
- .setEndTime(endTime)
- .setDescription(ByteString.copyFromUtf8("description"))
- .setUrl(ByteString.copyFromUtf8(URL))
- .addAllFrozenSupply(frozenList)
- .build());
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)))
+ .setName(ByteString.copyFromUtf8(NAME))
+ .setTotalSupply(TOTAL_SUPPLY)
+ .setTrxNum(TRX_NUM).setNum(NUM)
+ .setStartTime(startTime)
+ .setEndTime(endTime)
+ .setDescription(ByteString.copyFromUtf8("description"))
+ .setUrl(ByteString.copyFromUtf8(URL))
+ .addAllFrozenSupply(frozenList)
+ .build());
AssetIssueActuator actuator = new AssetIssueActuator(contract, dbManager);
TransactionResultCapsule ret = new TransactionResultCapsule();
try {
diff --git a/src/test/java/org/tron/core/actuator/BuyStorageActuatorTest.java b/src/test/java/org/tron/core/actuator/BuyStorageActuatorTest.java
index bbb478555aa..5ccb6ef85eb 100644
--- a/src/test/java/org/tron/core/actuator/BuyStorageActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/BuyStorageActuatorTest.java
@@ -9,7 +9,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -31,7 +31,7 @@ public class BuyStorageActuatorTest {
private static Manager dbManager;
private static final String dbPath = "output_buy_storage_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static final String OWNER_ADDRESS;
private static final String OWNER_ADDRESS_INVALID = "aaaa";
private static final String OWNER_ACCOUNT_INVALID;
@@ -39,7 +39,7 @@ public class BuyStorageActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
OWNER_ACCOUNT_INVALID =
Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a3456";
@@ -139,7 +139,7 @@ public void testBuyStorage2() {
Assert.assertEquals(currentPool, 100_000_000_000000L);
Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
- long quant = 1_000_000_000_000L; // 2 million trx
+ long quant = 1_000_000_000_000L; // 1 million trx
BuyStorageActuator actuator = new BuyStorageActuator(
getContract(OWNER_ADDRESS, quant), dbManager);
@@ -164,19 +164,17 @@ public void testBuyStorage2() {
dbManager.getDynamicPropertiesStore().getTotalStoragePool());
actuator2.validate();
- actuator2.execute(ret);
+ actuator2.execute(ret2);
Assert.assertEquals(ret2.getInstance().getRet(), code.SUCESS);
+
owner =
dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
Assert.assertEquals(owner.getBalance(), initBalance - 2 * quant
- ChainConstant.TRANSFER_FEE);
Assert.assertEquals(2694881439L, owner.getStorageLimit());
- long tax = 0L;
- Assert.assertEquals(tax,
- dbManager.getDynamicPropertiesStore().getTotalStorageTax());
Assert.assertEquals(currentReserved - 2694881439L,
dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool + 2 * quant - tax,
+ Assert.assertEquals(currentPool + 2 * quant,
dbManager.getDynamicPropertiesStore().getTotalStoragePool());
} catch (ContractValidateException e) {
@@ -186,21 +184,115 @@ public void testBuyStorage2() {
}
}
+// @Test
+// public void testBuyStorageTax() {
+// long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+// long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+// Assert.assertEquals(currentPool, 100_000_000_000000L);
+// Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+//
+// long quant = 1_000_000_000_000L; // 2 million trx
+//
+// BuyStorageActuator actuator = new BuyStorageActuator(
+// getContract(OWNER_ADDRESS, quant), dbManager);
+// TransactionResultCapsule ret = new TransactionResultCapsule();
+//
+// BuyStorageActuator actuator2 = new BuyStorageActuator(
+// getContract(OWNER_ADDRESS, quant), dbManager);
+// TransactionResultCapsule ret2 = new TransactionResultCapsule();
+//
+// try {
+// actuator.validate();
+// actuator.execute(ret);
+// Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS);
+// AccountCapsule owner =
+// dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+// Assert.assertEquals(owner.getBalance(), initBalance - quant
+// - ChainConstant.TRANSFER_FEE);
+// Assert.assertEquals(1360781717L, owner.getStorageLimit());
+// Assert.assertEquals(currentReserved - 1360781717L,
+// dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+// Assert.assertEquals(currentPool + quant,
+// dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+//
+// dbManager.getDynamicPropertiesStore()
+// .saveLatestBlockHeaderTimestamp(365 * 24 * 3600 * 1000L);
+// actuator2.validate();
+// actuator2.execute(ret);
+// Assert.assertEquals(ret2.getInstance().getRet(), code.SUCESS);
+// owner =
+// dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+// Assert.assertEquals(owner.getBalance(), initBalance - 2 * quant
+// - ChainConstant.TRANSFER_FEE);
+// Assert.assertEquals(2561459696L, owner.getStorageLimit());
+// long tax = 100899100225L;
+// Assert.assertEquals(tax,
+// dbManager.getDynamicPropertiesStore().getTotalStorageTax());
+// Assert.assertEquals(currentReserved - 2561459696L,
+// dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+// Assert.assertEquals(currentPool + 2 * quant - tax,
+// dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+//
+// } catch (ContractValidateException e) {
+// Assert.assertFalse(e instanceof ContractValidateException);
+// } catch (ContractExeException e) {
+// Assert.assertFalse(e instanceof ContractExeException);
+// }
+// }
+
+ @Test
+ public void buyLessThanZero() {
+ long quant = -1_000_000_000L;
+ BuyStorageActuator actuator = new BuyStorageActuator(
+ getContract(OWNER_ADDRESS, quant), dbManager);
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+ try {
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.fail("cannot run here.");
+
+ } catch (ContractValidateException e) {
+ Assert.assertTrue(e instanceof ContractValidateException);
+ Assert.assertEquals("quantity must be positive", e.getMessage());
+ } catch (ContractExeException e) {
+ Assert.assertFalse(e instanceof ContractExeException);
+ }
+ }
+
@Test
- public void testBuyStorageTax() {
+ public void buyLessThan1Trx() {
+ long quant = 200_000L;
+ BuyStorageActuator actuator = new BuyStorageActuator(
+ getContract(OWNER_ADDRESS, quant), dbManager);
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+ try {
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.fail("cannot run here.");
+
+ } catch (ContractValidateException e) {
+ Assert.assertTrue(e instanceof ContractValidateException);
+ Assert.assertEquals("quantity must be larger than 1TRX", e.getMessage());
+ } catch (ContractExeException e) {
+ Assert.assertFalse(e instanceof ContractExeException);
+ }
+ }
+
+ @Test
+ public void buyLessThan1Byte() {
long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
Assert.assertEquals(currentPool, 100_000_000_000000L);
Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
- long quant = 1_000_000_000_000L; // 2 million trx
+ long quant = 9_000_000_000_000_000L; // 9 billion trx
BuyStorageActuator actuator = new BuyStorageActuator(
getContract(OWNER_ADDRESS, quant), dbManager);
TransactionResultCapsule ret = new TransactionResultCapsule();
BuyStorageActuator actuator2 = new BuyStorageActuator(
- getContract(OWNER_ADDRESS, quant), dbManager);
+ getContract(OWNER_ADDRESS, 1_000_000), dbManager);
TransactionResultCapsule ret2 = new TransactionResultCapsule();
try {
@@ -211,54 +303,24 @@ public void testBuyStorageTax() {
dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
Assert.assertEquals(owner.getBalance(), initBalance - quant
- ChainConstant.TRANSFER_FEE);
- Assert.assertEquals(1360781717L, owner.getStorageLimit());
- Assert.assertEquals(currentReserved - 1360781717L,
+ Assert.assertEquals(135928635301L, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - 135928635301L,
dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
Assert.assertEquals(currentPool + quant,
dbManager.getDynamicPropertiesStore().getTotalStoragePool());
- dbManager.getDynamicPropertiesStore()
- .saveLatestBlockHeaderTimestamp(365 * 24 * 3600 * 1000L);
actuator2.validate();
- actuator2.execute(ret);
- Assert.assertEquals(ret2.getInstance().getRet(), code.SUCESS);
- owner =
- dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
- Assert.assertEquals(owner.getBalance(), initBalance - 2 * quant
- - ChainConstant.TRANSFER_FEE);
- Assert.assertEquals(2561459696L, owner.getStorageLimit());
- long tax = 100899100225L;
- Assert.assertEquals(tax,
- dbManager.getDynamicPropertiesStore().getTotalStorageTax());
- Assert.assertEquals(currentReserved - 2561459696L,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(currentPool + 2 * quant - tax,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
-
- } catch (ContractValidateException e) {
- Assert.assertFalse(e instanceof ContractValidateException);
- } catch (ContractExeException e) {
- Assert.assertFalse(e instanceof ContractExeException);
- }
- }
-
- @Test
- public void buyLessThanZero() {
- long quant = -1_000_000_000L;
- BuyStorageActuator actuator = new BuyStorageActuator(
- getContract(OWNER_ADDRESS, quant), dbManager);
- TransactionResultCapsule ret = new TransactionResultCapsule();
- try {
- actuator.validate();
- actuator.execute(ret);
+ actuator2.execute(ret2);
Assert.fail("cannot run here.");
} catch (ContractValidateException e) {
Assert.assertTrue(e instanceof ContractValidateException);
- Assert.assertEquals("quantity must be positive", e.getMessage());
+ Assert.assertEquals("storage_bytes must be larger than 1,current storage_bytes[0]",
+ e.getMessage());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
}
+
}
@Test
diff --git a/src/test/java/org/tron/core/actuator/BuyStorageBytesActuatorTest.java b/src/test/java/org/tron/core/actuator/BuyStorageBytesActuatorTest.java
new file mode 100644
index 00000000000..a479439e7a7
--- /dev/null
+++ b/src/test/java/org/tron/core/actuator/BuyStorageBytesActuatorTest.java
@@ -0,0 +1,369 @@
+package org.tron.core.actuator;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.tron.common.application.TronApplicationContext;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.capsule.TransactionResultCapsule;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.Parameter.ChainConstant;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.protos.Contract;
+import org.tron.protos.Protocol.AccountType;
+import org.tron.protos.Protocol.Transaction.Result.code;
+
+@Slf4j
+public class BuyStorageBytesActuatorTest {
+
+ private static Manager dbManager;
+ private static final String dbPath = "output_buy_storage_bytes_test";
+ private static TronApplicationContext context;
+ private static final String OWNER_ADDRESS;
+ private static final String OWNER_ADDRESS_INVALID = "aaaa";
+ private static final String OWNER_ACCOUNT_INVALID;
+ private static final long initBalance = 10_000_000_000_000_000L;
+
+ static {
+ Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
+ context = new TronApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
+ OWNER_ACCOUNT_INVALID =
+ Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a3456";
+ }
+
+ /**
+ * Init data.
+ */
+ @BeforeClass
+ public static void init() {
+ dbManager = context.getBean(Manager.class);
+ // Args.setParam(new String[]{"--output-directory", dbPath},
+ // "config-junit.conf");
+ // dbManager = new Manager();
+ // dbManager.init();
+ }
+
+ /**
+ * Release resources.
+ */
+ @AfterClass
+ public static void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+
+ /**
+ * create temp Capsule test need.
+ */
+ @Before
+ public void createAccountCapsule() {
+ AccountCapsule ownerCapsule =
+ new AccountCapsule(
+ ByteString.copyFromUtf8("owner"),
+ ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)),
+ AccountType.Normal,
+ initBalance);
+ dbManager.getAccountStore().put(ownerCapsule.getAddress().toByteArray(), ownerCapsule);
+
+ dbManager.getDynamicPropertiesStore().saveTotalStorageReserved(
+ 128L * 1024 * 1024 * 1024);
+ dbManager.getDynamicPropertiesStore().saveTotalStoragePool(100_000_000_000000L);
+ dbManager.getDynamicPropertiesStore().saveTotalStorageTax(0);
+
+ dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(0);
+ }
+
+ private Any getContract(String ownerAddress, long bytes) {
+ return Any.pack(
+ Contract.BuyStorageBytesContract.newBuilder()
+ .setOwnerAddress(ByteString.copyFrom(ByteArray.fromHexString(ownerAddress)))
+ .setBytes(bytes)
+ .build());
+ }
+
+ @Test
+ public void testBuyStorageBytes() {
+ long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+ long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+ Assert.assertEquals(currentPool, 100_000_000_000000L);
+ Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+
+ long bytes = 2694881440L; // 2 million trx
+ long quant = 2_000_000_000_000L;
+ BuyStorageBytesActuator actuator = new BuyStorageBytesActuator(
+ getContract(OWNER_ADDRESS, bytes), dbManager);
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+ try {
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS);
+ AccountCapsule owner =
+ dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+
+ Assert.assertEquals(owner.getBalance(), initBalance - quant
+ - ChainConstant.TRANSFER_FEE);
+ Assert.assertEquals(2694881440L, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - 2694881440L,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + quant,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+ } catch (ContractValidateException e) {
+ Assert.assertFalse(e instanceof ContractValidateException);
+ } catch (ContractExeException e) {
+ Assert.assertFalse(e instanceof ContractExeException);
+ }
+ }
+
+ @Test
+ public void testBuyStorageBytes2() {
+ long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+ long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+ Assert.assertEquals(currentPool, 100_000_000_000000L);
+ Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+
+ long quant = 1_000_000_000_000L; // 1 million trx
+ long bytes1 = 1360781717L;
+ long bytes2 = 2694881439L - bytes1;
+
+ BuyStorageBytesActuator actuator = new BuyStorageBytesActuator(
+ getContract(OWNER_ADDRESS, bytes1), dbManager);
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+
+ BuyStorageBytesActuator actuator2 = new BuyStorageBytesActuator(
+ getContract(OWNER_ADDRESS, bytes2), dbManager);
+ TransactionResultCapsule ret2 = new TransactionResultCapsule();
+
+ try {
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS);
+ AccountCapsule owner =
+ dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+ Assert.assertEquals(owner.getBalance(), initBalance - quant
+ - ChainConstant.TRANSFER_FEE);
+ Assert.assertEquals(bytes1, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - bytes1,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + quant,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ actuator2.validate();
+ actuator2.execute(ret2);
+ Assert.assertEquals(ret2.getInstance().getRet(), code.SUCESS);
+ owner =
+ dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+ Assert.assertEquals(owner.getBalance(), initBalance - 2 * quant
+ - ChainConstant.TRANSFER_FEE);
+ Assert.assertEquals(bytes1 + bytes2, owner.getStorageLimit());
+ Assert.assertEquals(currentReserved - bytes1 - bytes2,
+ dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+ Assert.assertEquals(currentPool + 2 * quant,
+ dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+
+ } catch (ContractValidateException e) {
+ Assert.assertFalse(e instanceof ContractValidateException);
+ } catch (ContractExeException e) {
+ Assert.assertFalse(e instanceof ContractExeException);
+ }
+ }
+
+// @Test
+// public void testBuyStorageTax() {
+// long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+// long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+// Assert.assertEquals(currentPool, 100_000_000_000000L);
+// Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+//
+// long quant = 1_000_000_000_000L; // 2 million trx
+//
+// BuyStorageActuator actuator = new BuyStorageActuator(
+// getContract(OWNER_ADDRESS, quant), dbManager);
+// TransactionResultCapsule ret = new TransactionResultCapsule();
+//
+// BuyStorageActuator actuator2 = new BuyStorageActuator(
+// getContract(OWNER_ADDRESS, quant), dbManager);
+// TransactionResultCapsule ret2 = new TransactionResultCapsule();
+//
+// try {
+// actuator.validate();
+// actuator.execute(ret);
+// Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS);
+// AccountCapsule owner =
+// dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+// Assert.assertEquals(owner.getBalance(), initBalance - quant
+// - ChainConstant.TRANSFER_FEE);
+// Assert.assertEquals(1360781717L, owner.getStorageLimit());
+// Assert.assertEquals(currentReserved - 1360781717L,
+// dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+// Assert.assertEquals(currentPool + quant,
+// dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+//
+// dbManager.getDynamicPropertiesStore()
+// .saveLatestBlockHeaderTimestamp(365 * 24 * 3600 * 1000L);
+// actuator2.validate();
+// actuator2.execute(ret);
+// Assert.assertEquals(ret2.getInstance().getRet(), code.SUCESS);
+// owner =
+// dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+// Assert.assertEquals(owner.getBalance(), initBalance - 2 * quant
+// - ChainConstant.TRANSFER_FEE);
+// Assert.assertEquals(2561459696L, owner.getStorageLimit());
+// long tax = 100899100225L;
+// Assert.assertEquals(tax,
+// dbManager.getDynamicPropertiesStore().getTotalStorageTax());
+// Assert.assertEquals(currentReserved - 2561459696L,
+// dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+// Assert.assertEquals(currentPool + 2 * quant - tax,
+// dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+//
+// } catch (ContractValidateException e) {
+// Assert.assertFalse(e instanceof ContractValidateException);
+// } catch (ContractExeException e) {
+// Assert.assertFalse(e instanceof ContractExeException);
+// }
+// }
+
+ @Test
+ public void buyLessThanZero() {
+ long bytes = -1_000_000_000L;
+ BuyStorageBytesActuator actuator = new BuyStorageBytesActuator(
+ getContract(OWNER_ADDRESS, bytes), dbManager);
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+ try {
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.fail("cannot run here.");
+
+ } catch (ContractValidateException e) {
+ Assert.assertTrue(e instanceof ContractValidateException);
+ Assert.assertEquals("bytes must be positive", e.getMessage());
+ } catch (ContractExeException e) {
+ Assert.assertFalse(e instanceof ContractExeException);
+ }
+ }
+
+ @Test
+ public void buyLessThan1Byte() {
+ long bytes = 0L;
+ BuyStorageBytesActuator actuator = new BuyStorageBytesActuator(
+ getContract(OWNER_ADDRESS, bytes), dbManager);
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+ try {
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.fail("cannot run here.");
+
+ } catch (ContractValidateException e) {
+ Assert.assertTrue(e instanceof ContractValidateException);
+ Assert.assertEquals("bytes must be larger than 1, current storage_bytes[0]", e.getMessage());
+ } catch (ContractExeException e) {
+ Assert.assertFalse(e instanceof ContractExeException);
+ }
+ }
+
+ @Test
+ public void buyLessThan1Trx() {
+ long bytes = 1L;
+ BuyStorageBytesActuator actuator = new BuyStorageBytesActuator(
+ getContract(OWNER_ADDRESS, bytes), dbManager);
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+ try {
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.fail("cannot run here.");
+
+ } catch (ContractValidateException e) {
+ Assert.assertTrue(e instanceof ContractValidateException);
+ Assert.assertEquals("quantity must be larger than 1TRX", e.getMessage());
+ } catch (ContractExeException e) {
+ Assert.assertFalse(e instanceof ContractExeException);
+ }
+
+ }
+
+ @Test
+ public void buyMoreThanBalance() {
+ long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+ long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+ Assert.assertEquals(currentPool, 100_000_000_000000L);
+ Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+
+ long bytes = 136178171754L;
+
+ BuyStorageBytesActuator actuator = new BuyStorageBytesActuator(
+ getContract(OWNER_ADDRESS, bytes), dbManager);
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+
+ try {
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.fail("cannot run here.");
+ } catch (ContractValidateException e) {
+ Assert.assertTrue(e instanceof ContractValidateException);
+ Assert.assertEquals("quantity must be less than accountBalance", e.getMessage());
+ } catch (ContractExeException e) {
+ Assert.assertFalse(e instanceof ContractExeException);
+ }
+ }
+
+ @Test
+ public void invalidOwnerAddress() {
+ long bytes = 1_000_000_000L;
+ BuyStorageBytesActuator actuator = new BuyStorageBytesActuator(
+ getContract(OWNER_ADDRESS_INVALID, bytes), dbManager);
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+ try {
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.fail("cannot run here.");
+
+ } catch (ContractValidateException e) {
+ Assert.assertTrue(e instanceof ContractValidateException);
+
+ Assert.assertEquals("Invalid address", e.getMessage());
+
+ } catch (ContractExeException e) {
+ Assert.assertTrue(e instanceof ContractExeException);
+ }
+
+ }
+
+ @Test
+ public void invalidOwnerAccount() {
+ long bytes = 1_000_000_000L;
+ BuyStorageBytesActuator actuator = new BuyStorageBytesActuator(
+ getContract(OWNER_ACCOUNT_INVALID, bytes), dbManager);
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+ try {
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.fail("cannot run here.");
+ } catch (ContractValidateException e) {
+ Assert.assertTrue(e instanceof ContractValidateException);
+ Assert.assertEquals("Account[" + OWNER_ACCOUNT_INVALID + "] not exists",
+ e.getMessage());
+ } catch (ContractExeException e) {
+ Assert.assertFalse(e instanceof ContractExeException);
+ }
+ }
+
+}
diff --git a/src/test/java/org/tron/core/actuator/CreateAccountActuatorTest.java b/src/test/java/org/tron/core/actuator/CreateAccountActuatorTest.java
index 29d4e1ecb0b..6477d417a68 100755
--- a/src/test/java/org/tron/core/actuator/CreateAccountActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/CreateAccountActuatorTest.java
@@ -9,7 +9,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.common.utils.StringUtil;
@@ -29,7 +29,7 @@
@Slf4j
public class CreateAccountActuatorTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static final String dbPath = "output_CreateAccount_test";
private static final String OWNER_ADDRESS_FIRST;
@@ -38,7 +38,7 @@ public class CreateAccountActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS_FIRST =
Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
OWNER_ADDRESS_SECOND =
diff --git a/src/test/java/org/tron/core/actuator/FreezeBalanceActuatorTest.java b/src/test/java/org/tron/core/actuator/FreezeBalanceActuatorTest.java
index 3bbca885a4f..1bcd76e53e1 100644
--- a/src/test/java/org/tron/core/actuator/FreezeBalanceActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/FreezeBalanceActuatorTest.java
@@ -11,7 +11,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -33,7 +33,7 @@ public class FreezeBalanceActuatorTest {
private static Manager dbManager;
private static final String dbPath = "output_freeze_balance_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static final String OWNER_ADDRESS;
private static final String OWNER_ADDRESS_INVALID = "aaaa";
private static final String OWNER_ACCOUNT_INVALID;
@@ -41,7 +41,7 @@ public class FreezeBalanceActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
OWNER_ACCOUNT_INVALID =
Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a3456";
diff --git a/src/test/java/org/tron/core/actuator/ParticipateAssetIssueActuatorTest.java b/src/test/java/org/tron/core/actuator/ParticipateAssetIssueActuatorTest.java
index e648e8417cb..effb63cb437 100755
--- a/src/test/java/org/tron/core/actuator/ParticipateAssetIssueActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/ParticipateAssetIssueActuatorTest.java
@@ -11,7 +11,7 @@
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -34,7 +34,7 @@ public class ParticipateAssetIssueActuatorTest {
private static final Logger logger = LoggerFactory.getLogger("Test");
private static Manager dbManager;
private static final String dbPath = "output_participateAsset_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static final String OWNER_ADDRESS;
private static final String TO_ADDRESS;
private static final String THIRD_ADDRESS;
@@ -51,7 +51,7 @@ public class ParticipateAssetIssueActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
TO_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
THIRD_ADDRESS = Wallet.getAddressPreFixString() + "4948c2e8a756d9437037dcd8c7e0c73d560ca38d";
diff --git a/src/test/java/org/tron/core/actuator/ProposalApproveActuatorTest.java b/src/test/java/org/tron/core/actuator/ProposalApproveActuatorTest.java
index 6f228dec09d..3e73073381e 100644
--- a/src/test/java/org/tron/core/actuator/ProposalApproveActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/ProposalApproveActuatorTest.java
@@ -12,7 +12,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.common.utils.StringUtil;
@@ -37,7 +37,7 @@
public class ProposalApproveActuatorTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static final String dbPath = "output_ProposalApprove_test";
private static final String ACCOUNT_NAME_FIRST = "ownerF";
@@ -50,7 +50,7 @@ public class ProposalApproveActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS_FIRST =
Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
OWNER_ADDRESS_SECOND =
diff --git a/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java b/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java
index 164d100e967..e0d26253fde 100644
--- a/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/ProposalCreateActuatorTest.java
@@ -12,7 +12,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -35,7 +35,7 @@
public class ProposalCreateActuatorTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static final String dbPath = "output_ProposalCreate_test";
private static final String ACCOUNT_NAME_FIRST = "ownerF";
@@ -49,7 +49,7 @@ public class ProposalCreateActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS_FIRST =
Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
OWNER_ADDRESS_SECOND =
@@ -263,6 +263,34 @@ public void invalidPara() {
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
}
+
+ paras = new HashMap<>();
+ paras.put(10L, -1L);
+ actuator =
+ new ProposalCreateActuator(getContract(OWNER_ADDRESS_FIRST, paras), dbManager);
+ dbManager.getDynamicPropertiesStore().saveRemoveThePowerOfTheGr(-1);
+ try {
+ actuator.validate();
+ fail("This proposal has been executed before and is only allowed to be executed once");
+ } catch (ContractValidateException e) {
+ Assert.assertTrue(e instanceof ContractValidateException);
+ Assert.assertEquals("This proposal has been executed before and is only allowed to be executed once",
+ e.getMessage());
+ }
+
+ paras.put(10L, -1L);
+ dbManager.getDynamicPropertiesStore().saveRemoveThePowerOfTheGr(0);
+ actuator =
+ new ProposalCreateActuator(getContract(OWNER_ADDRESS_FIRST, paras), dbManager);
+ dbManager.getDynamicPropertiesStore().saveRemoveThePowerOfTheGr(0);
+ try {
+ actuator.validate();
+ fail("This value[REMOVE_THE_POWER_OF_THE_GR] is only allowed to be 1");
+ } catch (ContractValidateException e) {
+ Assert.assertTrue(e instanceof ContractValidateException);
+ Assert.assertEquals("This value[REMOVE_THE_POWER_OF_THE_GR] is only allowed to be 1",
+ e.getMessage());
+ }
}
}
\ No newline at end of file
diff --git a/src/test/java/org/tron/core/actuator/ProposalDeleteActuatorTest.java b/src/test/java/org/tron/core/actuator/ProposalDeleteActuatorTest.java
index 74aa9dfeec1..49db73576b8 100644
--- a/src/test/java/org/tron/core/actuator/ProposalDeleteActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/ProposalDeleteActuatorTest.java
@@ -12,7 +12,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.common.utils.StringUtil;
@@ -37,7 +37,7 @@
public class ProposalDeleteActuatorTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static final String dbPath = "output_ProposalApprove_test";
private static final String ACCOUNT_NAME_FIRST = "ownerF";
@@ -50,7 +50,7 @@ public class ProposalDeleteActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS_FIRST =
Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
OWNER_ADDRESS_SECOND =
diff --git a/src/test/java/org/tron/core/actuator/SellStorageActuatorTest.java b/src/test/java/org/tron/core/actuator/SellStorageActuatorTest.java
index 4e4be4f7ec8..076a7db89dd 100644
--- a/src/test/java/org/tron/core/actuator/SellStorageActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/SellStorageActuatorTest.java
@@ -9,7 +9,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -31,7 +31,7 @@ public class SellStorageActuatorTest {
private static Manager dbManager;
private static final String dbPath = "output_sell_storage_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static final String OWNER_ADDRESS;
private static final String OWNER_ADDRESS_INVALID = "aaaa";
private static final String OWNER_ACCOUNT_INVALID;
@@ -39,7 +39,7 @@ public class SellStorageActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
OWNER_ACCOUNT_INVALID =
Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a3456";
@@ -151,11 +151,11 @@ public void testSellStorage() {
dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
// TODO: more precise
- Assert.assertEquals(owner.getBalance(), 9999999999999496L);
+ Assert.assertEquals(owner.getBalance(), initBalance);
Assert.assertEquals(0, owner.getStorageLimit());
Assert.assertEquals(currentReserved,
dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(100000000000504L,
+ Assert.assertEquals(100000000000000L,
dbManager.getDynamicPropertiesStore().getTotalStoragePool());
} catch (ContractValidateException e) {
logger.info(e.getMessage());
@@ -213,11 +213,11 @@ public void testSellStorage2() {
Assert.assertEquals(ret1.getInstance().getRet(), code.SUCESS);
AccountCapsule owner =
dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
- Assert.assertEquals(owner.getBalance(), 9998999999999882L);
+ Assert.assertEquals(owner.getBalance(), initBalance - 1_000_000_000_000L);
Assert.assertEquals(1360781717L, owner.getStorageLimit());
Assert.assertEquals(currentReserved - 1360781717L,
dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(101000000000118L,
+ Assert.assertEquals(101000000000000L,
dbManager.getDynamicPropertiesStore().getTotalStoragePool());
sellStorageActuator2.validate();
@@ -225,14 +225,14 @@ public void testSellStorage2() {
Assert.assertEquals(ret2.getInstance().getRet(), code.SUCESS);
owner =
dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
- Assert.assertEquals(owner.getBalance(), 9999999999999288L);
+ Assert.assertEquals(owner.getBalance(), initBalance);
Assert.assertEquals(0, owner.getStorageLimit());
long tax = 0L;
Assert.assertEquals(tax,
dbManager.getDynamicPropertiesStore().getTotalStorageTax());
Assert.assertEquals(currentReserved,
dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(100000000000712L,
+ Assert.assertEquals(100000000000000L,
dbManager.getDynamicPropertiesStore().getTotalStoragePool());
} catch (ContractValidateException e) {
@@ -242,8 +242,88 @@ public void testSellStorage2() {
}
}
+// @Test
+// public void testSellStorageTax() {
+// long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
+// long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
+// Assert.assertEquals(currentPool, 100_000_000_000000L);
+// Assert.assertEquals(currentReserved, 128L * 1024 * 1024 * 1024);
+//
+// long quant = 2_000_000_000_000L; // 2 million trx
+// BuyStorageActuator buyStorageactuator = new BuyStorageActuator(
+// getBuyContract(OWNER_ADDRESS, quant), dbManager);
+// TransactionResultCapsule ret = new TransactionResultCapsule();
+// try {
+// buyStorageactuator.validate();
+// buyStorageactuator.execute(ret);
+// Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS);
+// AccountCapsule owner =
+// dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+//
+// Assert.assertEquals(owner.getBalance(), initBalance - quant
+// - ChainConstant.TRANSFER_FEE);
+// Assert.assertEquals(2694881440L, owner.getStorageLimit());
+// Assert.assertEquals(currentReserved - 2694881440L,
+// dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+// Assert.assertEquals(currentPool + quant,
+// dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+// } catch (ContractValidateException e) {
+// Assert.assertFalse(e instanceof ContractValidateException);
+// } catch (ContractExeException e) {
+// Assert.assertFalse(e instanceof ContractExeException);
+// }
+//
+// dbManager.getDynamicPropertiesStore()
+// .saveLatestBlockHeaderTimestamp(365 * 24 * 3600 * 1000L);
+// long bytes = 2694881440L - 269488144L;
+// SellStorageActuator sellStorageActuator = new SellStorageActuator(
+// getContract(OWNER_ADDRESS, bytes), dbManager);
+// TransactionResultCapsule ret2 = new TransactionResultCapsule();
+// try {
+// sellStorageActuator.validate();
+// sellStorageActuator.execute(ret);
+// Assert.assertEquals(ret2.getInstance().getRet(), code.SUCESS);
+// AccountCapsule owner =
+// dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
+//
+// Assert.assertEquals(owner.getBalance(), 9999796407185160L);
+// Assert.assertEquals(0, owner.getStorageLimit());
+// long tax = 10_000_000_000_000_000L + 100_000_000_000_000L
+// - 9999796407185160L - 100000000000550L; // == 203592814290L
+// Assert.assertEquals(currentReserved,
+// dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
+// Assert.assertEquals(100000000000550L,
+// dbManager.getDynamicPropertiesStore().getTotalStoragePool());
+// Assert.assertEquals(tax,
+// dbManager.getDynamicPropertiesStore().getTotalStorageTax());
+// } catch (ContractValidateException e) {
+// Assert.assertFalse(e instanceof ContractValidateException);
+// } catch (ContractExeException e) {
+// Assert.assertFalse(e instanceof ContractExeException);
+// }
+// }
+
+ @Test
+ public void sellLessThanZero() {
+ long bytes = -1_000_000_000L;
+ SellStorageActuator actuator = new SellStorageActuator(
+ getContract(OWNER_ADDRESS, bytes), dbManager);
+ TransactionResultCapsule ret = new TransactionResultCapsule();
+ try {
+ actuator.validate();
+ actuator.execute(ret);
+ Assert.fail("cannot run here.");
+
+ } catch (ContractValidateException e) {
+ Assert.assertTrue(e instanceof ContractValidateException);
+ Assert.assertEquals("bytes must be positive", e.getMessage());
+ } catch (ContractExeException e) {
+ Assert.assertFalse(e instanceof ContractExeException);
+ }
+ }
+
@Test
- public void testSellStorageTax() {
+ public void sellLessThan1Trx() {
long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
Assert.assertEquals(currentPool, 100_000_000_000000L);
@@ -273,57 +353,25 @@ public void testSellStorageTax() {
Assert.assertFalse(e instanceof ContractExeException);
}
- dbManager.getDynamicPropertiesStore()
- .saveLatestBlockHeaderTimestamp(365 * 24 * 3600 * 1000L);
- long bytes = 2694881440L - 269488144L;
+ long bytes = 1200L;
SellStorageActuator sellStorageActuator = new SellStorageActuator(
getContract(OWNER_ADDRESS, bytes), dbManager);
TransactionResultCapsule ret2 = new TransactionResultCapsule();
try {
sellStorageActuator.validate();
- sellStorageActuator.execute(ret);
- Assert.assertEquals(ret2.getInstance().getRet(), code.SUCESS);
- AccountCapsule owner =
- dbManager.getAccountStore().get(ByteArray.fromHexString(OWNER_ADDRESS));
-
- Assert.assertEquals(owner.getBalance(), 9999796407185160L);
- Assert.assertEquals(0, owner.getStorageLimit());
- long tax = 10_000_000_000_000_000L + 100_000_000_000_000L
- - 9999796407185160L - 100000000000550L; // == 203592814290L
- Assert.assertEquals(currentReserved,
- dbManager.getDynamicPropertiesStore().getTotalStorageReserved());
- Assert.assertEquals(100000000000550L,
- dbManager.getDynamicPropertiesStore().getTotalStoragePool());
- Assert.assertEquals(tax,
- dbManager.getDynamicPropertiesStore().getTotalStorageTax());
- } catch (ContractValidateException e) {
- Assert.assertFalse(e instanceof ContractValidateException);
- } catch (ContractExeException e) {
- Assert.assertFalse(e instanceof ContractExeException);
- }
- }
-
- @Test
- public void sellLessThanZero() {
- long bytes = -1_000_000_000L;
- SellStorageActuator actuator = new SellStorageActuator(
- getContract(OWNER_ADDRESS, bytes), dbManager);
- TransactionResultCapsule ret = new TransactionResultCapsule();
- try {
- actuator.validate();
- actuator.execute(ret);
+ sellStorageActuator.execute(ret2);
Assert.fail("cannot run here.");
-
} catch (ContractValidateException e) {
Assert.assertTrue(e instanceof ContractValidateException);
- Assert.assertEquals("bytes must be positive", e.getMessage());
+ Assert.assertEquals("quantity must be larger than 1TRX,current quantity[900000]",
+ e.getMessage());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
}
}
@Test
- public void buyMoreThanLimit() {
+ public void sellMoreThanLimit() {
long currentPool = dbManager.getDynamicPropertiesStore().getTotalStoragePool();
long currentReserved = dbManager.getDynamicPropertiesStore().getTotalStorageReserved();
Assert.assertEquals(currentPool, 100_000_000_000000L);
@@ -353,19 +401,17 @@ public void buyMoreThanLimit() {
Assert.assertFalse(e instanceof ContractExeException);
}
- dbManager.getDynamicPropertiesStore()
- .saveLatestBlockHeaderTimestamp(365 * 24 * 3600 * 1000L);
- long bytes = 2694881440L - 269488143L;
+ long bytes = 2694881441L;
SellStorageActuator sellStorageActuator = new SellStorageActuator(
getContract(OWNER_ADDRESS, bytes), dbManager);
TransactionResultCapsule ret2 = new TransactionResultCapsule();
try {
sellStorageActuator.validate();
- sellStorageActuator.execute(ret);
+ sellStorageActuator.execute(ret2);
Assert.fail("cannot run here.");
} catch (ContractValidateException e) {
Assert.assertTrue(e instanceof ContractValidateException);
- Assert.assertEquals("bytes must be less than currentUnusedStorage minus tax",
+ Assert.assertEquals("bytes must be less than currentUnusedStorage[2694881440]",
e.getMessage());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
diff --git a/src/test/java/org/tron/core/actuator/SetAccountIdActuatorTest.java b/src/test/java/org/tron/core/actuator/SetAccountIdActuatorTest.java
index 511435b0ddf..f129f1bd265 100644
--- a/src/test/java/org/tron/core/actuator/SetAccountIdActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/SetAccountIdActuatorTest.java
@@ -9,7 +9,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -28,7 +28,7 @@
@Slf4j
public class SetAccountIdActuatorTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static final String dbPath = "output_setaccountid_test";
private static final String ACCOUNT_NAME = "ownertest";
@@ -39,7 +39,7 @@ public class SetAccountIdActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
OWNER_ADDRESS_1 = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
}
diff --git a/src/test/java/org/tron/core/actuator/TransferActuatorTest.java b/src/test/java/org/tron/core/actuator/TransferActuatorTest.java
index 32d4420be6f..b55309b5650 100755
--- a/src/test/java/org/tron/core/actuator/TransferActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/TransferActuatorTest.java
@@ -12,7 +12,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -34,7 +34,7 @@ public class TransferActuatorTest {
private static Manager dbManager;
private static final String dbPath = "output_transfer_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static final String OWNER_ADDRESS;
private static final String TO_ADDRESS;
private static final long AMOUNT = 100;
@@ -48,7 +48,7 @@ public class TransferActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
TO_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
OWNER_ACCOUNT_INVALID =
diff --git a/src/test/java/org/tron/core/actuator/TransferAssetActuatorTest.java b/src/test/java/org/tron/core/actuator/TransferAssetActuatorTest.java
index 4a99435b474..94b445ec1b2 100755
--- a/src/test/java/org/tron/core/actuator/TransferAssetActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/TransferAssetActuatorTest.java
@@ -26,7 +26,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -47,7 +47,7 @@
@Slf4j
public class TransferAssetActuatorTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static Any contract;
private static final String dbPath = "output_transferasset_test";
@@ -72,7 +72,7 @@ public class TransferAssetActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049150";
TO_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a146a";
NOT_EXIT_ADDRESS = Wallet.getAddressPreFixString() + "B56446E617E924805E4D6CA021D341FEF6E2013B";
@@ -583,7 +583,6 @@ public void assetNameTest() {
Assert.assertFalse(e instanceof ContractExeException);
}
-
//Too long name, throw exception. Max long is 32.
String assetName = "testname0123456789abcdefghijgklmo";
// actuator = new TransferAssetActuator(getContract(100L, assetName),
diff --git a/src/test/java/org/tron/core/actuator/UnfreezeAssetActuatorTest.java b/src/test/java/org/tron/core/actuator/UnfreezeAssetActuatorTest.java
index dff94f464d7..dda5e00fce9 100644
--- a/src/test/java/org/tron/core/actuator/UnfreezeAssetActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/UnfreezeAssetActuatorTest.java
@@ -9,7 +9,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.common.utils.StringUtil;
@@ -33,7 +33,7 @@ public class UnfreezeAssetActuatorTest {
private static Manager dbManager;
private static final String dbPath = "output_unfreeze_asset_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static final String OWNER_ADDRESS;
private static final String OWNER_ADDRESS_INVALID = "aaaa";
private static final String OWNER_ACCOUNT_INVALID;
@@ -43,7 +43,7 @@ public class UnfreezeAssetActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
OWNER_ACCOUNT_INVALID =
Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a3456";
@@ -105,8 +105,8 @@ public void testUnfreezeAsset() {
.setExpireTime(now)
.build();
Frozen newFrozen1 = Frozen.newBuilder()
- .setFrozenBalance(frozenBalance+1)
- .setExpireTime(now+600000)
+ .setFrozenBalance(frozenBalance + 1)
+ .setExpireTime(now + 600000)
.build();
account = account.toBuilder().addFrozenSupply(newFrozen0).addFrozenSupply(newFrozen1).build();
AccountCapsule accountCapsule = new AccountCapsule(account);
diff --git a/src/test/java/org/tron/core/actuator/UnfreezeBalanceActuatorTest.java b/src/test/java/org/tron/core/actuator/UnfreezeBalanceActuatorTest.java
index 364971b49f7..970d049b386 100644
--- a/src/test/java/org/tron/core/actuator/UnfreezeBalanceActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/UnfreezeBalanceActuatorTest.java
@@ -13,7 +13,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -36,7 +36,7 @@ public class UnfreezeBalanceActuatorTest {
private static Manager dbManager;
private static final String dbPath = "output_unfreeze_balance_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static final String OWNER_ADDRESS;
private static final String OWNER_ADDRESS_INVALID = "aaaa";
private static final String OWNER_ACCOUNT_INVALID;
@@ -45,7 +45,7 @@ public class UnfreezeBalanceActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
OWNER_ACCOUNT_INVALID =
Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a3456";
diff --git a/src/test/java/org/tron/core/actuator/UpdateAccountActuatorTest.java b/src/test/java/org/tron/core/actuator/UpdateAccountActuatorTest.java
index dad76eabe2a..a2749787171 100755
--- a/src/test/java/org/tron/core/actuator/UpdateAccountActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/UpdateAccountActuatorTest.java
@@ -9,7 +9,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -28,7 +28,7 @@
@Slf4j
public class UpdateAccountActuatorTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static final String dbPath = "output_updateaccount_test";
private static final String ACCOUNT_NAME = "ownerTest";
@@ -39,7 +39,7 @@ public class UpdateAccountActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
OWNER_ADDRESS_1 = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
}
diff --git a/src/test/java/org/tron/core/actuator/VoteWitnessActuatorTest.java b/src/test/java/org/tron/core/actuator/VoteWitnessActuatorTest.java
index d836136f462..5da02787d3b 100644
--- a/src/test/java/org/tron/core/actuator/VoteWitnessActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/VoteWitnessActuatorTest.java
@@ -11,7 +11,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.common.utils.StringUtil;
@@ -35,7 +35,7 @@
@Slf4j
public class VoteWitnessActuatorTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static WitnessController witnessController;
private static final String dbPath = "output_VoteWitness_test";
@@ -51,7 +51,7 @@ public class VoteWitnessActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
WITNESS_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
WITNESS_ADDRESS_NOACCOUNT =
@@ -156,8 +156,9 @@ public void voteWitness() {
.get(0).getVoteAddress().toByteArray());
Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS);
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
- Assert.assertEquals(10+1, witnessCapsule.getVoteCount());
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ Assert.assertEquals(10 + 1, witnessCapsule.getVoteCount());
} catch (ContractValidateException e) {
Assert.assertFalse(e instanceof ContractValidateException);
} catch (ContractExeException e) {
@@ -182,7 +183,8 @@ public void InvalidAddress() {
Assert.assertTrue(e instanceof ContractValidateException);
Assert.assertEquals("Invalid address", e.getMessage());
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
Assert.assertEquals(10, witnessCapsule.getVoteCount());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
@@ -210,7 +212,8 @@ public void noAccount() {
Assert.assertTrue(e instanceof ContractValidateException);
Assert.assertEquals("Account[" + WITNESS_ADDRESS_NOACCOUNT + "] not exists", e.getMessage());
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
Assert.assertEquals(10, witnessCapsule.getVoteCount());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
@@ -246,7 +249,8 @@ public void noWitness() {
Assert.assertTrue(e instanceof ContractValidateException);
Assert.assertEquals("Witness[" + WITNESS_ADDRESS_NOACCOUNT + "] not exists", e.getMessage());
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
Assert.assertEquals(10, witnessCapsule.getVoteCount());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
@@ -280,7 +284,8 @@ public void invalideVoteAddress() {
Assert.assertTrue(e instanceof ContractValidateException);
Assert.assertEquals("Invalid vote address!", e.getMessage());
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
Assert.assertEquals(10, witnessCapsule.getVoteCount());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
@@ -310,7 +315,8 @@ public void voteCountTest() {
Assert.assertTrue(e instanceof ContractValidateException);
Assert.assertEquals("vote count must be greater than 0", e.getMessage());
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
Assert.assertEquals(10, witnessCapsule.getVoteCount());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
@@ -328,7 +334,8 @@ public void voteCountTest() {
Assert.assertTrue(e instanceof ContractValidateException);
Assert.assertEquals("vote count must be greater than 0", e.getMessage());
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
Assert.assertEquals(10, witnessCapsule.getVoteCount());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
@@ -358,7 +365,8 @@ public void voteCountsTest() {
Assert.assertTrue(e instanceof ContractValidateException);
Assert.assertEquals("VoteNumber must more than 0", e.getMessage());
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
Assert.assertEquals(10, witnessCapsule.getVoteCount());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
@@ -374,7 +382,8 @@ public void voteCountsTest() {
Assert.assertTrue(e instanceof ContractValidateException);
Assert.assertEquals("VoteNumber more than maxVoteNumber 30", e.getMessage());
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
Assert.assertEquals(10, witnessCapsule.getVoteCount());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
@@ -401,8 +410,9 @@ public void vote1WitnssOneMoreTiems() {
actuator.execute(ret);
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
- Assert.assertEquals(10+30, witnessCapsule.getVoteCount());
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ Assert.assertEquals(10 + 30, witnessCapsule.getVoteCount());
} catch (ContractValidateException e) {
Assert.assertFalse(e instanceof ContractValidateException);
} catch (ContractExeException e) {
@@ -428,7 +438,8 @@ public void noOwnerAccount() {
Assert.assertTrue(e instanceof ContractValidateException);
Assert.assertEquals("Account[" + OWNER_ADDRESS_NOACCOUNT + "] not exists", e.getMessage());
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
Assert.assertEquals(10, witnessCapsule.getVoteCount());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
@@ -450,7 +461,8 @@ public void balanceNotSufficient() {
dbManager.getAccountStore()
.put(balanceNotSufficientCapsule.getAddress().toByteArray(), balanceNotSufficientCapsule);
VoteWitnessActuator actuator =
- new VoteWitnessActuator(getContract(OWNER_ADDRESS_BALANCENOTSUFFICIENT, WITNESS_ADDRESS, 1L),
+ new VoteWitnessActuator(
+ getContract(OWNER_ADDRESS_BALANCENOTSUFFICIENT, WITNESS_ADDRESS, 1L),
dbManager);
TransactionResultCapsule ret = new TransactionResultCapsule();
try {
@@ -466,7 +478,8 @@ public void balanceNotSufficient() {
.assertEquals("The total number of votes[" + 1000000 + "] is greater than the tronPower["
+ balanceNotSufficientCapsule.getTronPower() + "]", e.getMessage());
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
Assert.assertEquals(10, witnessCapsule.getVoteCount());
} catch (ContractExeException e) {
Assert.assertFalse(e instanceof ContractExeException);
@@ -503,7 +516,8 @@ public void voteWitnessTwice() {
Assert.assertEquals(ret.getInstance().getRet(), code.SUCESS);
witnessController.updateWitness();
- WitnessCapsule witnessCapsule = witnessController.getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
+ WitnessCapsule witnessCapsule = witnessController
+ .getWitnesseByAddress(StringUtil.hexString2ByteString(WITNESS_ADDRESS));
Assert.assertEquals(13, witnessCapsule.getVoteCount());
} catch (ContractValidateException e) {
Assert.assertFalse(e instanceof ContractValidateException);
diff --git a/src/test/java/org/tron/core/actuator/WithdrawBalanceActuatorTest.java b/src/test/java/org/tron/core/actuator/WithdrawBalanceActuatorTest.java
index fc7fea5e8aa..cbc9cd13c58 100644
--- a/src/test/java/org/tron/core/actuator/WithdrawBalanceActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/WithdrawBalanceActuatorTest.java
@@ -11,7 +11,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.common.utils.StringUtil;
@@ -36,7 +36,7 @@ public class WithdrawBalanceActuatorTest {
private static Manager dbManager;
private static final String dbPath = "output_withdraw_balance_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static final String OWNER_ADDRESS;
private static final String OWNER_ADDRESS_INVALID = "aaaa";
private static final String OWNER_ACCOUNT_INVALID;
@@ -45,7 +45,7 @@ public class WithdrawBalanceActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
OWNER_ACCOUNT_INVALID =
Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a3456";
diff --git a/src/test/java/org/tron/core/actuator/WitnessCreateActuatorTest.java b/src/test/java/org/tron/core/actuator/WitnessCreateActuatorTest.java
index ff4360936b7..991ee9dd167 100644
--- a/src/test/java/org/tron/core/actuator/WitnessCreateActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/WitnessCreateActuatorTest.java
@@ -11,7 +11,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -32,7 +32,7 @@
public class WitnessCreateActuatorTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static final String dbPath = "output_WitnessCreate_test";
private static final String ACCOUNT_NAME_FIRST = "ownerF";
@@ -46,7 +46,7 @@ public class WitnessCreateActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS_FIRST =
Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
OWNER_ADDRESS_SECOND =
diff --git a/src/test/java/org/tron/core/actuator/WitnessUpdateActuatorTest.java b/src/test/java/org/tron/core/actuator/WitnessUpdateActuatorTest.java
index 033dcbe85ad..b0b5c2dbe36 100644
--- a/src/test/java/org/tron/core/actuator/WitnessUpdateActuatorTest.java
+++ b/src/test/java/org/tron/core/actuator/WitnessUpdateActuatorTest.java
@@ -11,7 +11,7 @@
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -31,7 +31,7 @@
@Slf4j
public class WitnessUpdateActuatorTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static final String dbPath = "output_WitnessUpdate_test";
private static final String OWNER_ADDRESS;
@@ -45,7 +45,7 @@ public class WitnessUpdateActuatorTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
OWNER_ADDRESS = Wallet.getAddressPreFixString() + "abd4b9367799eaa3197fecb144eb71de1e049abc";
OWNER_ADDRESS_NOTEXIST =
Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
@@ -68,10 +68,10 @@ public static void init() {
public void createCapsule() {
// address in accountStore and witnessStore
AccountCapsule accountCapsule =
- new AccountCapsule(
- ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)),
- ByteString.copyFromUtf8(OWNER_ADDRESS_ACCOUNT_NAME),
- Protocol.AccountType.Normal);
+ new AccountCapsule(
+ ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)),
+ ByteString.copyFromUtf8(OWNER_ADDRESS_ACCOUNT_NAME),
+ Protocol.AccountType.Normal);
dbManager.getAccountStore().put(ByteArray.fromHexString(OWNER_ADDRESS), accountCapsule);
WitnessCapsule ownerCapsule = new WitnessCapsule(
ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS)), 10_000_000L, URL);
@@ -79,11 +79,12 @@ public void createCapsule() {
// address exist in accountStore, but is not witness
AccountCapsule accountNotWitnessCapsule =
- new AccountCapsule(
- ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_NOT_WITNESS)),
- ByteString.copyFromUtf8(OWNER_ADDRESS_NOT_WITNESS_ACCOUNT_NAME),
- Protocol.AccountType.Normal);
- dbManager.getAccountStore().put(ByteArray.fromHexString(OWNER_ADDRESS_NOT_WITNESS), accountNotWitnessCapsule);
+ new AccountCapsule(
+ ByteString.copyFrom(ByteArray.fromHexString(OWNER_ADDRESS_NOT_WITNESS)),
+ ByteString.copyFromUtf8(OWNER_ADDRESS_NOT_WITNESS_ACCOUNT_NAME),
+ Protocol.AccountType.Normal);
+ dbManager.getAccountStore()
+ .put(ByteArray.fromHexString(OWNER_ADDRESS_NOT_WITNESS), accountNotWitnessCapsule);
dbManager.getWitnessStore().delete(ByteArray.fromHexString(OWNER_ADDRESS_NOT_WITNESS));
// address does not exist in accountStore
@@ -221,8 +222,8 @@ public void InvalidUrlTest() {
}
/**
- * use AccountStore not exists Address createWitness,result is failed,exception is
- * "Witness does not exist"
+ * use AccountStore not exists Address createWitness,result is failed,exception is "Witness does
+ * not exist"
*/
@Test
public void notExistWitness() {
@@ -247,7 +248,7 @@ public void notExistWitness() {
@Test
public void notExistAccount() {
WitnessUpdateActuator actuator = new WitnessUpdateActuator(
- getContract(OWNER_ADDRESS_NOTEXIST, URL), dbManager);
+ getContract(OWNER_ADDRESS_NOTEXIST, URL), dbManager);
TransactionResultCapsule ret = new TransactionResultCapsule();
try {
actuator.validate();
diff --git a/src/test/java/org/tron/core/capsule/ExchangeCapsuleTest.java b/src/test/java/org/tron/core/capsule/ExchangeCapsuleTest.java
new file mode 100644
index 00000000000..11ed3007745
--- /dev/null
+++ b/src/test/java/org/tron/core/capsule/ExchangeCapsuleTest.java
@@ -0,0 +1,125 @@
+package org.tron.core.capsule;
+
+import com.google.protobuf.ByteString;
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+import org.tron.core.db.Manager;
+import org.tron.core.db.StorageMarket;
+import org.tron.core.exception.ItemNotFoundException;
+
+@Slf4j
+public class ExchangeCapsuleTest {
+
+ private static Manager dbManager;
+ private static StorageMarket storageMarket;
+ private static final String dbPath = "output_buy_storage_test";
+ private static AnnotationConfigApplicationContext context;
+ private static final String OWNER_ADDRESS;
+ private static final String OWNER_ADDRESS_INVALID = "aaaa";
+ private static final String OWNER_ACCOUNT_INVALID;
+ private static final long initBalance = 10_000_000_000_000_000L;
+
+ static {
+ Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
+ context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
+ OWNER_ACCOUNT_INVALID =
+ Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a3456";
+ }
+
+ /**
+ * Init data.
+ */
+ @BeforeClass
+ public static void init() {
+ dbManager = context.getBean(Manager.class);
+ storageMarket = new StorageMarket(dbManager);
+ // Args.setParam(new String[]{"--output-directory", dbPath},
+ // "config-junit.conf");
+ // dbManager = new Manager();
+ // dbManager.init();
+ }
+
+ /**
+ * Release resources.
+ */
+ @AfterClass
+ public static void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+
+ /**
+ * create temp Capsule test need.
+ */
+ @Before
+ public void createExchangeCapsule() {
+ dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(0);
+
+ long now = dbManager.getHeadBlockTimeStamp();
+ ExchangeCapsule exchangeCapsulee =
+ new ExchangeCapsule(
+ ByteString.copyFromUtf8("owner"),
+ 1,
+ now,
+ "abc".getBytes(),
+ "def".getBytes());
+
+ dbManager.getExchangeStore().put(exchangeCapsulee.createDbKey(), exchangeCapsulee);
+
+ }
+
+ @Test
+ public void testExchange() {
+ long sellBalance = 100000000L;
+ long buyBalance = 100000000L;
+
+ byte[] key = ByteArray.fromLong(1);
+
+ ExchangeCapsule exchangeCapsule;
+ try {
+ exchangeCapsule = dbManager.getExchangeStore().get(key);
+ exchangeCapsule.setBalance(sellBalance, buyBalance);
+
+ long sellQuant = 1_000_000L;
+ byte[] sellID = "abc".getBytes();
+
+ long result = exchangeCapsule.transaction(sellID, sellQuant);
+ Assert.assertEquals(990_099L, result);
+ sellBalance += sellQuant;
+ Assert.assertEquals(sellBalance, exchangeCapsule.getFirstTokenBalance());
+ buyBalance -= result;
+ Assert.assertEquals(buyBalance, exchangeCapsule.getSecondTokenBalance());
+
+ sellQuant = 9_000_000L;
+ long result2 = exchangeCapsule.transaction(sellID, sellQuant);
+ Assert.assertEquals(9090909L, result + result2);
+ sellBalance += sellQuant;
+ Assert.assertEquals(sellBalance, exchangeCapsule.getFirstTokenBalance());
+ buyBalance -= result2;
+ Assert.assertEquals(buyBalance, exchangeCapsule.getSecondTokenBalance());
+
+ } catch (ItemNotFoundException e) {
+ Assert.fail();
+ }
+
+ }
+
+}
diff --git a/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java b/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java
new file mode 100644
index 00000000000..c9839b8dc1a
--- /dev/null
+++ b/src/test/java/org/tron/core/capsule/utils/ExchangeProcessorTest.java
@@ -0,0 +1,135 @@
+package org.tron.core.capsule.utils;
+
+import java.io.File;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Constant;
+import org.tron.core.Wallet;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+
+@Slf4j
+public class ExchangeProcessorTest {
+
+ private static ExchangeProcessor processor;
+ private static final String dbPath = "output_buy_exchange_processor_test";
+ private static AnnotationConfigApplicationContext context;
+ private static final String OWNER_ADDRESS;
+ private static final String OWNER_ADDRESS_INVALID = "aaaa";
+ private static final String OWNER_ACCOUNT_INVALID;
+ private static final long initBalance = 10_000_000_000_000_000L;
+
+ static {
+ Args.setParam(new String[]{"--output-directory", dbPath}, Constant.TEST_CONF);
+ context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ OWNER_ADDRESS = Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a1abc";
+ OWNER_ACCOUNT_INVALID =
+ Wallet.getAddressPreFixString() + "548794500882809695a8a687866e76d4271a3456";
+ }
+
+ /**
+ * Init data.
+ */
+ @BeforeClass
+ public static void init() {
+ long supply = 1_000_000_000_000_000_000L;
+ processor = new ExchangeProcessor(supply);
+ // Args.setParam(new String[]{"--output-directory", dbPath},
+ // "config-junit.conf");
+ // dbManager = new Manager();
+ // dbManager.init();
+ }
+
+ /**
+ * Release resources.
+ */
+ @AfterClass
+ public static void destroy() {
+ Args.clearParam();
+ if (FileUtil.deleteDir(new File(dbPath))) {
+ logger.info("Release resources successful.");
+ } else {
+ logger.info("Release resources failure.");
+ }
+ context.destroy();
+ }
+
+ @Test
+ public void testExchange() {
+ long sellBalance = 100_000_000_000000L;
+ long buyBalance = 128L * 1024 * 1024 * 1024;
+ long sellQuant = 2_000_000_000_000L; // 2 million trx
+
+ long result = processor.exchange(sellBalance, buyBalance, sellQuant);
+
+ Assert.assertEquals(2694881440L, result);
+ }
+
+ @Test
+ public void testExchange2() {
+ long sellBalance = 100_000_000_000000L;
+ long buyBalance = 128L * 1024 * 1024 * 1024;
+ long sellQuant = 1_000_000_000_000L; // 2 million trx
+
+ long result = processor.exchange(sellBalance, buyBalance, sellQuant);
+ Assert.assertEquals(1360781717L, result);
+
+ sellBalance += sellQuant;
+ buyBalance -= result;
+
+ long result2 = processor.exchange(sellBalance, buyBalance, sellQuant);
+ Assert.assertEquals(2694881440L - 1360781717L, result2);
+
+ }
+
+
+ @Test
+ public void testSellAndBuy() {
+ long sellBalance = 100_000_000_000000L;
+ long buyBalance = 128L * 1024 * 1024 * 1024;
+ long sellQuant = 2_000_000_000_000L; // 2 million trx
+
+ long result = processor.exchange(sellBalance, buyBalance, sellQuant);
+ Assert.assertEquals(2694881440L, result);
+
+ sellBalance += sellQuant;
+ buyBalance -= result;
+
+ long result2 = processor.exchange(buyBalance, sellBalance, result);
+ Assert.assertEquals(1999999999542L, result2);
+
+ }
+
+ @Test
+ public void testSellAndBuy2() {
+ long sellBalance = 100_000_000_000000L;
+ long buyBalance = 128L * 1024 * 1024 * 1024;
+ long sellQuant = 2_000_000_000_000L; // 2 million trx
+
+ long result = processor.exchange(sellBalance, buyBalance, sellQuant);
+ Assert.assertEquals(2694881440L, result);
+
+ sellBalance += sellQuant;
+ buyBalance -= result;
+
+ long quant1 = 2694881440L - 1360781717L;
+ long quant2 = 1360781717L;
+
+ long result1 = processor.exchange(buyBalance, sellBalance, quant1);
+ Assert.assertEquals(999999999927L, result1);
+
+ buyBalance += quant1;
+ sellBalance -= result1;
+
+ long result2 = processor.exchange(buyBalance, sellBalance, quant2);
+ Assert.assertEquals(999999999587L, result2);
+
+ }
+
+
+}
diff --git a/src/test/java/org/tron/core/db/AccountIdIndexStoreTest.java b/src/test/java/org/tron/core/db/AccountIdIndexStoreTest.java
index d338597b977..9c1996b85a3 100644
--- a/src/test/java/org/tron/core/db/AccountIdIndexStoreTest.java
+++ b/src/test/java/org/tron/core/db/AccountIdIndexStoreTest.java
@@ -7,7 +7,7 @@
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
import org.tron.core.Wallet;
@@ -19,7 +19,7 @@
public class AccountIdIndexStoreTest {
private static String dbPath = "output_AccountIndexStore_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static AccountIdIndexStore accountIdIndexStore;
private static final byte[] ACCOUNT_ADDRESS_ONE = randomBytes(16);
private static final byte[] ACCOUNT_ADDRESS_TWO = randomBytes(16);
@@ -38,7 +38,7 @@ public class AccountIdIndexStoreTest {
static {
Args.setParam(new String[]{"--output-directory", dbPath},
Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@AfterClass
diff --git a/src/test/java/org/tron/core/db/AccountStoreTest.java b/src/test/java/org/tron/core/db/AccountStoreTest.java
index abbf8d40f53..d58fa06d8c4 100755
--- a/src/test/java/org/tron/core/db/AccountStoreTest.java
+++ b/src/test/java/org/tron/core/db/AccountStoreTest.java
@@ -8,7 +8,7 @@
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -22,7 +22,7 @@ public class AccountStoreTest {
private static String dbPath = "output_AccountStore_test";
private static String dbDirectory = "db_AccountStore_test";
private static String indexDirectory = "index_AccountStore_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static AccountStore accountStore;
private static final byte[] data = TransactionStoreTest.randomBytes(32);
private static byte[] address = TransactionStoreTest.randomBytes(32);
@@ -37,7 +37,7 @@ public class AccountStoreTest {
},
Constant.TEST_CONF
);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@AfterClass
diff --git a/src/test/java/org/tron/core/db/BlockStoreTest.java b/src/test/java/org/tron/core/db/BlockStoreTest.java
index bd9199e3211..68408809063 100644
--- a/src/test/java/org/tron/core/db/BlockStoreTest.java
+++ b/src/test/java/org/tron/core/db/BlockStoreTest.java
@@ -5,7 +5,7 @@
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
import org.tron.core.config.DefaultConfig;
@@ -16,12 +16,12 @@ public class BlockStoreTest {
private static final String dbPath = "output-blockStore-test";
BlockStore blockStore;
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
static {
Args.setParam(new String[]{"--output-directory", dbPath},
Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@Before
diff --git a/src/test/java/org/tron/core/db/KhaosDatabaseTest.java b/src/test/java/org/tron/core/db/KhaosDatabaseTest.java
index 9f371e704ac..abec8fd355a 100644
--- a/src/test/java/org/tron/core/db/KhaosDatabaseTest.java
+++ b/src/test/java/org/tron/core/db/KhaosDatabaseTest.java
@@ -9,7 +9,7 @@
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -27,12 +27,12 @@ public class KhaosDatabaseTest {
private static final String dbPath = "output-khaosDatabase-test";
private static KhaosDatabase khaosDatabase;
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
static {
Args.setParam(new String[]{"--output-directory", dbPath},
Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@BeforeClass
diff --git a/src/test/java/org/tron/core/db/ManagerTest.java b/src/test/java/org/tron/core/db/ManagerTest.java
index b655b5ee7d7..35e2d70ee33 100755
--- a/src/test/java/org/tron/core/db/ManagerTest.java
+++ b/src/test/java/org/tron/core/db/ManagerTest.java
@@ -8,12 +8,10 @@
import java.util.stream.IntStream;
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
-import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.crypto.ECKey;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
@@ -36,10 +34,14 @@
import org.tron.core.exception.HeaderNotFound;
import org.tron.core.exception.ItemNotFoundException;
import org.tron.core.exception.NonCommonBlockException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.core.exception.ReceiptException;
import org.tron.core.exception.TaposException;
import org.tron.core.exception.TooBigTransactionException;
import org.tron.core.exception.TransactionExpirationException;
+import org.tron.core.exception.TransactionTraceException;
import org.tron.core.exception.UnLinkedBlockException;
+import org.tron.core.exception.UnsupportVMException;
import org.tron.core.exception.ValidateScheduleException;
import org.tron.core.exception.ValidateSignatureException;
import org.tron.core.witness.WitnessController;
@@ -51,14 +53,14 @@
public class ManagerTest {
private static Manager dbManager;
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static BlockCapsule blockCapsule2;
private static String dbPath = "output_manager_test";
@Before
public void init() {
Args.setParam(new String[]{"-d", dbPath, "-w"}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
dbManager = context.getBean(Manager.class);
@@ -89,7 +91,7 @@ public void removeDb() {
@Test
public void setBlockReference()
throws ContractExeException, UnLinkedBlockException, ValidateScheduleException, BadBlockException,
- ContractValidateException, ValidateSignatureException, BadItemException, ItemNotFoundException, AccountResourceInsufficientException, TransactionExpirationException, TooBigTransactionException, DupTransactionException, TaposException, BadNumberBlockException, NonCommonBlockException {
+ ContractValidateException, ValidateSignatureException, BadItemException, ItemNotFoundException, AccountResourceInsufficientException, TransactionExpirationException, TooBigTransactionException, DupTransactionException, TaposException, BadNumberBlockException, NonCommonBlockException, ReceiptException, TransactionTraceException, OutOfSlotTimeException, UnsupportVMException {
BlockCapsule blockCapsule =
new BlockCapsule(
@@ -213,11 +215,11 @@ public void updateWits() {
@Test
public void fork()
throws ValidateSignatureException, ContractValidateException, ContractExeException,
- UnLinkedBlockException, ValidateScheduleException, BadItemException,
+ UnLinkedBlockException, ValidateScheduleException, BadItemException, ReceiptException,
ItemNotFoundException, HeaderNotFound, AccountResourceInsufficientException,
- TransactionExpirationException, TooBigTransactionException,
- DupTransactionException, BadBlockException,
- TaposException, BadNumberBlockException, NonCommonBlockException {
+ TransactionExpirationException, TooBigTransactionException, DupTransactionException,
+ BadBlockException, TaposException, BadNumberBlockException, NonCommonBlockException,
+ TransactionTraceException, OutOfSlotTimeException, UnsupportVMException {
Args.setParam(new String[]{"--witness"}, Constant.TEST_CONF);
long size = dbManager.getBlockStore().size();
System.out.print("block store size:" + size + "\n");
@@ -227,29 +229,34 @@ public void fork()
byte[] address = ecKey.getAddress();
WitnessCapsule witnessCapsule = new WitnessCapsule(ByteString.copyFrom(address));
dbManager.addWitness(ByteString.copyFrom(address));
- dbManager.generateBlock(witnessCapsule, System.currentTimeMillis(), privateKey);
+ dbManager.generateBlock(witnessCapsule, 1533529947843L, privateKey);
Map addressToProvateKeys = addTestWitnessAndAccount();
+
long num = dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber();
BlockCapsule blockCapsule0 =
createTestBlockCapsule(
+ 1533529947843L+3000,
num + 1,
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
addressToProvateKeys);
BlockCapsule blockCapsule1 =
createTestBlockCapsule(
+ 1533529947843L+3000,
num + 1,
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
addressToProvateKeys);
+ dbManager.pushBlock(blockCapsule0);
+ dbManager.pushBlock(blockCapsule1);
+
BlockCapsule blockCapsule2 =
createTestBlockCapsule(
+ 1533529947843L +6000,
num + 2, blockCapsule1.getBlockId().getByteString(), addressToProvateKeys);
- dbManager.pushBlock(blockCapsule0);
- dbManager.pushBlock(blockCapsule1);
dbManager.pushBlock(blockCapsule2);
Assert.assertNotNull(dbManager.getBlockStore().get(blockCapsule1.getBlockId().getBytes()));
@@ -277,11 +284,12 @@ public void fork()
@Test
public void doNotSwitch()
throws ValidateSignatureException, ContractValidateException, ContractExeException,
- UnLinkedBlockException, ValidateScheduleException, BadItemException,
+ UnLinkedBlockException, ValidateScheduleException, BadItemException, ReceiptException,
ItemNotFoundException, HeaderNotFound, AccountResourceInsufficientException,
TransactionExpirationException, TooBigTransactionException,
DupTransactionException, BadBlockException,
- TaposException, BadNumberBlockException, NonCommonBlockException {
+ TaposException, BadNumberBlockException, NonCommonBlockException, TransactionTraceException,
+ OutOfSlotTimeException, UnsupportVMException {
Args.setParam(new String[]{"--witness"}, Constant.TEST_CONF);
long size = dbManager.getBlockStore().size();
System.out.print("block store size:" + size + "\n");
@@ -291,35 +299,40 @@ public void doNotSwitch()
byte[] address = ecKey.getAddress();
WitnessCapsule witnessCapsule = new WitnessCapsule(ByteString.copyFrom(address));
dbManager.addWitness(ByteString.copyFrom(address));
- dbManager.generateBlock(witnessCapsule, System.currentTimeMillis(), privateKey);
+ dbManager.generateBlock(witnessCapsule, 1533529947843L, privateKey);
Map addressToProvateKeys = addTestWitnessAndAccount();
long num = dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber();
BlockCapsule blockCapsule0 =
createTestBlockCapsule(
+ 1533529947843L + 3000,
num + 1,
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
addressToProvateKeys);
BlockCapsule blockCapsule1 =
createTestBlockCapsule(
+ 1533529947843L + 3001,
num + 1,
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
addressToProvateKeys);
- BlockCapsule blockCapsule2 =
- createTestBlockCapsule(
- num + 2, blockCapsule1.getBlockId().getByteString(), addressToProvateKeys);
+
logger.info("******block0:" + blockCapsule0);
logger.info("******block1:" + blockCapsule1);
- logger.info("******block2:" + blockCapsule2);
dbManager.pushBlock(blockCapsule0);
dbManager.pushBlock(blockCapsule1);
context.getBean(KhaosDatabase.class).removeBlk(dbManager.getBlockIdByNum(num));
Exception exception = null;
+
+ BlockCapsule blockCapsule2 =
+ createTestBlockCapsule(
+ 1533529947843L + 6000,
+ num + 2, blockCapsule1.getBlockId().getByteString(), addressToProvateKeys);
+ logger.info("******block2:" + blockCapsule2);
try {
dbManager.pushBlock(blockCapsule2);
} catch (NonCommonBlockException e) {
@@ -337,19 +350,22 @@ public void doNotSwitch()
}
BlockCapsule blockCapsule3 =
- createTestBlockCapsule(
+ createTestBlockCapsule(1533529947843L + 9000,
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() + 1,
- dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(), addressToProvateKeys);
+ dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
+ addressToProvateKeys);
logger.info("******block3:" + blockCapsule3);
dbManager.pushBlock(blockCapsule3);
Assert.assertEquals(blockCapsule3.getBlockId(),
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash());
Assert.assertEquals(blockCapsule3.getBlockId(),
- dbManager.getBlockStore().get(dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getBytes()).getBlockId());
+ dbManager.getBlockStore()
+ .get(dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getBytes())
+ .getBlockId());
BlockCapsule blockCapsule4 =
- createTestBlockCapsule(
+ createTestBlockCapsule(1533529947843L + 12000,
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() + 1,
blockCapsule3.getBlockId().getByteString(), addressToProvateKeys);
logger.info("******block4:" + blockCapsule4);
@@ -358,17 +374,19 @@ public void doNotSwitch()
Assert.assertEquals(blockCapsule4.getBlockId(),
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash());
Assert.assertEquals(blockCapsule4.getBlockId(),
- dbManager.getBlockStore().get(dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getBytes()).getBlockId());
+ dbManager.getBlockStore()
+ .get(dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getBytes())
+ .getBlockId());
}
@Test
public void switchBack()
throws ValidateSignatureException, ContractValidateException, ContractExeException,
- UnLinkedBlockException, ValidateScheduleException, BadItemException,
+ UnLinkedBlockException, ValidateScheduleException, BadItemException, ReceiptException,
ItemNotFoundException, HeaderNotFound, AccountResourceInsufficientException,
- TransactionExpirationException, TooBigTransactionException,
- DupTransactionException, BadBlockException,
- TaposException, BadNumberBlockException, NonCommonBlockException {
+ TransactionExpirationException, TooBigTransactionException, DupTransactionException,
+ BadBlockException, TaposException, BadNumberBlockException, NonCommonBlockException,
+ TransactionTraceException, OutOfSlotTimeException, UnsupportVMException {
Args.setParam(new String[]{"--witness"}, Constant.TEST_CONF);
long size = dbManager.getBlockStore().size();
System.out.print("block store size:" + size + "\n");
@@ -378,30 +396,34 @@ public void switchBack()
byte[] address = ecKey.getAddress();
WitnessCapsule witnessCapsule = new WitnessCapsule(ByteString.copyFrom(address));
dbManager.addWitness(ByteString.copyFrom(address));
- dbManager.generateBlock(witnessCapsule, System.currentTimeMillis(), privateKey);
+ dbManager.generateBlock(witnessCapsule, 1533529947843L, privateKey);
Map addressToProvateKeys = addTestWitnessAndAccount();
long num = dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber();
BlockCapsule blockCapsule0 =
createTestBlockCapsule(
+ 1533529947843L +3000,
num + 1,
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
addressToProvateKeys);
BlockCapsule blockCapsule1 =
createTestBlockCapsule(
+ 1533529947843L +3000,
num + 1,
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
addressToProvateKeys);
- BlockCapsule blockCapsule2 =
- createTestBlockCapsuleError(
- num + 2, blockCapsule1.getBlockId().getByteString(), addressToProvateKeys);
dbManager.pushBlock(blockCapsule0);
dbManager.pushBlock(blockCapsule1);
try {
+ BlockCapsule blockCapsule2 =
+ createTestBlockCapsuleError(
+ 1533529947843L +6000,
+ num + 2, blockCapsule1.getBlockId().getByteString(), addressToProvateKeys);
+
dbManager.pushBlock(blockCapsule2);
} catch (ValidateScheduleException e) {
logger.info("the fork chain has error block");
@@ -413,6 +435,7 @@ public void switchBack()
BlockCapsule blockCapsule3 =
createTestBlockCapsule(
+ 1533529947843L +9000,
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() + 1,
blockCapsule0.getBlockId().getByteString(), addressToProvateKeys);
dbManager.pushBlock(blockCapsule3);
@@ -420,10 +443,13 @@ public void switchBack()
Assert.assertEquals(blockCapsule3.getBlockId(),
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash());
Assert.assertEquals(blockCapsule3.getBlockId(),
- dbManager.getBlockStore().get(dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getBytes()).getBlockId());
+ dbManager.getBlockStore()
+ .get(dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getBytes())
+ .getBlockId());
BlockCapsule blockCapsule4 =
createTestBlockCapsule(
+ 1533529947843L +12000,
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() + 1,
blockCapsule3.getBlockId().getByteString(), addressToProvateKeys);
dbManager.pushBlock(blockCapsule4);
@@ -431,7 +457,9 @@ public void switchBack()
Assert.assertEquals(blockCapsule4.getBlockId(),
dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash());
Assert.assertEquals(blockCapsule4.getBlockId(),
- dbManager.getBlockStore().get(dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getBytes()).getBlockId());
+ dbManager.getBlockStore()
+ .get(dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getBytes())
+ .getBlockId());
}
private Map addTestWitnessAndAccount() {
@@ -455,14 +483,18 @@ private Map addTestWitnessAndAccount() {
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}
-
private BlockCapsule createTestBlockCapsule(
long number, ByteString hash, Map addressToProvateKeys) {
long time = System.currentTimeMillis();
+ return createTestBlockCapsule(time,number,hash,addressToProvateKeys);
+ }
+ private BlockCapsule createTestBlockCapsule(long time ,
+ long number, ByteString hash, Map addressToProvateKeys) {
WitnessController witnessController = dbManager.getWitnessController();
ByteString witnessAddress =
witnessController.getScheduledWitness(witnessController.getSlotAtTime(time));
- BlockCapsule blockCapsule = new BlockCapsule(number, Sha256Hash.wrap(hash), time, witnessAddress);
+ BlockCapsule blockCapsule = new BlockCapsule(number, Sha256Hash.wrap(hash), time,
+ witnessAddress);
blockCapsule.generatedByMyself = true;
blockCapsule.setMerkleRoot();
blockCapsule.sign(ByteArray.fromHexString(addressToProvateKeys.get(witnessAddress)));
@@ -472,10 +504,15 @@ private BlockCapsule createTestBlockCapsule(
private BlockCapsule createTestBlockCapsuleError(
long number, ByteString hash, Map addressToProvateKeys) {
long time = System.currentTimeMillis();
+ return createTestBlockCapsuleError(time,number,hash,addressToProvateKeys);
+ }
+ private BlockCapsule createTestBlockCapsuleError(long time ,
+ long number, ByteString hash, Map addressToProvateKeys) {
WitnessController witnessController = dbManager.getWitnessController();
ByteString witnessAddress =
witnessController.getScheduledWitness(witnessController.getSlotAtTime(time));
- BlockCapsule blockCapsule = new BlockCapsule(number, Sha256Hash.wrap(hash), time, ByteString.copyFromUtf8("onlyTest"));
+ BlockCapsule blockCapsule = new BlockCapsule(number, Sha256Hash.wrap(hash), time,
+ ByteString.copyFromUtf8("onlyTest"));
blockCapsule.generatedByMyself = true;
blockCapsule.setMerkleRoot();
blockCapsule.sign(ByteArray.fromHexString(addressToProvateKeys.get(witnessAddress)));
diff --git a/src/test/java/org/tron/core/db/TransactionHistoryTest.java b/src/test/java/org/tron/core/db/TransactionHistoryTest.java
index 26a040c5ac5..49e683cee41 100644
--- a/src/test/java/org/tron/core/db/TransactionHistoryTest.java
+++ b/src/test/java/org/tron/core/db/TransactionHistoryTest.java
@@ -5,7 +5,7 @@
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -19,7 +19,7 @@ public class TransactionHistoryTest {
private static String dbPath = "output_TransactionHistoryStore_test";
private static String dbDirectory = "db_TransactionHistoryStore_test";
private static String indexDirectory = "index_TransactionHistoryStore_test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static TransactionHistoryStore transactionHistoryStore;
private static final byte[] transactionId = TransactionStoreTest.randomBytes(32);
@@ -32,7 +32,7 @@ public class TransactionHistoryTest {
},
Constant.TEST_CONF
);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@AfterClass
diff --git a/src/test/java/org/tron/core/db/TransactionStoreTest.java b/src/test/java/org/tron/core/db/TransactionStoreTest.java
index 2800b5b4a71..c444cfba5d5 100644
--- a/src/test/java/org/tron/core/db/TransactionStoreTest.java
+++ b/src/test/java/org/tron/core/db/TransactionStoreTest.java
@@ -7,7 +7,7 @@
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
@@ -30,7 +30,7 @@ public class TransactionStoreTest {
private static String dbDirectory = "db_TransactionStore_test";
private static String indexDirectory = "index_TransactionStore_test";
private static TransactionStore transactionStore;
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static final byte[] key1 = TransactionStoreTest.randomBytes(21);
private static Manager dbManager;
private static final byte[] key2 = TransactionStoreTest.randomBytes(21);
@@ -57,7 +57,7 @@ public class TransactionStoreTest {
},
Constant.TEST_CONF
);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
/**
diff --git a/src/test/java/org/tron/core/db/TransactionTraceTest.java b/src/test/java/org/tron/core/db/TransactionTraceTest.java
new file mode 100644
index 00000000000..105a380161e
--- /dev/null
+++ b/src/test/java/org/tron/core/db/TransactionTraceTest.java
@@ -0,0 +1,272 @@
+/*
+ * java-tron is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * java-tron is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+package org.tron.core.db;
+
+import com.google.protobuf.Any;
+import com.google.protobuf.ByteString;
+import com.google.protobuf.InvalidProtocolBufferException;
+import java.io.File;
+import java.util.Arrays;
+import java.util.Collection;
+import org.junit.AfterClass;
+import org.junit.Assert;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+import org.tron.common.application.TronApplicationContext;
+import org.tron.common.runtime.Runtime;
+import org.tron.common.runtime.vm.program.invoke.ProgramInvokeFactoryImpl;
+import org.tron.common.storage.DepositImpl;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.FileUtil;
+import org.tron.core.Wallet;
+import org.tron.core.capsule.AccountCapsule;
+import org.tron.core.capsule.ContractCapsule;
+import org.tron.core.capsule.TransactionCapsule;
+import org.tron.core.config.DefaultConfig;
+import org.tron.core.config.args.Args;
+import org.tron.core.exception.ContractExeException;
+import org.tron.core.exception.ContractValidateException;
+import org.tron.core.exception.OutOfSlotTimeException;
+import org.tron.protos.Contract.CreateSmartContract;
+import org.tron.protos.Contract.TriggerSmartContract;
+import org.tron.protos.Protocol.Account;
+import org.tron.protos.Protocol.Account.AccountResource;
+import org.tron.protos.Protocol.Account.Frozen;
+import org.tron.protos.Protocol.AccountType;
+import org.tron.protos.Protocol.SmartContract;
+import org.tron.protos.Protocol.Transaction;
+import org.tron.protos.Protocol.Transaction.Contract;
+import org.tron.protos.Protocol.Transaction.Contract.ContractType;
+import org.tron.protos.Protocol.Transaction.raw;
+
+@RunWith(Parameterized.class)
+public class TransactionTraceTest {
+
+ public static final long totalBalance = 1000_0000_000_000L;
+ public static final int deployStorageDelta = 680000;
+ private static String dbPath = "output_TransactionTrace_test";
+ private static String dbDirectory = "db_TransactionTrace_test";
+ private static String indexDirectory = "index_TransactionTrace_test";
+ private static TronApplicationContext context;
+ private static Manager dbManager;
+ private static StorageMarket storageMarket;
+ private static ByteString ownerAddress = ByteString.copyFrom(ByteArray.fromInt(1));
+ private static ByteString contractAddress = ByteString.copyFrom(ByteArray.fromInt(2));
+
+ private long energyUsage;
+ private long storageUsage;
+ /*
+ * DeployContract tracetestContract [{"constant":false,"inputs":[{"name":"accountId","type":"uint256"}],"name":"getVoters","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"voters","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"vote","type":"uint256"}],"name":"addVoters","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"inputs":[],"payable":false,"stateMutability":"nonpayable","type":"constructor"}] 608060405234801561001057600080fd5b5060015b620186a0811015610038576000818152602081905260409020819055600a01610014565b5061010b806100486000396000f30060806040526004361060525763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166386b646f281146057578063da58c7d914607e578063eb91a5ff146093575b600080fd5b348015606257600080fd5b50606c60043560aa565b60408051918252519081900360200190f35b348015608957600080fd5b50606c60043560bc565b348015609e57600080fd5b5060a860043560ce565b005b60009081526020819052604090205490565b60006020819052908152604090205481565b6000818152602081905260409020555600a165627a7a72305820f9935f89890e51bcf3ea98fa4841c91ac5957a197d99eeb7879a775b30ee9a2d0029 1000000000000 100
+ * */
+ private String trxByte = "0a80050a0231ca220844c8b91d4d5d7e5f40e0f19aecd32c5ad904081e12d4040a30747970652e676f6f676c65617069732e636f6d2f70726f746f636f6c2e437265617465536d617274436f6e7472616374129f040a15411bd09e9a1bf949b3d08b56f85ad3e3e3905763c81285040a15411bd09e9a1bf949b3d08b56f85ad3e3e3905763c81a80010a301a09676574566f74657273221412096163636f756e7449641a0775696e743235362a091a0775696e74323536300240030a2410011a06766f7465727322091a0775696e743235362a091a0775696e74323536300240020a201a09616464566f74657273220f1204766f74651a0775696e74323536300240030a043001400322d302608060405234801561001057600080fd5b5060015b620186a0811015610038576000818152602081905260409020819055600a01610014565b5061010b806100486000396000f30060806040526004361060525763ffffffff7c010000000000000000000000000000000000000000000000000000000060003504166386b646f281146057578063da58c7d914607e578063eb91a5ff146093575b600080fd5b348015606257600080fd5b50606c60043560aa565b60408051918252519081900360200190f35b348015608957600080fd5b50606c60043560bc565b348015609e57600080fd5b5060a860043560ce565b005b60009081526020819052604090205490565b60006020819052908152604090205481565b6000818152602081905260409020555600a165627a7a72305820f9935f89890e51bcf3ea98fa4841c91ac5957a197d99eeb7879a775b30ee9a2d002930643a11747261636574657374436f6e747261637470d7b297ecd32c900180a094a58d1d124165e6fe033d9ee0369c298f7ef263eab2ebf33a63e20c6fad38cf64e0f0a4f8fa0c562e6beafbd43a841ff9058e7a09c88381636db68a9ce17f4529d66f00111e00";
+ private static String OwnerAddress = "TCWHANtDDdkZCTo2T2peyEq3Eg9c2XB7ut";
+
+ static {
+ Args.setParam(
+ new String[]{
+ "--output-directory", dbPath,
+ "--storage-db-directory", dbDirectory,
+ "--storage-index-directory", indexDirectory,
+ "-w",
+ "--debug"
+ },
+ "config-test-mainnet.conf"
+ );
+ context = new TronApplicationContext(DefaultConfig.class);
+ }
+
+ public TransactionTraceTest(long energyUsage, long storageUsage) {
+ this.energyUsage = energyUsage;
+ this.storageUsage = storageUsage;
+ }
+
+ /**
+ * resourceUsage prepare data for testing.
+ */
+ @Parameters
+ public static Collection resourceUsage() {
+ return Arrays.asList(new Object[][]{
+
+ {0, 0},
+ // {6, 1000},
+ // {7, 1000},
+ // {10, 999},
+ // {13, 1000},
+ // {14, 1000},
+ // {20, 1000},
+ // {10, 1000},
+ // {10, 1001}
+
+ });
+ }
+
+ /**
+ * Init data.
+ */
+ @BeforeClass
+ public static void init() {
+ dbManager = context.getBean(Manager.class);
+ storageMarket = new StorageMarket(dbManager);
+ //init energy
+ dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(1526647838000L);
+ dbManager.getDynamicPropertiesStore().saveTotalEnergyWeight(10_000_000L);
+ //init storage
+ dbManager.getDynamicPropertiesStore().saveTotalStorageReserved(
+ 128L * 1024 * 1024 * 1024);
+ dbManager.getDynamicPropertiesStore().saveTotalStoragePool(100_000_000_000000L);
+ dbManager.getDynamicPropertiesStore().saveTotalStorageTax(0);
+ dbManager.getDynamicPropertiesStore().saveLatestBlockHeaderTimestamp(0);
+
+ }
+
+ @Test
+ public void testUseFee() throws InvalidProtocolBufferException {
+ AccountCapsule accountCapsule = new AccountCapsule(ByteString.copyFrom("owner".getBytes()),
+ ByteString.copyFrom(Wallet.decodeFromBase58Check(OwnerAddress)), AccountType.Normal,
+ totalBalance);
+ dbManager.getAccountStore()
+ .put(Wallet.decodeFromBase58Check(OwnerAddress), accountCapsule);
+ Transaction transaction = Transaction.parseFrom(ByteArray.fromHexString(trxByte));
+ TransactionCapsule transactionCapsule = new TransactionCapsule(transaction);
+ TransactionTrace trace = new TransactionTrace(transactionCapsule, dbManager);
+ DepositImpl deposit = DepositImpl.createRoot(dbManager);
+ Runtime runtime = new Runtime(trace, null, deposit,
+ new ProgramInvokeFactoryImpl());
+ try {
+ trace.exec(runtime);
+ trace.pay();
+ Assert.assertEquals(0, trace.getReceipt().getEnergyUsage());
+ Assert.assertEquals(49503930, trace.getReceipt().getEnergyFee());
+ // Assert.assertEquals(deployStorageDelta, trace.getReceipt().getStorageDelta());
+ // Assert.assertEquals(494800000, trace.getReceipt().getStorageFee());
+ accountCapsule = dbManager.getAccountStore().get(accountCapsule.getAddress().toByteArray());
+ // Assert.assertEquals(totalBalance,
+ // trace.getReceipt().getStorageFee() + trace.getReceipt().getEnergyFee() + accountCapsule
+ // .getBalance());
+ } catch (ContractExeException e) {
+ e.printStackTrace();
+ } catch (ContractValidateException e) {
+ e.printStackTrace();
+ } catch (OutOfSlotTimeException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void testUseUsage() throws InvalidProtocolBufferException {
+
+ AccountCapsule accountCapsule = new AccountCapsule(ByteString.copyFrom("owner".getBytes()),
+ ByteString.copyFrom(Wallet.decodeFromBase58Check(OwnerAddress)), AccountType.Normal,
+ totalBalance);
+
+ accountCapsule.setFrozenForEnergy(10_000_000L, 0L);
+ dbManager.getAccountStore()
+ .put(Wallet.decodeFromBase58Check(OwnerAddress), accountCapsule);
+ storageMarket.buyStorage(accountCapsule, 1000_000L);
+ Transaction transaction = Transaction.parseFrom(ByteArray.fromHexString(trxByte));
+ TransactionCapsule transactionCapsule = new TransactionCapsule(transaction);
+ TransactionTrace trace = new TransactionTrace(transactionCapsule, dbManager);
+ DepositImpl deposit = DepositImpl.createRoot(dbManager);
+ Runtime runtime = new Runtime(trace, null, deposit,
+ new ProgramInvokeFactoryImpl());
+ try {
+ trace.exec(runtime);
+ trace.pay();
+ Assert.assertEquals(50000, trace.getReceipt().getEnergyUsage());
+ Assert.assertEquals(20110013100L, trace.getReceipt().getEnergyFee());
+ Assert.assertEquals(201150131L, trace.getReceipt().getEnergyUsageTotal());
+ // Assert.assertEquals(deployStorageDelta, trace.getReceipt().getStorageDelta());
+ // Assert.assertEquals(493800000, trace.getReceipt().getStorageFee());
+ accountCapsule = dbManager.getAccountStore().get(accountCapsule.getAddress().toByteArray());
+ } catch (ContractExeException e) {
+ e.printStackTrace();
+ } catch (ContractValidateException e) {
+ e.printStackTrace();
+ } catch (OutOfSlotTimeException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Test
+ public void testPay() {
+ Account account = Account.newBuilder()
+ .setAddress(ownerAddress)
+ .setBalance(1000000)
+ .setAccountResource(
+ AccountResource.newBuilder()
+ .setEnergyUsage(this.energyUsage)
+ .setFrozenBalanceForEnergy(
+ Frozen.newBuilder()
+ .setExpireTime(100000)
+ .setFrozenBalance(100000)
+ .build())
+ .setStorageUsage(this.storageUsage)
+ .setStorageLimit(3000)
+ .build()).build();
+
+ AccountCapsule accountCapsule = new AccountCapsule(account);
+ dbManager.getAccountStore().put(accountCapsule.getAddress().toByteArray(), accountCapsule);
+ TriggerSmartContract contract = TriggerSmartContract.newBuilder()
+ .setContractAddress(contractAddress)
+ .setOwnerAddress(ownerAddress)
+ .build();
+
+ SmartContract smartContract = SmartContract.newBuilder()
+ .setOriginAddress(ownerAddress)
+ .setContractAddress(contractAddress)
+ .build();
+
+ CreateSmartContract createSmartContract = CreateSmartContract.newBuilder()
+ .setOwnerAddress(ownerAddress)
+ .setNewContract(smartContract)
+ .build();
+
+ Transaction transaction = Transaction.newBuilder()
+ .setRawData(
+ raw.newBuilder()
+ .addContract(
+ Contract.newBuilder()
+ .setParameter(Any.pack(contract))
+ .setType(ContractType.TriggerSmartContract)
+ .build())
+ .build()
+ )
+ .build();
+
+ dbManager.getContractStore().put(
+ contractAddress.toByteArray(),
+ new ContractCapsule(smartContract));
+
+ TransactionCapsule transactionCapsule = new TransactionCapsule(transaction);
+ TransactionTrace transactionTrace = new TransactionTrace(transactionCapsule, dbManager);
+ // transactionTrace.setBill(this.energyUsage, this.storageUsage);
+ transactionTrace.pay();
+ AccountCapsule accountCapsule1 = dbManager.getAccountStore().get(ownerAddress.toByteArray());
+ }
+
+ /**
+ * destroy clear data of testing.
+ */
+ @AfterClass
+ public static void destroy() {
+ Args.clearParam();
+ FileUtil.deleteDir(new File(dbPath));
+ context.destroy();
+ }
+}
diff --git a/src/test/java/org/tron/core/db/VotesStoreTest.java b/src/test/java/org/tron/core/db/VotesStoreTest.java
index af1eb8e17d6..2ff2dd26bc6 100755
--- a/src/test/java/org/tron/core/db/VotesStoreTest.java
+++ b/src/test/java/org/tron/core/db/VotesStoreTest.java
@@ -9,7 +9,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
import org.tron.core.capsule.VotesCapsule;
@@ -21,12 +21,12 @@
public class VotesStoreTest {
private static final String dbPath = "output-votesStore-test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
VotesStore votesStore;
static {
Args.setParam(new String[]{"-d", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@Before
diff --git a/src/test/java/org/tron/core/db/WitnessStoreTest.java b/src/test/java/org/tron/core/db/WitnessStoreTest.java
index 6f88132c63f..4dd0dd7e53f 100755
--- a/src/test/java/org/tron/core/db/WitnessStoreTest.java
+++ b/src/test/java/org/tron/core/db/WitnessStoreTest.java
@@ -7,7 +7,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
import org.tron.core.capsule.WitnessCapsule;
@@ -18,12 +18,12 @@
public class WitnessStoreTest {
private static final String dbPath = "output-witnessStore-test";
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
WitnessStore witnessStore;
static {
Args.setParam(new String[]{"-d", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@Before
diff --git a/src/test/java/org/tron/core/db/api/IndexHelperTest.java b/src/test/java/org/tron/core/db/api/IndexHelperTest.java
index effa60c836d..b3eee71ef68 100644
--- a/src/test/java/org/tron/core/db/api/IndexHelperTest.java
+++ b/src/test/java/org/tron/core/db/api/IndexHelperTest.java
@@ -12,7 +12,7 @@
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.capsule.AccountCapsule;
@@ -38,13 +38,13 @@ public class IndexHelperTest {
private static Manager dbManager;
private static IndexHelper indexHelper;
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static String dbPath = "output_IndexHelper_test";
static {
Args.setParam(new String[]{"-d", dbPath, "-w"}, "config-test-index.conf");
Args.getInstance().setSolidityNode(true);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@BeforeClass
diff --git a/src/test/java/org/tron/core/db/api/StoreAPITest.java b/src/test/java/org/tron/core/db/api/StoreAPITest.java
index 534cdc3dbc0..dbc2c6d41b8 100644
--- a/src/test/java/org/tron/core/db/api/StoreAPITest.java
+++ b/src/test/java/org/tron/core/db/api/StoreAPITest.java
@@ -9,7 +9,7 @@
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.capsule.AccountCapsule;
@@ -98,13 +98,13 @@ public class StoreAPITest {
public static AssetIssueContract assetIssue4;
private static Manager dbManager;
private static StoreAPI storeAPI;
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static String dbPath = "output_StoreAPI_test";
static {
Args.setParam(new String[]{"-d", dbPath, "-w"}, "config-test-index.conf");
Args.getInstance().setSolidityNode(true);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@BeforeClass
diff --git a/src/test/java/org/tron/core/net/UdpTest.java b/src/test/java/org/tron/core/net/UdpTest.java
index d3d148177ca..35fdf75b080 100644
--- a/src/test/java/org/tron/core/net/UdpTest.java
+++ b/src/test/java/org/tron/core/net/UdpTest.java
@@ -7,7 +7,7 @@
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.testng.collections.Lists;
import org.tron.common.net.udp.message.discover.FindNodeMessage;
import org.tron.common.net.udp.message.Message;
@@ -45,7 +45,7 @@ public void before(){
cfgArgs.getSeedNode().setIpList(Lists.newArrayList());
cfgArgs.setNodeP2pVersion(100);
cfgArgs.setNodeListenPort(10001);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}).start();
}
diff --git a/src/test/java/org/tron/core/net/node/BaseNetTest.java b/src/test/java/org/tron/core/net/node/BaseNetTest.java
index 72348c59bad..84c353f891a 100644
--- a/src/test/java/org/tron/core/net/node/BaseNetTest.java
+++ b/src/test/java/org/tron/core/net/node/BaseNetTest.java
@@ -21,7 +21,7 @@
import lombok.extern.slf4j.Slf4j;
import org.junit.After;
import org.junit.Before;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.overlay.client.PeerClient;
@@ -39,7 +39,7 @@
@Slf4j
public abstract class BaseNetTest {
- protected static AnnotationConfigApplicationContext context;
+ protected static TronApplicationContext context;
protected NodeImpl node;
protected RpcApiService rpcApiService;
protected PeerClient peerClient;
@@ -84,7 +84,7 @@ public void run() {
cfgArgs.setNeedSyncCheck(false);
cfgArgs.setNodeExternalIp("127.0.0.1");
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
if (cfgArgs.isHelp()) {
logger.info("Here is the help message.");
diff --git a/src/test/java/org/tron/core/net/node/BroadTest.java b/src/test/java/org/tron/core/net/node/BroadTest.java
index 4d7ce73e586..475b46fad61 100644
--- a/src/test/java/org/tron/core/net/node/BroadTest.java
+++ b/src/test/java/org/tron/core/net/node/BroadTest.java
@@ -13,7 +13,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.overlay.client.PeerClient;
@@ -45,7 +45,7 @@
@Slf4j
public class BroadTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private NodeImpl node;
RpcApiService rpcApiService;
PeerClient peerClient;
@@ -196,7 +196,7 @@ public void run() {
cfgArgs.setNeedSyncCheck(false);
cfgArgs.setNodeExternalIp("127.0.0.1");
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
if (cfgArgs.isHelp()) {
logger.info("Here is the help message.");
diff --git a/src/test/java/org/tron/core/net/node/FinishProcessSyncBlockTest.java b/src/test/java/org/tron/core/net/node/FinishProcessSyncBlockTest.java
index d490a8702b7..1bf4e172c15 100644
--- a/src/test/java/org/tron/core/net/node/FinishProcessSyncBlockTest.java
+++ b/src/test/java/org/tron/core/net/node/FinishProcessSyncBlockTest.java
@@ -7,7 +7,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.crypto.ECKey;
@@ -39,7 +39,7 @@
@Slf4j
public class FinishProcessSyncBlockTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private NodeImpl node;
RpcApiService rpcApiService;
PeerClient peerClient;
@@ -131,7 +131,7 @@ public void run() {
cfgArgs.setNeedSyncCheck(false);
cfgArgs.setNodeExternalIp("127.0.0.1");
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
if (cfgArgs.isHelp()) {
logger.info("Here is the help message.");
diff --git a/src/test/java/org/tron/core/net/node/GetBlockChainSummaryTest.java b/src/test/java/org/tron/core/net/node/GetBlockChainSummaryTest.java
index df77d3b77c9..13e6ebc3c9b 100644
--- a/src/test/java/org/tron/core/net/node/GetBlockChainSummaryTest.java
+++ b/src/test/java/org/tron/core/net/node/GetBlockChainSummaryTest.java
@@ -8,7 +8,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.crypto.ECKey;
@@ -43,7 +43,7 @@
@Slf4j
public class GetBlockChainSummaryTest{
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private NodeImpl node;
RpcApiService rpcApiService;
PeerClient peerClient;
@@ -73,8 +73,8 @@ public void testGetBlockChainSummary() {
long number = dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() + 1;
Map addressToProvateKeys = addTestWitnessAndAccount();
- BlockCapsule capsule = createTestBlockCapsule(number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
- addressToProvateKeys);
+ BlockCapsule capsule = createTestBlockCapsule(1533529947843L,number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
+ addressToProvateKeys);
try {
dbManager.pushBlock(capsule);
} catch (Exception e) {
@@ -82,7 +82,7 @@ public void testGetBlockChainSummary() {
}
for (int i = 1; i < 5; i++) {
number = dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() + 1;
- capsule = createTestBlockCapsule(number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(), addressToProvateKeys);
+ capsule = createTestBlockCapsule(1533529947843L + 3000L * i,number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(), addressToProvateKeys);
try {
dbManager.pushBlock(capsule);
} catch (Exception e) {
@@ -111,7 +111,7 @@ public void testGetBlockChainSummary() {
peer_he.getSyncBlockToFetch().clear();
for(int i=0; i<4 ;i++){
number = dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() + 1;
- capsule = createTestBlockCapsule(number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
+ capsule = createTestBlockCapsule(1533529947843L + 3000L * i, number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
addressToProvateKeys);
toFetch.add(capsule.getBlockId());
}
@@ -131,18 +131,18 @@ public void testGetBlockChainSummary() {
toFetch.clear();
peer_he.getSyncBlockToFetch().clear();
number = dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() + 1;
- BlockCapsule capsule1 = createTestBlockCapsule(number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
+ BlockCapsule capsule1 = createTestBlockCapsule(1533529947843L + 3000L * 6, number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
addressToProvateKeys);
dbManager.pushBlock(capsule1);
number = dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() + 1;
- BlockCapsule capsule2 = createTestBlockCapsule(number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
+ BlockCapsule capsule2 = createTestBlockCapsule(1533529947843L + 3000L * 7, number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
addressToProvateKeys);
dbManager.pushBlock(capsule2);
for(int i=0; i<2; i++){
number = dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() + 1;
- capsule = createTestBlockCapsule(number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
+ capsule = createTestBlockCapsule(1533529947843L + 3000L * 8 + 3000L * i, number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(),
addressToProvateKeys);
toFetch.add(capsule.getBlockId());
}
@@ -185,6 +185,11 @@ private Map addTestWitnessAndAccount() {
private BlockCapsule createTestBlockCapsule(
long number, ByteString hash, Map addressToProvateKeys) {
long time = System.currentTimeMillis();
+ return createTestBlockCapsule(time,number,hash,addressToProvateKeys);
+ }
+
+ private BlockCapsule createTestBlockCapsule(long time ,
+ long number, ByteString hash, Map addressToProvateKeys) {
WitnessController witnessController = dbManager.getWitnessController();
ByteString witnessAddress =
witnessController.getScheduledWitness(witnessController.getSlotAtTime(time));
@@ -216,7 +221,7 @@ public void run() {
cfgArgs.setNeedSyncCheck(false);
cfgArgs.setNodeExternalIp("127.0.0.1");
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
if (cfgArgs.isHelp()) {
logger.info("Here is the help message.");
diff --git a/src/test/java/org/tron/core/net/node/GetLostBlockIdsTest.java b/src/test/java/org/tron/core/net/node/GetLostBlockIdsTest.java
index c22c7500e2b..fc46abe04ab 100644
--- a/src/test/java/org/tron/core/net/node/GetLostBlockIdsTest.java
+++ b/src/test/java/org/tron/core/net/node/GetLostBlockIdsTest.java
@@ -5,7 +5,7 @@
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.junit.*;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.crypto.ECKey;
@@ -37,7 +37,7 @@
@Slf4j
public class GetLostBlockIdsTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private NodeImpl node;
RpcApiService rpcApiService;
PeerClient peerClient;
@@ -64,7 +64,7 @@ public void testGetLostBlockIds(){
BlockCapsule capsule = null;
for (int i = 0; i<5; i++) {
number = dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() + 1;
- capsule = createTestBlockCapsule(number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(), addressToProvateKeys);
+ capsule = createTestBlockCapsule(1533529947843L + 3000L * i ,number, dbManager.getDynamicPropertiesStore().getLatestBlockHeaderHash().getByteString(), addressToProvateKeys);
try {
dbManager.pushBlock(capsule);
} catch (Exception e) {
@@ -167,6 +167,10 @@ private Map addTestWitnessAndAccount() {
private BlockCapsule createTestBlockCapsule(
long number, ByteString hash, Map addressToProvateKeys) {
long time = System.currentTimeMillis();
+ return createTestBlockCapsule(time,number,hash,addressToProvateKeys);
+ }
+ private BlockCapsule createTestBlockCapsule(long time ,
+ long number, ByteString hash, Map addressToProvateKeys) {
WitnessController witnessController = dbManager.getWitnessController();
ByteString witnessAddress =
witnessController.getScheduledWitness(witnessController.getSlotAtTime(time));
@@ -198,7 +202,7 @@ public void run() {
cfgArgs.setNeedSyncCheck(false);
cfgArgs.setNodeExternalIp("127.0.0.1");
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
if (cfgArgs.isHelp()) {
logger.info("Here is the help message.");
diff --git a/src/test/java/org/tron/core/net/node/HandleBlockMessageTest.java b/src/test/java/org/tron/core/net/node/HandleBlockMessageTest.java
index 484ce1870fc..564810b83ca 100644
--- a/src/test/java/org/tron/core/net/node/HandleBlockMessageTest.java
+++ b/src/test/java/org/tron/core/net/node/HandleBlockMessageTest.java
@@ -1,13 +1,17 @@
package org.tron.core.net.node;
import com.google.protobuf.ByteString;
+import java.io.File;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutorService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.MapUtils;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.crypto.ECKey;
@@ -32,15 +36,11 @@
import org.tron.protos.Protocol.BlockHeader;
import org.tron.protos.Protocol.Inventory.InventoryType;
-import java.io.File;
-import java.util.Map;
-import java.util.concurrent.ExecutorService;
-
@Slf4j
public class HandleBlockMessageTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private NodeImpl node;
RpcApiService rpcApiService;
PeerClient peerClient;
@@ -67,7 +67,8 @@ private static Boolean deleteFolder(File index) {
@Test
public void testHandleBlockMessage() throws Exception {
- PeerConnection peer = new PeerConnection();
+ List activePeers = ReflectUtils.getFieldValue(pool, "activePeers");
+ PeerConnection peer = activePeers.get(0);
//收到同步请求块
BlockCapsule headBlockCapsule = dbManager.getHead();
@@ -148,7 +149,7 @@ public void run() {
cfgArgs.setNeedSyncCheck(false);
cfgArgs.setNodeExternalIp("127.0.0.1");
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
if (cfgArgs.isHelp()) {
logger.info("Here is the help message.");
diff --git a/src/test/java/org/tron/core/net/node/HandleSyncBlockTest.java b/src/test/java/org/tron/core/net/node/HandleSyncBlockTest.java
index 01ce0263140..1c9312ecf62 100644
--- a/src/test/java/org/tron/core/net/node/HandleSyncBlockTest.java
+++ b/src/test/java/org/tron/core/net/node/HandleSyncBlockTest.java
@@ -13,7 +13,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.crypto.ECKey;
@@ -42,7 +42,7 @@
@Slf4j
public class HandleSyncBlockTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private NodeImpl node;
RpcApiService rpcApiService;
PeerClient peerClient;
@@ -169,7 +169,7 @@ public void run() {
cfgArgs.setNeedSyncCheck(false);
cfgArgs.setNodeExternalIp("127.0.0.1");
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
if (cfgArgs.isHelp()) {
logger.info("Here is the help message.");
diff --git a/src/test/java/org/tron/core/net/node/HandleTransactionTest.java b/src/test/java/org/tron/core/net/node/HandleTransactionTest.java
index 2632081dc19..f81485c65db 100644
--- a/src/test/java/org/tron/core/net/node/HandleTransactionTest.java
+++ b/src/test/java/org/tron/core/net/node/HandleTransactionTest.java
@@ -6,7 +6,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.overlay.client.PeerClient;
@@ -36,7 +36,7 @@
@Slf4j
public class HandleTransactionTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private NodeImpl node;
RpcApiService rpcApiService;
PeerClient peerClient;
@@ -105,7 +105,7 @@ public void run() {
cfgArgs.setNeedSyncCheck(false);
cfgArgs.setNodeExternalIp("127.0.0.1");
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
if (cfgArgs.isHelp()) {
logger.info("Here is the help message.");
diff --git a/src/test/java/org/tron/core/net/node/NodeImplTest.java b/src/test/java/org/tron/core/net/node/NodeImplTest.java
index e9864d851db..16dc288d4ce 100644
--- a/src/test/java/org/tron/core/net/node/NodeImplTest.java
+++ b/src/test/java/org/tron/core/net/node/NodeImplTest.java
@@ -11,7 +11,7 @@
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.crypto.ECKey;
@@ -36,7 +36,7 @@
@Slf4j
public class NodeImplTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Application appT;
private static String dbPath = "output_nodeimpl_test";
@@ -46,7 +46,7 @@ public class NodeImplTest {
static {
Args.setParam(new String[]{"-d", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
Args.getInstance().setSolidityNode(true);
appT = ApplicationFactory.create(context);
}
diff --git a/src/test/java/org/tron/core/net/node/StartFetchSyncBlockTest.java b/src/test/java/org/tron/core/net/node/StartFetchSyncBlockTest.java
index b0ff27acd11..e3c31187106 100644
--- a/src/test/java/org/tron/core/net/node/StartFetchSyncBlockTest.java
+++ b/src/test/java/org/tron/core/net/node/StartFetchSyncBlockTest.java
@@ -12,7 +12,7 @@
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.overlay.client.PeerClient;
@@ -37,7 +37,7 @@
@Slf4j
public class StartFetchSyncBlockTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private NodeImpl node;
RpcApiService rpcApiService;
PeerClient peerClient;
@@ -150,7 +150,7 @@ public void run() {
cfgArgs.setNeedSyncCheck(false);
cfgArgs.setNodeExternalIp("127.0.0.1");
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
if (cfgArgs.isHelp()) {
logger.info("Here is the help message.");
diff --git a/src/test/java/org/tron/core/net/node/TcpNetTest.java b/src/test/java/org/tron/core/net/node/TcpNetTest.java
index 0ac2f8cf137..3390cf18f02 100644
--- a/src/test/java/org/tron/core/net/node/TcpNetTest.java
+++ b/src/test/java/org/tron/core/net/node/TcpNetTest.java
@@ -5,7 +5,7 @@
import static org.tron.protos.Protocol.ReasonCode.DUPLICATE_PEER;
import static org.tron.protos.Protocol.ReasonCode.FORKED;
import static org.tron.protos.Protocol.ReasonCode.INCOMPATIBLE_CHAIN;
-import static org.tron.protos.Protocol.ReasonCode.INCOMPATIBLE_PROTOCOL;
+import static org.tron.protos.Protocol.ReasonCode.INCOMPATIBLE_VERSION;
import com.google.common.cache.CacheBuilder;
import io.netty.buffer.ByteBuf;
@@ -99,7 +99,7 @@ protected void decode(ChannelHandlerContext ctx, ByteBuf buffer, List ou
break;
case errorVersion:
Assert.assertEquals(msg.getType(), P2P_DISCONNECT);
- Assert.assertEquals(((DisconnectMessage) msg).getReasonCode(), INCOMPATIBLE_PROTOCOL);
+ Assert.assertEquals(((DisconnectMessage) msg).getReasonCode(), INCOMPATIBLE_VERSION);
break;
case errorSolid:
Assert.assertEquals(msg.getType(), P2P_DISCONNECT);
diff --git a/src/test/java/org/tron/core/witness/ProposalControllerTest.java b/src/test/java/org/tron/core/witness/ProposalControllerTest.java
index f85bc69f4f7..c779995569f 100644
--- a/src/test/java/org/tron/core/witness/ProposalControllerTest.java
+++ b/src/test/java/org/tron/core/witness/ProposalControllerTest.java
@@ -9,7 +9,7 @@
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.testng.collections.Lists;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
@@ -26,13 +26,13 @@
public class ProposalControllerTest {
private static Manager dbManager = new Manager();
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static String dbPath = "output_proposal_controller_test";
private static ProposalController proposalController;
static {
Args.setParam(new String[]{"-d", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@BeforeClass
diff --git a/src/test/java/org/tron/core/witness/WitnessControllerTest.java b/src/test/java/org/tron/core/witness/WitnessControllerTest.java
index 8a5ffeabed1..8270778a2ff 100644
--- a/src/test/java/org/tron/core/witness/WitnessControllerTest.java
+++ b/src/test/java/org/tron/core/witness/WitnessControllerTest.java
@@ -9,22 +9,24 @@
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.utils.ByteArray;
import org.tron.common.utils.FileUtil;
import org.tron.core.Constant;
import org.tron.core.config.DefaultConfig;
import org.tron.core.config.args.Args;
+import org.tron.core.config.args.Witness;
import org.tron.core.db.Manager;
public class WitnessControllerTest {
+
private static Manager dbManager = new Manager();
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static String dbPath = "output_witness_controller_test";
static {
- Args.setParam(new String[] {"-d", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ Args.setParam(new String[]{"-d", dbPath}, Constant.TEST_CONF);
+ context = new TronApplicationContext(DefaultConfig.class);
}
@BeforeClass
@@ -51,10 +53,9 @@ public void testSlot() {
// assertEquals(2, dbManager.getWitnessController().getSlotAtTime(21500));
// assertEquals(19, dbManager.getWitnessController().getHeadSlot());
-
}
-// @Test
+ // @Test
public void testWitnessSchedule() {
// no witness produce block
@@ -106,4 +107,26 @@ public void testWitnessSchedule() {
assertEquals(a, dbManager.getWitnessController().getScheduledWitness(3));
assertEquals(b, dbManager.getWitnessController().getScheduledWitness(4));
}
+
+ @Test
+ public void testTryRemoveThePowerOfTheGr() {
+
+ Witness witness = Args.getInstance().getGenesisBlock().getWitnesses().get(0);
+ assertEquals(105, witness.getVoteCount());
+
+ dbManager.getDynamicPropertiesStore().saveRemoveThePowerOfTheGr(-1);
+ dbManager.getWitnessController().tryRemoveThePowerOfTheGr();
+ assertEquals(105, dbManager.getWitnessStore().get(witness.getAddress()).getVoteCount());
+
+ dbManager.getDynamicPropertiesStore().saveRemoveThePowerOfTheGr(1);
+ dbManager.getWitnessController().tryRemoveThePowerOfTheGr();
+ assertEquals(0, dbManager.getWitnessStore().get(witness.getAddress()).getVoteCount());
+
+ dbManager.getWitnessController().tryRemoveThePowerOfTheGr();
+ assertEquals(0, dbManager.getWitnessStore().get(witness.getAddress()).getVoteCount());
+
+
+ }
+
+
}
diff --git a/src/test/java/org/tron/program/AccountVoteWitnessTest.java b/src/test/java/org/tron/program/AccountVoteWitnessTest.java
index 3a433a71bf1..5726ca85a47 100755
--- a/src/test/java/org/tron/program/AccountVoteWitnessTest.java
+++ b/src/test/java/org/tron/program/AccountVoteWitnessTest.java
@@ -8,7 +8,7 @@
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.core.Constant;
import org.tron.core.capsule.AccountCapsule;
import org.tron.core.capsule.WitnessCapsule;
@@ -20,14 +20,14 @@
@Slf4j
public class AccountVoteWitnessTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static Manager dbManager;
private static String dbPath = "output_witness_test";
static {
Args.setParam(new String[] {"-d", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
}
/** init db. */
diff --git a/src/test/java/org/tron/program/SolidityNodeTest.java b/src/test/java/org/tron/program/SolidityNodeTest.java
index 8d8df4a4cfd..e2e68677e65 100755
--- a/src/test/java/org/tron/program/SolidityNodeTest.java
+++ b/src/test/java/org/tron/program/SolidityNodeTest.java
@@ -6,7 +6,7 @@
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
-import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.tron.common.application.TronApplicationContext;
import org.tron.common.application.Application;
import org.tron.common.application.ApplicationFactory;
import org.tron.common.overlay.client.DatabaseGrpcClient;
@@ -20,7 +20,7 @@
@Slf4j
public class SolidityNodeTest {
- private static AnnotationConfigApplicationContext context;
+ private static TronApplicationContext context;
private static RpcApiService rpcApiService;
private static Application appT;
@@ -28,7 +28,7 @@ public class SolidityNodeTest {
static {
Args.setParam(new String[]{"-d", dbPath}, Constant.TEST_CONF);
- context = new AnnotationConfigApplicationContext(DefaultConfig.class);
+ context = new TronApplicationContext(DefaultConfig.class);
Args.getInstance().setSolidityNode(true);
appT = ApplicationFactory.create(context);
rpcApiService = context.getBean(RpcApiService.class);
diff --git a/src/test/java/stest/tron/wallet/account/WalletTestAccount001.java b/src/test/java/stest/tron/wallet/account/WalletTestAccount001.java
index 5aa7686ae95..ef576012ee1 100644
--- a/src/test/java/stest/tron/wallet/account/WalletTestAccount001.java
+++ b/src/test/java/stest/tron/wallet/account/WalletTestAccount001.java
@@ -5,6 +5,7 @@
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
import java.math.BigInteger;
+import java.util.Random;
import java.util.concurrent.TimeUnit;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@@ -19,14 +20,13 @@
import org.tron.api.WalletSolidityGrpc;
import org.tron.common.crypto.ECKey;
import org.tron.common.utils.ByteArray;
+import org.tron.core.Wallet;
import org.tron.protos.Protocol.Account;
import org.tron.protos.Protocol.Block;
import stest.tron.wallet.common.client.Configuration;
import stest.tron.wallet.common.client.Parameter.CommonConstant;
-import stest.tron.wallet.common.client.WalletClient;
-import stest.tron.wallet.common.client.utils.Base58;
import stest.tron.wallet.common.client.utils.PublicMethed;
-import org.tron.core.Wallet;
+
@Slf4j
@@ -109,6 +109,7 @@ public void testqueryaccountfromsoliditynode() {
Assert.assertTrue(invalidQueryResult.getAccountName().isEmpty());
Assert.assertTrue(invalidQueryResult.getAddress().isEmpty());
+
}
@AfterClass
diff --git a/src/test/java/stest/tron/wallet/account/WalletTestAccount003.java b/src/test/java/stest/tron/wallet/account/WalletTestAccount003.java
index 362a896685d..1fa5641127a 100644
--- a/src/test/java/stest/tron/wallet/account/WalletTestAccount003.java
+++ b/src/test/java/stest/tron/wallet/account/WalletTestAccount003.java
@@ -126,7 +126,7 @@ public void testCreateAccount() {
}
}
- @Test(enabled = false)
+ @Test(enabled = true)
public void testUpdateAccount() {
Account tryToUpdateAccount = queryAccount(lowBalTest, blockingStubFull);
if (tryToUpdateAccount.getAccountName().isEmpty()) {
@@ -139,11 +139,11 @@ public void testUpdateAccount() {
Assert.assertTrue(updateAccount(lowBalAddress, mostLongName.getBytes(), lowBalTest));
tryToUpdateAccount = queryAccount(lowBalTest, blockingStubFull);
Assert.assertFalse(tryToUpdateAccount.getAccountName().isEmpty());
- Assert.assertFalse(updateAccount(lowBalAddress, "secondUpdateName".getBytes(), lowBalTest));
+ Assert.assertTrue(updateAccount(lowBalAddress, "secondUpdateName".getBytes(), lowBalTest));
}
}
- @Test(enabled = false)
+ @Test(enabled = true)
public void testNoBalanceCreateAssetIssue() {
Account lowaccount = queryAccount(lowBalTest, blockingStubFull);
if (lowaccount.getBalance() > 0) {
@@ -161,19 +161,19 @@ public void testNoBalanceCreateAssetIssue() {
logger.info("nobalancecreateassetissue");
}
- @Test(enabled = false)
+ @Test(enabled = true)
public void testNoBalanceTransferTrx() {
//Send Coin failed when there is no enough balance.
Assert.assertFalse(sendCoin(toAddress, 100000000000000000L, lowBalAddress, lowBalTest));
}
- @Test(enabled = false)
+ @Test(enabled = true)
public void testNoBalanceCreateWitness() {
//Apply to be super witness failed when no enough balance.
Assert.assertFalse(createWitness(lowBalAddress, fromAddress, lowBalTest));
}
- @Test(enabled = false)
+ @Test(enabled = true)
public void testNoFreezeBalanceToUnfreezeBalance() {
//Unfreeze account failed when no freeze balance
Account noFreezeAccount = queryAccount(lowBalTest, blockingStubFull);
diff --git a/src/test/java/stest/tron/wallet/account/WalletTestAccount008.java b/src/test/java/stest/tron/wallet/account/WalletTestAccount008.java
new file mode 100644
index 00000000000..95da20f4a8b
--- /dev/null
+++ b/src/test/java/stest/tron/wallet/account/WalletTestAccount008.java
@@ -0,0 +1,156 @@
+package stest.tron.wallet.account;
+
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import java.util.Random;
+import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.Test;
+import org.tron.api.GrpcAPI.AccountNetMessage;
+import org.tron.api.WalletGrpc;
+import org.tron.common.crypto.ECKey;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.Utils;
+import org.tron.core.Wallet;
+import org.tron.protos.Protocol.Account;
+import stest.tron.wallet.common.client.Configuration;
+import stest.tron.wallet.common.client.Parameter.CommonConstant;
+import stest.tron.wallet.common.client.utils.PublicMethed;
+
+@Slf4j
+public class WalletTestAccount008 {
+ private final String testKey002 =
+ "FC8BF0238748587B9617EB6D15D47A66C0E07C1A1959033CF249C6532DC29FE6";
+
+ private final byte[] fromAddress = PublicMethed.getFinalAddress(testKey002);
+
+ private static final long now = System.currentTimeMillis();
+ private static String name = "AssetIssue012_" + Long.toString(now);
+ private static final long totalSupply = now;
+ private static final long sendAmount = 10000000000L;
+
+ private ManagedChannel channelFull = null;
+ private WalletGrpc.WalletBlockingStub blockingStubFull = null;
+ private String fullnode = Configuration.getByPath("testng.conf").getStringList("fullnode.ip.list")
+ .get(0);
+
+ private static final long FREENETLIMIT = 5000L;
+ private static final long BASELINE = 4800L;
+
+ ECKey ecKey1 = new ECKey(Utils.getRandom());
+ byte[] account008Address = ecKey1.getAddress();
+ String account008Key = ByteArray.toHexString(ecKey1.getPrivKeyBytes());
+
+ ECKey ecKey2 = new ECKey(Utils.getRandom());
+ byte[] account008SecondAddress = ecKey2.getAddress();
+ String account008SecondKey = ByteArray.toHexString(ecKey2.getPrivKeyBytes());
+
+ ECKey ecKey3 = new ECKey(Utils.getRandom());
+ byte[] account008InvalidAddress = ecKey3.getAddress();
+ String account008InvalidKey = ByteArray.toHexString(ecKey3.getPrivKeyBytes());
+
+
+ @BeforeSuite
+ public void beforeSuite() {
+ Wallet wallet = new Wallet();
+ Wallet.setAddressPreFixByte(CommonConstant.ADD_PRE_FIX_BYTE_MAINNET);
+ }
+
+ @BeforeClass(enabled = true)
+ public void beforeClass() {
+ PublicMethed.printAddress(account008Key);
+ PublicMethed.printAddress(account008SecondKey);
+ channelFull = ManagedChannelBuilder.forTarget(fullnode)
+ .usePlaintext(true)
+ .build();
+ blockingStubFull = WalletGrpc.newBlockingStub(channelFull);
+
+ Assert.assertTrue(PublicMethed.sendcoin(account008Address,10000000,
+ fromAddress,testKey002,blockingStubFull));
+ Assert.assertTrue(PublicMethed.sendcoin(account008SecondAddress,10000000,
+ fromAddress,testKey002,blockingStubFull));
+ Assert.assertTrue(PublicMethed.sendcoin(account008InvalidAddress,10000000,
+ fromAddress,testKey002,blockingStubFull));
+
+ }
+
+ @Test(enabled = true)
+ public void testSetAccountId() {
+ String lessThan7Char = getRandomStr(7);
+ String moreThan32Char = getRandomStr(33);
+ String shortAccountId = getRandomStr(8);
+ String longAccountId = getRandomStr(32);
+ //Less than 7 char can't set success.
+ Assert.assertFalse(PublicMethed.setAccountId(lessThan7Char.getBytes(),account008Address,
+ account008Key,blockingStubFull));
+ //More than 33 char can't set success.
+ Assert.assertFalse(PublicMethed.setAccountId(moreThan32Char.getBytes(),account008Address,
+ account008Key,blockingStubFull));
+ //The shortest char is 8,it can success.
+ Assert.assertTrue(PublicMethed.setAccountId(shortAccountId.getBytes(),account008Address,
+
+ account008Key,blockingStubFull));
+ //One account only can set account id 1 time.
+ Assert.assertFalse(PublicMethed.setAccountId(longAccountId.getBytes(),account008Address,
+ account008Key,blockingStubFull));
+ //One account id only can set by one account, when another account try to set, is will failed.
+ Assert.assertFalse(PublicMethed.setAccountId(shortAccountId.getBytes(),account008SecondAddress,
+ account008SecondKey,blockingStubFull));
+ //The longest char is 32, it can success.
+ Assert.assertTrue(PublicMethed.setAccountId(longAccountId.getBytes(),account008SecondAddress,
+ account008SecondKey,blockingStubFull));
+
+ Account account008Info = PublicMethed.queryAccount(account008Key,blockingStubFull);
+ Assert.assertTrue(ByteArray.toStr(account008Info.getAccountId().toByteArray()).length() == 8);
+ Account account008SecondInfo = PublicMethed.queryAccount(account008SecondKey,blockingStubFull);
+ Assert.assertTrue(ByteArray.toStr(account008SecondInfo.getAccountId()
+ .toByteArray()).length() == 32);
+
+ }
+
+ @Test(enabled = true)
+ public void testSetInvalidAccountId() {
+ String hasSpaceAccountId = getRandomStr(4) + " " + getRandomStr(10);
+ String hasChineseAccountId = getRandomStr(4) + "中文账户名称";
+ Assert.assertFalse(PublicMethed.setAccountId(hasSpaceAccountId.getBytes(),
+ account008InvalidAddress, account008InvalidKey,blockingStubFull));
+ Assert.assertFalse(PublicMethed.setAccountId(hasChineseAccountId.getBytes(),
+ account008InvalidAddress, account008InvalidKey,blockingStubFull));
+
+
+ }
+
+ @AfterClass(enabled = true)
+ public void shutdown() throws InterruptedException {
+ if (channelFull != null) {
+ channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+ }
+
+
+ public static String getRandomStr(int length) {
+ String base = "abcdefghijklmnopqrstuvwxyz0123456789";
+ int randomNum;
+ char randomChar;
+ Random random = new Random();
+ // StringBuffer类型的可以append增加字符
+ StringBuffer str = new StringBuffer();
+
+ for (int i = 0; i < length; i++) {
+ // 可生成[0,n)之间的整数,获得随机位置
+ randomNum = random.nextInt(base.length());
+ // 获得随机位置对应的字符
+ randomChar = base.charAt(randomNum);
+ // 组成一个随机字符串
+ str.append(randomChar);
+ }
+ return str.toString();
+ }
+
+}
+
+
diff --git a/src/test/java/stest/tron/wallet/account/WalletTestAccount009.java b/src/test/java/stest/tron/wallet/account/WalletTestAccount009.java
new file mode 100644
index 00000000000..04f79af4d11
--- /dev/null
+++ b/src/test/java/stest/tron/wallet/account/WalletTestAccount009.java
@@ -0,0 +1,122 @@
+package stest.tron.wallet.account;
+
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.Test;
+import org.tron.api.GrpcAPI.AccountResourceMessage;
+import org.tron.api.WalletGrpc;
+import org.tron.common.crypto.ECKey;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.Utils;
+import org.tron.core.Wallet;
+import org.tron.protos.Protocol.Account;
+import stest.tron.wallet.common.client.Configuration;
+import stest.tron.wallet.common.client.Parameter.CommonConstant;
+import stest.tron.wallet.common.client.utils.PublicMethed;
+
+@Slf4j
+public class WalletTestAccount009 {
+ private final String testKey002 =
+ "FC8BF0238748587B9617EB6D15D47A66C0E07C1A1959033CF249C6532DC29FE6";
+
+ private final byte[] fromAddress = PublicMethed.getFinalAddress(testKey002);
+
+ private static final long now = System.currentTimeMillis();
+ private static String name = "AssetIssue012_" + Long.toString(now);
+ private static final long totalSupply = now;
+ private static final long sendAmount = 10000000000L;
+
+ private ManagedChannel channelFull = null;
+ private WalletGrpc.WalletBlockingStub blockingStubFull = null;
+ private String fullnode = Configuration.getByPath("testng.conf").getStringList("fullnode.ip.list")
+ .get(0);
+
+ private static final long FREENETLIMIT = 5000L;
+ private static final long BASELINE = 4800L;
+
+ ECKey ecKey1 = new ECKey(Utils.getRandom());
+ byte[] account009Address = ecKey1.getAddress();
+ String account009Key = ByteArray.toHexString(ecKey1.getPrivKeyBytes());
+
+ ECKey ecKey2 = new ECKey(Utils.getRandom());
+ byte[] account009SecondAddress = ecKey2.getAddress();
+ String account009SecondKey = ByteArray.toHexString(ecKey2.getPrivKeyBytes());
+
+ ECKey ecKey3 = new ECKey(Utils.getRandom());
+ byte[] account009InvalidAddress = ecKey3.getAddress();
+ String account009InvalidKey = ByteArray.toHexString(ecKey3.getPrivKeyBytes());
+
+
+ @BeforeSuite
+ public void beforeSuite() {
+ Wallet wallet = new Wallet();
+ Wallet.setAddressPreFixByte(CommonConstant.ADD_PRE_FIX_BYTE_MAINNET);
+ }
+
+ @BeforeClass(enabled = true)
+ public void beforeClass() {
+ PublicMethed.printAddress(account009Key);
+ PublicMethed.printAddress(account009SecondKey);
+ channelFull = ManagedChannelBuilder.forTarget(fullnode)
+ .usePlaintext(true)
+ .build();
+ blockingStubFull = WalletGrpc.newBlockingStub(channelFull);
+
+ Assert.assertTrue(PublicMethed.sendcoin(account009Address,10000000,
+ fromAddress,testKey002,blockingStubFull));
+ Assert.assertTrue(PublicMethed.sendcoin(account009SecondAddress,10000000,
+ fromAddress,testKey002,blockingStubFull));
+ Assert.assertTrue(PublicMethed.sendcoin(account009InvalidAddress,10000000,
+ fromAddress,testKey002,blockingStubFull));
+
+ }
+
+ @Test(enabled = true)
+ public void testGetEnergy() {
+ Account account009Info = PublicMethed.queryAccount(account009Key,blockingStubFull);
+ Assert.assertTrue(account009Info.getAccountResource().getEnergyUsage() == 0);
+ Assert.assertTrue(account009Info.getAccountResource().getFrozenBalanceForEnergy()
+ .getExpireTime() == 0);
+
+ Assert.assertTrue(PublicMethed.freezeBalanceGetEnergy(account009Address, 1000000L,
+ 3,1,account009Key,blockingStubFull));
+ account009Info = PublicMethed.queryAccount(account009Key,blockingStubFull);
+ Assert.assertTrue(account009Info.getAccountResource().getEnergyUsage() == 0);
+ Assert.assertTrue(account009Info.getAccountResource().getFrozenBalanceForEnergy()
+ .getFrozenBalance() == 1000000L);
+
+ AccountResourceMessage account009Resource = PublicMethed.getAccountResource(account009Address,
+ blockingStubFull);
+ Assert.assertTrue(account009Resource.getTotalEnergyLimit() == 50000000000L);
+ Assert.assertTrue(account009Resource.getEnergyLimit() > 0);
+ Assert.assertTrue(account009Resource.getTotalEnergyWeight() >= 1);
+ }
+
+ @Test(enabled = true)
+ public void testGetEnergyInvalid() {
+ //The resourceCode can only be 0 or 1
+ Assert.assertTrue(PublicMethed.freezeBalanceGetEnergy(account009InvalidAddress,
+ 1000000L, 3,0,account009InvalidKey,blockingStubFull));
+ Assert.assertFalse(PublicMethed.freezeBalanceGetEnergy(account009InvalidAddress, 1000000L,
+ 3,-1,account009InvalidKey,blockingStubFull));
+ Assert.assertFalse(PublicMethed.freezeBalanceGetEnergy(account009InvalidAddress, 1000000L,
+ 3,2,account009InvalidKey,blockingStubFull));
+
+ }
+
+
+ @AfterClass(enabled = true)
+ public void shutdown() throws InterruptedException {
+ if (channelFull != null) {
+ channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+ }
+}
+
+
diff --git a/src/test/java/stest/tron/wallet/account/WalletTestAccount010.java b/src/test/java/stest/tron/wallet/account/WalletTestAccount010.java
new file mode 100644
index 00000000000..3ef53ab174c
--- /dev/null
+++ b/src/test/java/stest/tron/wallet/account/WalletTestAccount010.java
@@ -0,0 +1,129 @@
+package stest.tron.wallet.account;
+
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.Test;
+import org.tron.api.GrpcAPI.AccountResourceMessage;
+import org.tron.api.WalletGrpc;
+import org.tron.common.crypto.ECKey;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.Utils;
+import org.tron.core.Wallet;
+import org.tron.protos.Protocol.Account;
+import stest.tron.wallet.common.client.Configuration;
+import stest.tron.wallet.common.client.Parameter.CommonConstant;
+import stest.tron.wallet.common.client.utils.PublicMethed;
+
+@Slf4j
+public class WalletTestAccount010 {
+ private final String testKey002 =
+ "FC8BF0238748587B9617EB6D15D47A66C0E07C1A1959033CF249C6532DC29FE6";
+
+ private final byte[] fromAddress = PublicMethed.getFinalAddress(testKey002);
+
+ private static final long now = System.currentTimeMillis();
+
+ private ManagedChannel channelFull = null;
+ private WalletGrpc.WalletBlockingStub blockingStubFull = null;
+ private String fullnode = Configuration.getByPath("testng.conf").getStringList("fullnode.ip.list")
+ .get(0);
+
+ ECKey ecKey1 = new ECKey(Utils.getRandom());
+ byte[] account010Address = ecKey1.getAddress();
+ String account010Key = ByteArray.toHexString(ecKey1.getPrivKeyBytes());
+
+ ECKey ecKey2 = new ECKey(Utils.getRandom());
+ byte[] account010SecondAddress = ecKey2.getAddress();
+ String account010SecondKey = ByteArray.toHexString(ecKey2.getPrivKeyBytes());
+
+ ECKey ecKey3 = new ECKey(Utils.getRandom());
+ byte[] account010InvalidAddress = ecKey3.getAddress();
+ String account010InvalidKey = ByteArray.toHexString(ecKey3.getPrivKeyBytes());
+
+
+ @BeforeSuite
+ public void beforeSuite() {
+ Wallet wallet = new Wallet();
+ Wallet.setAddressPreFixByte(CommonConstant.ADD_PRE_FIX_BYTE_MAINNET);
+ }
+
+ @BeforeClass(enabled = false)
+ public void beforeClass() {
+ PublicMethed.printAddress(account010Key);
+ PublicMethed.printAddress(account010SecondKey);
+ channelFull = ManagedChannelBuilder.forTarget(fullnode)
+ .usePlaintext(true)
+ .build();
+ blockingStubFull = WalletGrpc.newBlockingStub(channelFull);
+
+ Assert.assertTrue(PublicMethed.sendcoin(account010Address,100000000,
+ fromAddress,testKey002,blockingStubFull));
+ Assert.assertTrue(PublicMethed.sendcoin(account010SecondAddress,100000000,
+ fromAddress,testKey002,blockingStubFull));
+ Assert.assertTrue(PublicMethed.sendcoin(account010InvalidAddress,100000000,
+ fromAddress,testKey002,blockingStubFull));
+
+ }
+
+ @Test(enabled = false)
+ public void testGetStorage() {
+ Account account010Info = PublicMethed.queryAccount(account010Key,blockingStubFull);
+ Assert.assertTrue(account010Info.getAccountResource().getStorageLimit() == 0);
+ Assert.assertTrue(account010Info.getAccountResource().getLatestExchangeStorageTime() == 0);
+
+ Assert.assertTrue(PublicMethed.buyStorage(100000000L,account010Address,account010Key,
+ blockingStubFull));
+
+ account010Info = PublicMethed.queryAccount(account010Key,blockingStubFull);
+ Assert.assertTrue(account010Info.getAccountResource().getStorageLimit() > 0);
+ Assert.assertTrue(account010Info.getAccountResource().getLatestExchangeStorageTime() > 0);
+
+ AccountResourceMessage account010Resource = PublicMethed.getAccountResource(account010Address,
+ blockingStubFull);
+ Assert.assertTrue(account010Resource.getStorageLimit() > 0);
+ }
+
+ @Test(enabled = false)
+ public void testSellStorage() {
+ AccountResourceMessage account010Resource = PublicMethed.getAccountResource(account010Address,
+ blockingStubFull);
+ Long storageLimit = account010Resource.getStorageLimit();
+ Account account001Info = PublicMethed.queryAccount(account010Key,blockingStubFull);
+ Assert.assertTrue(account001Info.getBalance() == 0);
+ //When there is no enough storage,sell failed.
+ Assert.assertFalse(PublicMethed.sellStorage(storageLimit + 1,account010Address,account010Key,
+ blockingStubFull));
+ //Can not sell 0 storage
+ Assert.assertFalse(PublicMethed.sellStorage(0,account010Address,account010Key,
+ blockingStubFull));
+ //Sell all storage.
+ Assert.assertTrue(PublicMethed.sellStorage(storageLimit,account010Address,account010Key,
+ blockingStubFull));
+ account010Resource = PublicMethed.getAccountResource(account010Address,
+ blockingStubFull);
+ storageLimit = account010Resource.getStorageLimit();
+ Assert.assertTrue(storageLimit == 0);
+ account001Info = PublicMethed.queryAccount(account010Key,blockingStubFull);
+ Assert.assertTrue(account001Info.getBalance() > 0);
+
+
+
+ }
+
+
+
+ @AfterClass(enabled = false)
+ public void shutdown() throws InterruptedException {
+ if (channelFull != null) {
+ channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+ }
+}
+
+
diff --git a/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue002.java b/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue002.java
index b41e09ff7a1..8ef7c66a8a7 100644
--- a/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue002.java
+++ b/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue002.java
@@ -97,7 +97,8 @@ public void beforeClass() {
testKey002,blockingStubFull));
//Create a new Asset Issue
Assert.assertTrue(PublicMethed.createAssetIssue(participateAccountAddress,
- name, totalSupply, 1, 1, start, end, 1, description, url,
+ name, totalSupply, 1, 1, System.currentTimeMillis() + 2000,
+ System.currentTimeMillis() + 1000000000, 1, description, url,
2000L,2000L, 1L, 1L,
participateAccountKey,blockingStubFull));
} else {
diff --git a/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue003.java b/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue003.java
index 0c4b9dcb0f4..089f01dbb2f 100644
--- a/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue003.java
+++ b/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue003.java
@@ -185,11 +185,6 @@ public void beforeClass() {
//Test not in the duration time, participate failed.
Assert.assertFalse(PublicMethed.participateAssetIssue(fromAddress, name.getBytes(), 1L,
toAddress, testKey003,blockingStubFull));
- //Test another address try to create the same name asset issue, create failed.
- Assert.assertFalse(PublicMethed.createAssetIssue(toAddress, name, totalSupply, 1, 10,
- start, end, 2, description, url, 10000L,10000L,
- 1L, 3652L, testKey003,blockingStubFull));
-
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
diff --git a/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue007.java b/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue007.java
index 3244e36bc7a..8f02bff4870 100644
--- a/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue007.java
+++ b/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue007.java
@@ -51,7 +51,7 @@ public class WalletTestAssetIssue007 {
private static final long totalSupply = now;
private static final long sendAmount = 10000000000L;
private static final long netCostMeasure = 200L;
- private static final Integer trxNum = 2;
+ private static final Integer trxNum = 1;
private static final Integer icoNum = 1;
Long freeAssetNetLimit = 10000L;
@@ -117,9 +117,11 @@ public void beforeClass() {
}
}
- @Test(enabled = false)
+ @Test(enabled = true)
public void testParticipateAssetIssueUseParticipaterBandwidth() {
logger.info(name);
+ Assert.assertTrue(PublicMethed.waitProduceNextBlock(blockingStubFull));
+ Assert.assertTrue(PublicMethed.waitProduceNextBlock(blockingStubFull));
//When no balance, participate an asset issue
Assert.assertFalse(PublicMethed.participateAssetIssue(asset007Address, name.getBytes(),
1L, participateAssetAddress, participateAssetCreateKey,blockingStubFull));
@@ -139,7 +141,6 @@ public void testParticipateAssetIssueUseParticipaterBandwidth() {
Assert.assertTrue(participateAccountBeforeNetUsed == 0);
//Participate an assetIssue, then query the net information.
- //Assert.assertTrue(PublicMethed.waitProduceNextBlock(blockingStubFull));
ByteString assetNameBs = ByteString.copyFrom(name.getBytes());
GrpcAPI.BytesMessage request1 = GrpcAPI.BytesMessage.newBuilder().setValue(assetNameBs).build();
Contract.AssetIssueContract assetIssueByName = blockingStubFull.getAssetIssueByName(request1);
@@ -180,7 +181,7 @@ public void testParticipateAssetIssueUseParticipaterBandwidth() {
participateInfo = PublicMethed.queryAccount(participateAssetCreateKey,blockingStubFull);
final Long afterBalance = participateInfo.getBalance();
- Assert.assertTrue(beforeBalance - trxNum*1*icoNum > afterBalance);
+ Assert.assertTrue(beforeBalance - trxNum*1*icoNum >= afterBalance);
diff --git a/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue011.java b/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue011.java
index f97bcea13cd..67a5265fafa 100644
--- a/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue011.java
+++ b/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue011.java
@@ -73,8 +73,8 @@ public void beforeSuite() {
@BeforeClass(enabled = true)
public void beforeClass() {
- logger.info(testKeyForAssetIssue011);
- logger.info(transferAssetCreateKey);
+ PublicMethed.printAddress(testKeyForAssetIssue011);
+ PublicMethed.printAddress(transferAssetCreateKey);
channelFull = ManagedChannelBuilder.forTarget(fullnode)
.usePlaintext(true)
diff --git a/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue018.java b/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue018.java
new file mode 100644
index 00000000000..53ef65ac485
--- /dev/null
+++ b/src/test/java/stest/tron/wallet/assetissue/WalletTestAssetIssue018.java
@@ -0,0 +1,355 @@
+package stest.tron.wallet.assetissue;
+
+import com.google.protobuf.ByteString;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import java.math.BigInteger;
+import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.spongycastle.util.encoders.Hex;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.Test;
+import org.tron.api.GrpcAPI;
+import org.tron.api.GrpcAPI.NumberMessage;
+import org.tron.api.GrpcAPI.Return;
+import org.tron.api.WalletGrpc;
+import org.tron.common.crypto.ECKey;
+import org.tron.common.utils.ByteArray;
+import org.tron.common.utils.Utils;
+import org.tron.core.Wallet;
+import org.tron.protos.Contract;
+import org.tron.protos.Protocol.Account;
+import org.tron.protos.Protocol.Block;
+import org.tron.protos.Protocol.Transaction;
+import stest.tron.wallet.common.client.Configuration;
+import stest.tron.wallet.common.client.Parameter.CommonConstant;
+import stest.tron.wallet.common.client.utils.PublicMethed;
+import stest.tron.wallet.common.client.utils.TransactionUtils;
+
+@Slf4j
+public class WalletTestAssetIssue018 {
+
+ //testng001、testng002、testng003、testng004
+ private final String testKey002 =
+ "FC8BF0238748587B9617EB6D15D47A66C0E07C1A1959033CF249C6532DC29FE6";
+ private final String testKey003 =
+ "6815B367FDDE637E53E9ADC8E69424E07724333C9A2B973CFA469975E20753FC";
+
+ /* //testng001、testng002、testng003、testng004
+ private static final byte[] fromAddress = Base58
+ .decodeFromBase58Check("THph9K2M2nLvkianrMGswRhz5hjSA9fuH7");
+ private static final byte[] toAddress = Base58
+ .decodeFromBase58Check("TV75jZpdmP2juMe1dRwGrwpV6AMU6mr1EU");*/
+
+ private final byte[] fromAddress = PublicMethed.getFinalAddress(testKey002);
+ private final byte[] toAddress = PublicMethed.getFinalAddress(testKey003);
+
+ private static final long now = System.currentTimeMillis();
+ private static final String name = "testAssetIssue018_" + Long.toString(now);
+ private static final long totalSupply = now;
+ String description = "just-test";
+ String url = "https://github.com/tronprotocol/wallet-cli/";
+
+ private ManagedChannel channelFull = null;
+ private WalletGrpc.WalletBlockingStub blockingStubFull = null;
+ private String fullnode = Configuration.getByPath("testng.conf").getStringList("fullnode.ip.list")
+ .get(0);
+
+ //get account
+ ECKey ecKey1 = new ECKey(Utils.getRandom());
+ byte[] assetAccount1Address = ecKey1.getAddress();
+ String assetAccount1Key = ByteArray.toHexString(ecKey1.getPrivKeyBytes());
+
+ ECKey ecKey2 = new ECKey(Utils.getRandom());
+ byte[] assetAccount2Address = ecKey2.getAddress();
+ String assetAccount2Key = ByteArray.toHexString(ecKey2.getPrivKeyBytes());
+
+ ECKey ecKey3 = new ECKey(Utils.getRandom());
+ byte[] assetAccount3Address = ecKey3.getAddress();
+ String assetAccount3Key = ByteArray.toHexString(ecKey3.getPrivKeyBytes());
+
+ @BeforeSuite
+ public void beforeSuite() {
+ Wallet wallet = new Wallet();
+ Wallet.setAddressPreFixByte(CommonConstant.ADD_PRE_FIX_BYTE_MAINNET);
+ }
+
+ @BeforeClass(enabled = true)
+ public void beforeClass() {
+ channelFull = ManagedChannelBuilder.forTarget(fullnode)
+ .usePlaintext(true)
+ .build();
+ blockingStubFull = WalletGrpc.newBlockingStub(channelFull);
+ PublicMethed.printAddress(assetAccount1Key);
+ PublicMethed.printAddress(assetAccount2Key);
+ PublicMethed.printAddress(assetAccount3Key);
+ }
+
+ @Test(enabled = true)
+ public void testSameAssetissueName() {
+ logger.info(name);
+ logger.info("total supply is " + Long.toString(totalSupply));
+ //send coin to the new account
+ Assert.assertTrue(PublicMethed.sendcoin(assetAccount1Address,2048000000,fromAddress,
+ testKey002,blockingStubFull));
+ Assert.assertTrue(PublicMethed.sendcoin(assetAccount2Address,2048000000,fromAddress,
+ testKey002,blockingStubFull));
+ Assert.assertTrue(PublicMethed.sendcoin(assetAccount3Address,2048000000,fromAddress,
+ testKey002,blockingStubFull));
+
+ //Create 3 the same name token.
+ Long start = System.currentTimeMillis() + 3000;
+ Long end = System.currentTimeMillis() + 1000000000;
+ Assert.assertTrue(PublicMethed.createAssetIssue(assetAccount1Address,
+ name, totalSupply, 1, 1, start, end, 1, description, url,
+ 2000L,2000L, 1L,1L,assetAccount1Key,blockingStubFull));
+ start = System.currentTimeMillis() + 3000;
+ end = System.currentTimeMillis() + 1000000000;
+ Assert.assertTrue(PublicMethed.createAssetIssue(assetAccount2Address,
+ name, totalSupply + 1, 2, 2, start, end, 2, description, url,
+ 3000L,3000L, 2L,2L,assetAccount2Key,blockingStubFull));
+ start = System.currentTimeMillis() + 3000;
+ end = System.currentTimeMillis() + 1000000000;
+ Assert.assertTrue(PublicMethed.createAssetIssue(assetAccount3Address,
+ name, totalSupply + 2, 3, 3, start, end, 3, description, url,
+ 4000L,4000L, 3L,2L,assetAccount3Key,blockingStubFull));
+
+
+ //Get asset issue by name
+ String asset1Name = name;
+ String asset2Name = name + "_1";
+ String asset3Name = name + "_2";
+ ByteString assetNameBs = ByteString.copyFrom(asset1Name.getBytes());
+ GrpcAPI.BytesMessage request = GrpcAPI.BytesMessage.newBuilder().setValue(assetNameBs).build();
+ Contract.AssetIssueContract assetIssueByName = blockingStubFull.getAssetIssueByName(request);
+ Assert.assertTrue(assetIssueByName.getVoteScore() == 1);
+
+ assetNameBs = ByteString.copyFrom(asset2Name.getBytes());
+ request = GrpcAPI.BytesMessage.newBuilder().setValue(assetNameBs).build();
+ assetIssueByName = blockingStubFull.getAssetIssueByName(request);
+ Assert.assertTrue(assetIssueByName.getVoteScore() == 2);
+
+ assetNameBs = ByteString.copyFrom(asset3Name.getBytes());
+ request = GrpcAPI.BytesMessage.newBuilder().setValue(assetNameBs).build();
+ assetIssueByName = blockingStubFull.getAssetIssueByName(request);
+ Assert.assertTrue(assetIssueByName.getVoteScore() == 3);
+
+ //Transfer asset issue.
+ Assert.assertTrue(PublicMethed.transferAsset(assetAccount2Address,
+ asset1Name.getBytes(),1L,assetAccount1Address,assetAccount1Key,blockingStubFull));
+
+ Assert.assertTrue(PublicMethed.transferAsset(assetAccount3Address,
+ asset2Name.getBytes(),2L,assetAccount2Address,assetAccount2Key,blockingStubFull));
+
+ Assert.assertTrue(PublicMethed.transferAsset(assetAccount1Address,
+ asset3Name.getBytes(),3L,assetAccount3Address,assetAccount3Key,blockingStubFull));
+
+ try {
+ Thread.sleep(10000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ //Participate asset issue.
+ Assert.assertTrue(PublicMethed.participateAssetIssue(assetAccount3Address,asset3Name.getBytes(),
+ 1L,assetAccount2Address,assetAccount2Key,blockingStubFull));
+
+ Assert.assertTrue(PublicMethed.participateAssetIssue(assetAccount1Address,asset1Name.getBytes(),
+ 2L,assetAccount3Address,assetAccount3Key,blockingStubFull));
+
+ Assert.assertTrue(PublicMethed.participateAssetIssue(assetAccount2Address,asset2Name.getBytes(),
+ 3L,assetAccount1Address,assetAccount1Key,blockingStubFull));
+
+
+ }
+
+ @AfterClass(enabled = true)
+ public void shutdown() throws InterruptedException {
+ if (channelFull != null) {
+ channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+ }
+
+ public boolean participateAssetIssue(byte[] to, byte[] assertName, long amount, byte[] from,
+ String priKey) {
+ ECKey temKey = null;
+ try {
+ BigInteger priK = new BigInteger(priKey, 16);
+ temKey = ECKey.fromPrivate(priK);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ final ECKey ecKey = temKey;
+
+ Contract.ParticipateAssetIssueContract.Builder builder = Contract.ParticipateAssetIssueContract
+ .newBuilder();
+ ByteString bsTo = ByteString.copyFrom(to);
+ ByteString bsName = ByteString.copyFrom(assertName);
+ ByteString bsOwner = ByteString.copyFrom(from);
+ builder.setToAddress(bsTo);
+ builder.setAssetName(bsName);
+ builder.setOwnerAddress(bsOwner);
+ builder.setAmount(amount);
+ Contract.ParticipateAssetIssueContract contract = builder.build();
+
+ Transaction transaction = blockingStubFull.participateAssetIssue(contract);
+ transaction = signTransaction(ecKey, transaction);
+ Return response = blockingStubFull.broadcastTransaction(transaction);
+ if (response.getResult() == false) {
+ logger.info(ByteArray.toStr(response.getMessage().toByteArray()));
+ return false;
+ } else {
+ logger.info(name);
+ return true;
+ }
+ }
+
+ public Boolean createAssetIssue(byte[] address, String name, Long totalSupply, Integer trxNum,
+ Integer icoNum, Long startTime, Long endTime,
+ Integer voteScore, String description, String url, Long fronzenAmount, Long frozenDay,
+ String priKey,Long order) {
+ ECKey temKey = null;
+ try {
+ BigInteger priK = new BigInteger(priKey, 16);
+ temKey = ECKey.fromPrivate(priK);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ ECKey ecKey = temKey;
+
+ try {
+ Contract.AssetIssueContract.Builder builder = Contract.AssetIssueContract.newBuilder();
+ builder.setOwnerAddress(ByteString.copyFrom(address));
+ builder.setName(ByteString.copyFrom(name.getBytes()));
+ builder.setTotalSupply(totalSupply);
+ builder.setTrxNum(trxNum);
+ builder.setNum(icoNum);
+ builder.setStartTime(startTime);
+ builder.setEndTime(endTime);
+ builder.setVoteScore(voteScore);
+ builder.setDescription(ByteString.copyFrom(description.getBytes()));
+ builder.setUrl(ByteString.copyFrom(url.getBytes()));
+ builder.setFreeAssetNetLimit(20000);
+ builder.setPublicFreeAssetNetLimit(20000);
+ Contract.AssetIssueContract.FrozenSupply.Builder frozenBuilder =
+ Contract.AssetIssueContract.FrozenSupply.newBuilder();
+ frozenBuilder.setFrozenAmount(fronzenAmount);
+ frozenBuilder.setFrozenDays(frozenDay);
+ builder.addFrozenSupply(0, frozenBuilder);
+
+ Transaction transaction = blockingStubFull.createAssetIssue(builder.build());
+ if (transaction == null || transaction.getRawData().getContractCount() == 0) {
+ return false;
+ }
+ transaction = signTransaction(ecKey, transaction);
+ Return response = blockingStubFull.broadcastTransaction(transaction);
+ if (response.getResult() == false) {
+ return false;
+ } else {
+ logger.info(name);
+ return true;
+ }
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ return false;
+ }
+ }
+
+ public Account queryAccount(String priKey, WalletGrpc.WalletBlockingStub blockingStubFull) {
+ byte[] address;
+ ECKey temKey = null;
+ try {
+ BigInteger priK = new BigInteger(priKey, 16);
+ temKey = ECKey.fromPrivate(priK);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ ECKey ecKey = temKey;
+ if (ecKey == null) {
+ String pubKey = loadPubKey(); //04 PubKey[128]
+ if (StringUtils.isEmpty(pubKey)) {
+ logger.warn("Warning: QueryAccount failed, no wallet address !!");
+ return null;
+ }
+ byte[] pubKeyAsc = pubKey.getBytes();
+ byte[] pubKeyHex = Hex.decode(pubKeyAsc);
+ ecKey = ECKey.fromPublicOnly(pubKeyHex);
+ }
+ return grpcQueryAccount(ecKey.getAddress(), blockingStubFull);
+ }
+
+ public static String loadPubKey() {
+ char[] buf = new char[0x100];
+ return String.valueOf(buf, 32, 130);
+ }
+
+ public byte[] getAddress(ECKey ecKey) {
+ return ecKey.getAddress();
+ }
+
+ public Account grpcQueryAccount(byte[] address, WalletGrpc.WalletBlockingStub blockingStubFull) {
+ ByteString addressBs = ByteString.copyFrom(address);
+ Account request = Account.newBuilder().setAddress(addressBs).build();
+ return blockingStubFull.getAccount(request);
+ }
+
+ public Block getBlock(long blockNum, WalletGrpc.WalletBlockingStub blockingStubFull) {
+ NumberMessage.Builder builder = NumberMessage.newBuilder();
+ builder.setNum(blockNum);
+ return blockingStubFull.getBlockByNum(builder.build());
+
+ }
+
+ private Transaction signTransaction(ECKey ecKey, Transaction transaction) {
+ if (ecKey == null || ecKey.getPrivKey() == null) {
+ logger.warn("Warning: Can't sign,there is no private key !!");
+ return null;
+ }
+ transaction = TransactionUtils.setTimestamp(transaction);
+ return TransactionUtils.sign(transaction, ecKey);
+ }
+
+ public boolean transferAsset(byte[] to, byte[] assertName, long amount, byte[] address,
+ String priKey) {
+ ECKey temKey = null;
+ try {
+ BigInteger priK = new BigInteger(priKey, 16);
+ temKey = ECKey.fromPrivate(priK);
+ } catch (Exception ex) {
+ ex.printStackTrace();
+ }
+ final ECKey ecKey = temKey;
+
+ Contract.TransferAssetContract.Builder builder = Contract.TransferAssetContract.newBuilder();
+ ByteString bsTo = ByteString.copyFrom(to);
+ ByteString bsName = ByteString.copyFrom(assertName);
+ ByteString bsOwner = ByteString.copyFrom(address);
+ builder.setToAddress(bsTo);
+ builder.setAssetName(bsName);
+ builder.setOwnerAddress(bsOwner);
+ builder.setAmount(amount);
+
+ Contract.TransferAssetContract contract = builder.build();
+ Transaction transaction = blockingStubFull.transferAsset(contract);
+ if (transaction == null || transaction.getRawData().getContractCount() == 0) {
+ logger.info("transaction == null || transaction.getRawData().getContractCount() == 0");
+ return false;
+ }
+ transaction = signTransaction(ecKey, transaction);
+ Return response = blockingStubFull.broadcastTransaction(transaction);
+ if (response.getResult() == false) {
+ logger.info(ByteArray.toStr(response.getMessage().toByteArray()));
+ return false;
+ } else {
+ //Account search = queryAccount(ecKey, blockingStubFull);
+ return true;
+ }
+
+ }
+}
+
+
diff --git a/src/test/java/stest/tron/wallet/block/WalletTestBlock002.java b/src/test/java/stest/tron/wallet/block/WalletTestBlock002.java
index 2b9ebae13ac..1302a2b2224 100644
--- a/src/test/java/stest/tron/wallet/block/WalletTestBlock002.java
+++ b/src/test/java/stest/tron/wallet/block/WalletTestBlock002.java
@@ -68,11 +68,11 @@ public void testGetBlockByNum() {
}
//The number is large than the currently number, there is no exception when query this number.
- Long outOfCurrentBlockNum = currentBlockNum + 10000L;
+ /* Long outOfCurrentBlockNum = currentBlockNum + 10000L;
NumberMessage.Builder builder1 = NumberMessage.newBuilder();
builder1.setNum(outOfCurrentBlockNum);
Block outOfCurrentBlock = blockingStubFull.getBlockByNum(builder1.build());
- Assert.assertFalse(outOfCurrentBlock.hasBlockHeader());
+ Assert.assertFalse(outOfCurrentBlock.hasBlockHeader());*/
//Query the first block.
NumberMessage.Builder builder2 = NumberMessage.newBuilder();
@@ -112,11 +112,11 @@ public void testGetBlockByNumFromSolidity() {
}
//The number is large than the currently number, there is no exception when query this number.
- Long outOfCurrentBlockNum = currentBlockNum + 10000L;
+ /* Long outOfCurrentBlockNum = currentBlockNum + 10000L;
NumberMessage.Builder builder1 = NumberMessage.newBuilder();
builder1.setNum(outOfCurrentBlockNum);
Block outOfCurrentBlock = blockingStubSolidity.getBlockByNum(builder1.build());
- Assert.assertFalse(outOfCurrentBlock.hasBlockHeader());
+ Assert.assertFalse(outOfCurrentBlock.hasBlockHeader());*/
//Query the first block.
NumberMessage.Builder builder2 = NumberMessage.newBuilder();
@@ -145,41 +145,6 @@ public void testGetBlockByNumFromSolidity() {
Assert.assertTrue(lastSecondBlock.getBlockHeader().getRawData().getWitnessId() >= 0);
logger.info("Last second test from solidity succesfully");
}
-
- @Test(enabled = true)
- public void testGetexceptionBlockByNum() {
- //The number is -1, there is no exception when query this number.
- NumberMessage.Builder builder1 = NumberMessage.newBuilder();
- builder1.setNum(-1);
- Block exceptionBlock = blockingStubFull.getBlockByNum(builder1.build());
- Assert.assertFalse(exceptionBlock.hasBlockHeader());
-
- //The number is 0, there is no exception when query this number.
- builder1 = NumberMessage.newBuilder();
- builder1.setNum(0);
- exceptionBlock = blockingStubFull.getBlockByNum(builder1.build());
- logger.info(Long.toString(exceptionBlock.getBlockHeader().getRawData().getNumber()));
- Assert.assertTrue(exceptionBlock.hasBlockHeader());
- //Assert.assertFalse(exceptionBlock.getBlockHeader().getRawData().
- // getWitnessAddress().isEmpty());
- Assert.assertFalse(exceptionBlock.getBlockHeader().getRawData().getTxTrieRoot().isEmpty());
-
- //On soliditynode, the number is 0, there is no exception when query this number.
- builder1 = NumberMessage.newBuilder();
- builder1.setNum(0);
- exceptionBlock = blockingStubSolidity.getBlockByNum(builder1.build());
- Assert.assertTrue(exceptionBlock.hasBlockHeader());
- Assert.assertFalse(exceptionBlock.getBlockHeader().getRawData().getTxTrieRoot().isEmpty());
-
- //On soliditynode, the number is -1, there is no exception when query this number.
- builder1 = NumberMessage.newBuilder();
- builder1.setNum(-1);
- exceptionBlock = blockingStubSolidity.getBlockByNum(builder1.build());
- Assert.assertFalse(exceptionBlock.hasBlockHeader());
-
-
- }
-
@Test(enabled = true)
public void testGetBlockById() {
diff --git a/src/test/java/stest/tron/wallet/committee/WalletTestCommittee001.java b/src/test/java/stest/tron/wallet/committee/WalletTestCommittee001.java
new file mode 100644
index 00000000000..be67910cf68
--- /dev/null
+++ b/src/test/java/stest/tron/wallet/committee/WalletTestCommittee001.java
@@ -0,0 +1,131 @@
+package stest.tron.wallet.committee;
+
+import com.google.protobuf.ByteString;
+import com.sun.media.jfxmedia.logging.Logger;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import java.math.BigInteger;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.spongycastle.util.encoders.Hex;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.Test;
+import org.tron.api.GrpcAPI.EmptyMessage;
+import org.tron.api.GrpcAPI.NumberMessage;
+import org.tron.api.GrpcAPI.ProposalList;
+import org.tron.api.WalletGrpc;
+import org.tron.api.WalletSolidityGrpc;
+import org.tron.common.crypto.ECKey;
+import org.tron.common.utils.ByteArray;
+import org.tron.core.Wallet;
+import org.tron.protos.Protocol.Account;
+import org.tron.protos.Protocol.Block;
+import stest.tron.wallet.common.client.Configuration;
+import stest.tron.wallet.common.client.Parameter.CommonConstant;
+import stest.tron.wallet.common.client.utils.PublicMethed;
+
+
+@Slf4j
+public class WalletTestCommittee001 {
+ //from account
+ private final String testKey002 =
+ "FC8BF0238748587B9617EB6D15D47A66C0E07C1A1959033CF249C6532DC29FE6";
+ //Witness 47.93.9.236
+ private final String witnessKey001 =
+ "369F095838EB6EED45D4F6312AF962D5B9DE52927DA9F04174EE49F9AF54BC77";
+ //Witness 47.93.33.201
+ private final String witnessKey002 =
+ "9FD8E129DE181EA44C6129F727A6871440169568ADE002943EAD0E7A16D8EDAC";
+ //Witness 123.56.10.6
+ private final String witnessKey003 =
+ "291C233A5A7660FB148BAE07FCBCF885224F2DF453239BD983F859E8E5AA4602";
+ //Wtiness 39.107.80.135
+ private final String witnessKey004 =
+ "99676348CBF9501D07819BD4618ED885210CB5A03FEAF6BFF28F0AF8E1DE7DBE";
+ //Witness 47.93.184.2
+ private final String witnessKey005 =
+ "FA090CFB9F3A6B00BE95FE185E82BBCFC4DA959CA6A795D275635ECF5D58466D";
+
+
+ private final byte[] fromAddress = PublicMethed.getFinalAddress(testKey002);
+ private final byte[] witness001Address = PublicMethed.getFinalAddress(witnessKey001);
+ private final byte[] witness002Address = PublicMethed.getFinalAddress(witnessKey002);
+ private final byte[] witness003Address = PublicMethed.getFinalAddress(witnessKey003);
+ private final byte[] witness004Address = PublicMethed.getFinalAddress(witnessKey004);
+ private final byte[] witness005Address = PublicMethed.getFinalAddress(witnessKey005);
+
+
+ private ManagedChannel channelFull = null;
+ private ManagedChannel channelSolidity = null;
+ private WalletGrpc.WalletBlockingStub blockingStubFull = null;
+ private WalletSolidityGrpc.WalletSolidityBlockingStub blockingStubSolidity = null;
+
+ private static final long now = System.currentTimeMillis();
+
+ private String fullnode = Configuration.getByPath("testng.conf").getStringList("fullnode.ip.list")
+ .get(0);
+ private String soliditynode = Configuration.getByPath("testng.conf")
+ .getStringList("solidityNode.ip.list").get(0);
+
+ @BeforeSuite
+ public void beforeSuite() {
+ Wallet wallet = new Wallet();
+ Wallet.setAddressPreFixByte(CommonConstant.ADD_PRE_FIX_BYTE_MAINNET);
+ }
+
+ @BeforeClass
+ public void beforeClass() {
+ channelFull = ManagedChannelBuilder.forTarget(fullnode)
+ .usePlaintext(true)
+ .build();
+ blockingStubFull = WalletGrpc.newBlockingStub(channelFull);
+
+ channelSolidity = ManagedChannelBuilder.forTarget(soliditynode)
+ .usePlaintext(true)
+ .build();
+ blockingStubSolidity = WalletSolidityGrpc.newBlockingStub(channelSolidity);
+ }
+
+
+ @Test
+ public void testListProposals() {
+ //List proposals
+ ProposalList proposalList = blockingStubFull.listProposals(EmptyMessage.newBuilder().build());
+ Optional listProposals = Optional.ofNullable(proposalList);
+ final Integer beforeProposalCount = listProposals.get().getProposalsCount();
+
+ //CreateProposal
+ final long now = System.currentTimeMillis();
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(0L, 1000000L);
+ PublicMethed.createProposal(witness001Address,witnessKey001,proposalMap,blockingStubFull);
+
+ //List proposals
+ proposalList = blockingStubFull.listProposals(EmptyMessage.newBuilder().build());
+ listProposals = Optional.ofNullable(proposalList);
+ Integer afterProposalCount = listProposals.get().getProposalsCount();
+ Assert.assertTrue(beforeProposalCount + 1 == afterProposalCount);
+ logger.info(Long.toString(listProposals.get().getProposals(0).getCreateTime()));
+ logger.info(Long.toString(now));
+ //Assert.assertTrue(listProposals.get().getProposals(0).getCreateTime() >= now);
+ Assert.assertTrue(listProposals.get().getProposals(0).getParametersMap().equals(proposalMap));
+ }
+
+ @AfterClass
+ public void shutdown() throws InterruptedException {
+ if (channelFull != null) {
+ channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+ if (channelSolidity != null) {
+ channelSolidity.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+ }
+}
+
+
diff --git a/src/test/java/stest/tron/wallet/committee/WalletTestCommittee002.java b/src/test/java/stest/tron/wallet/committee/WalletTestCommittee002.java
new file mode 100644
index 00000000000..7a37a32b9a4
--- /dev/null
+++ b/src/test/java/stest/tron/wallet/committee/WalletTestCommittee002.java
@@ -0,0 +1,367 @@
+package stest.tron.wallet.committee;
+
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.Test;
+import org.tron.api.GrpcAPI.EmptyMessage;
+import org.tron.api.GrpcAPI.ProposalList;
+import org.tron.api.WalletGrpc;
+import org.tron.api.WalletSolidityGrpc;
+import org.tron.core.Wallet;
+import stest.tron.wallet.common.client.Configuration;
+import stest.tron.wallet.common.client.Parameter.CommonConstant;
+import stest.tron.wallet.common.client.utils.PublicMethed;
+
+
+@Slf4j
+public class WalletTestCommittee002 {
+ //from account
+ private final String testKey003 =
+ "6815B367FDDE637E53E9ADC8E69424E07724333C9A2B973CFA469975E20753FC";
+ //Witness 47.93.9.236
+ private final String witnessKey001 =
+ "369F095838EB6EED45D4F6312AF962D5B9DE52927DA9F04174EE49F9AF54BC77";
+ //Witness 47.93.33.201
+ private final String witnessKey002 =
+ "9FD8E129DE181EA44C6129F727A6871440169568ADE002943EAD0E7A16D8EDAC";
+ //Witness 123.56.10.6
+ private final String witnessKey003 =
+ "291C233A5A7660FB148BAE07FCBCF885224F2DF453239BD983F859E8E5AA4602";
+ //Wtiness 39.107.80.135
+ private final String witnessKey004 =
+ "99676348CBF9501D07819BD4618ED885210CB5A03FEAF6BFF28F0AF8E1DE7DBE";
+ //Witness 47.93.184.2
+ private final String witnessKey005 =
+ "FA090CFB9F3A6B00BE95FE185E82BBCFC4DA959CA6A795D275635ECF5D58466D";
+
+
+ private final byte[] toAddress = PublicMethed.getFinalAddress(testKey003);
+ private final byte[] witness001Address = PublicMethed.getFinalAddress(witnessKey001);
+ private final byte[] witness002Address = PublicMethed.getFinalAddress(witnessKey002);
+ private final byte[] witness003Address = PublicMethed.getFinalAddress(witnessKey003);
+ private final byte[] witness004Address = PublicMethed.getFinalAddress(witnessKey004);
+ private final byte[] witness005Address = PublicMethed.getFinalAddress(witnessKey005);
+
+
+ private ManagedChannel channelFull = null;
+ private ManagedChannel channelSolidity = null;
+ private WalletGrpc.WalletBlockingStub blockingStubFull = null;
+ private WalletSolidityGrpc.WalletSolidityBlockingStub blockingStubSolidity = null;
+
+ private static final long now = System.currentTimeMillis();
+
+ private String fullnode = Configuration.getByPath("testng.conf").getStringList("fullnode.ip.list")
+ .get(0);
+ private String soliditynode = Configuration.getByPath("testng.conf")
+ .getStringList("solidityNode.ip.list").get(0);
+
+ @BeforeSuite
+ public void beforeSuite() {
+ Wallet wallet = new Wallet();
+ Wallet.setAddressPreFixByte(CommonConstant.ADD_PRE_FIX_BYTE_MAINNET);
+ }
+
+ @BeforeClass
+ public void beforeClass() {
+ channelFull = ManagedChannelBuilder.forTarget(fullnode)
+ .usePlaintext(true)
+ .build();
+ blockingStubFull = WalletGrpc.newBlockingStub(channelFull);
+
+ channelSolidity = ManagedChannelBuilder.forTarget(soliditynode)
+ .usePlaintext(true)
+ .build();
+ blockingStubSolidity = WalletSolidityGrpc.newBlockingStub(channelSolidity);
+ Assert.assertTrue(PublicMethed.sendcoin(witness001Address,10000000L,
+ toAddress,testKey003,blockingStubFull));
+ }
+
+
+ @Test(enabled = true)
+ public void testCreateProposalMaintenanceTimeInterval() {
+ //0:MAINTENANCE_TIME_INTERVAL,[3*27s,24h]
+ //Minimum interval
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(0L, 81000L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum interval
+ proposalMap.put(0L, 86400000L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Minimum -1 interval, create failed.
+ proposalMap.put(0L, 80000L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum + 1 interval
+ proposalMap.put(0L, 86401000L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Non witness account
+ proposalMap.put(0L, 86400000L);
+ Assert.assertFalse(PublicMethed.createProposal(toAddress,testKey003,proposalMap,
+ blockingStubFull));
+ }
+
+ @Test(enabled = true)
+ public void testCreateProposalAccountUpgradeCost() {
+ //1:ACCOUNT_UPGRADE_COST,[0,100 000 000 000 000 000]//drop
+ //Minimum AccountUpgradeCost
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(1L, 0L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum AccountUpgradeCost
+ proposalMap.put(1L, 100000000000000000L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Minimum - 1 AccountUpgradeCost
+ proposalMap.put(1L, -1L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum + 1 AccountUpgradeCost
+ proposalMap.put(1L, 100000000000000001L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Non witness account
+ proposalMap.put(1L, 86400000L);
+ Assert.assertFalse(PublicMethed.createProposal(toAddress,testKey003,
+ proposalMap,blockingStubFull));
+ }
+
+ @Test(enabled = true)
+ public void testCreateProposalCreateAccountFee() {
+ //2:CREATE_ACCOUNT_FEE,[0,100 000 000 000 000 000]//drop
+ //Minimum CreateAccountFee
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(2L, 0L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum CreateAccountFee
+ proposalMap.put(2L, 100000000000000000L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Minimum - 1 CreateAccountFee
+ proposalMap.put(2L, -1L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum + 1 CreateAccountFee
+ proposalMap.put(2L, 100000000000000001L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Non witness account
+ proposalMap.put(2L, 86400000L);
+ Assert.assertFalse(PublicMethed.createProposal(toAddress,testKey003,
+ proposalMap,blockingStubFull));
+
+ }
+
+ @Test(enabled = true)
+ public void testTransactionFee() {
+ //3:TRANSACTION_FEE,[0,100 000 000 000 000 000]//drop
+ //Minimum TransactionFee
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(3L, 0L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum TransactionFee
+ proposalMap.put(3L, 100000000000000000L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Minimum - 1 TransactionFee
+ proposalMap.put(3L, -1L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum + 1 TransactionFee
+ proposalMap.put(3L, 100000000000000001L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Non witness account
+ proposalMap.put(3L, 86400000L);
+ Assert.assertFalse(PublicMethed.createProposal(toAddress,testKey003,
+ proposalMap,blockingStubFull));
+
+ }
+
+ @Test(enabled = true)
+ public void testAssetIssueFee() {
+ //4:ASSET_ISSUE_FEE,[0,100 000 000 000 000 000]//drop
+ //Minimum AssetIssueFee
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(4L, 0L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Duplicat proposals
+ proposalMap.put(4L, 0L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum AssetIssueFee
+ proposalMap.put(4L, 100000000000000000L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Minimum - 1 AssetIssueFee
+ proposalMap.put(4L, -1L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum + 1 AssetIssueFee
+ proposalMap.put(4L, 100000000000000001L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Non witness account
+ proposalMap.put(4L, 86400000L);
+ Assert.assertFalse(PublicMethed.createProposal(toAddress,testKey003,
+ proposalMap,blockingStubFull));
+
+ }
+
+ @Test(enabled = true)
+ public void testWitnessPayPerBlock() {
+ //5:WITNESS_PAY_PER_BLOCK,[0,100 000 000 000 000 000]//drop
+ //Minimum WitnessPayPerBlock
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(5L, 0L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum WitnessPayPerBlock
+ proposalMap.put(5L, 100000000000000000L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Minimum - 1 WitnessPayPerBlock
+ proposalMap.put(5L, -1L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum + 1 WitnessPayPerBlock
+ proposalMap.put(5L, 100000000000000001L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Non witness account
+ proposalMap.put(5L, 86400000L);
+ Assert.assertFalse(PublicMethed.createProposal(toAddress,testKey003,
+ proposalMap,blockingStubFull));
+
+ }
+
+ @Test(enabled = true)
+ public void testWitnessStandbyAllowance() {
+ //6:WITNESS_STANDBY_ALLOWANCE,[0,100 000 000 000 000 000]//drop
+ //Minimum WitnessStandbyAllowance
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(6L, 0L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum WitnessStandbyAllowance
+ proposalMap.put(6L, 100000000000000000L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Minimum - 1 WitnessStandbyAllowance
+ proposalMap.put(6L, -1L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum + 1 WitnessStandbyAllowance
+ proposalMap.put(6L, 100000000000000001L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Non witness account
+ proposalMap.put(6L, 86400000L);
+ Assert.assertFalse(PublicMethed.createProposal(toAddress,testKey003,
+ proposalMap,blockingStubFull));
+
+ }
+
+ @Test(enabled = true)
+ public void testCreateNewAccountFeeInSystemControl() {
+ //7:CREATE_NEW_ACCOUNT_FEE_IN_SYSTEM_CONTRACT,0 or 1
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(7L, 1L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum WitnessStandbyAllowance
+ proposalMap.put(7L, 100000000000000000L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Minimum - 1 WitnessStandbyAllowance
+ proposalMap.put(6L, -1L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Maximum + 1 WitnessStandbyAllowance
+ proposalMap.put(6L, 100000000000000001L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //Non witness account
+ proposalMap.put(6L, 86400000L);
+ Assert.assertFalse(PublicMethed.createProposal(toAddress,testKey003,
+ proposalMap,blockingStubFull));
+
+ }
+
+
+
+ @Test(enabled = true)
+ public void testInvalidProposals() {
+ // The index isn't from 0-9
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(10L, 60L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+ //The index is -1
+ proposalMap.put(-1L, 6L);
+ Assert.assertFalse(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+
+
+ }
+
+ @AfterClass
+ public void shutdown() throws InterruptedException {
+ if (channelFull != null) {
+ channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+ if (channelSolidity != null) {
+ channelSolidity.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+ }
+}
+
+
diff --git a/src/test/java/stest/tron/wallet/committee/WalletTestCommittee003.java b/src/test/java/stest/tron/wallet/committee/WalletTestCommittee003.java
new file mode 100644
index 00000000000..6edef11cfac
--- /dev/null
+++ b/src/test/java/stest/tron/wallet/committee/WalletTestCommittee003.java
@@ -0,0 +1,166 @@
+package stest.tron.wallet.committee;
+
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.Test;
+import org.tron.api.GrpcAPI.EmptyMessage;
+import org.tron.api.GrpcAPI.ProposalList;
+import org.tron.api.WalletGrpc;
+import org.tron.api.WalletSolidityGrpc;
+import org.tron.common.utils.ByteArray;
+import org.tron.core.Wallet;
+import stest.tron.wallet.common.client.Configuration;
+import stest.tron.wallet.common.client.Parameter.CommonConstant;
+import stest.tron.wallet.common.client.utils.Base58;
+import stest.tron.wallet.common.client.utils.PublicMethed;
+
+
+@Slf4j
+public class WalletTestCommittee003 {
+ //from account
+ private final String testKey003 =
+ "6815B367FDDE637E53E9ADC8E69424E07724333C9A2B973CFA469975E20753FC";
+ //Witness 47.93.9.236
+ private final String witnessKey001 =
+ "369F095838EB6EED45D4F6312AF962D5B9DE52927DA9F04174EE49F9AF54BC77";
+ //Witness 47.93.33.201
+ private final String witnessKey002 =
+ "9FD8E129DE181EA44C6129F727A6871440169568ADE002943EAD0E7A16D8EDAC";
+ //Witness 123.56.10.6
+ private final String witnessKey003 =
+ "291C233A5A7660FB148BAE07FCBCF885224F2DF453239BD983F859E8E5AA4602";
+ //Wtiness 39.107.80.135
+ private final String witnessKey004 =
+ "99676348CBF9501D07819BD4618ED885210CB5A03FEAF6BFF28F0AF8E1DE7DBE";
+ //Witness 47.93.184.2
+ private final String witnessKey005 =
+ "FA090CFB9F3A6B00BE95FE185E82BBCFC4DA959CA6A795D275635ECF5D58466D";
+
+
+ private final byte[] toAddress = PublicMethed.getFinalAddress(testKey003);
+ private final byte[] witness001Address = PublicMethed.getFinalAddress(witnessKey001);
+ private final byte[] witness002Address = PublicMethed.getFinalAddress(witnessKey002);
+ private final byte[] witness003Address = PublicMethed.getFinalAddress(witnessKey003);
+ private final byte[] witness004Address = PublicMethed.getFinalAddress(witnessKey004);
+ private final byte[] witness005Address = PublicMethed.getFinalAddress(witnessKey005);
+
+
+ private ManagedChannel channelFull = null;
+ private ManagedChannel channelSolidity = null;
+ private WalletGrpc.WalletBlockingStub blockingStubFull = null;
+ private WalletSolidityGrpc.WalletSolidityBlockingStub blockingStubSolidity = null;
+
+ private static final long now = System.currentTimeMillis();
+
+ private String fullnode = Configuration.getByPath("testng.conf").getStringList("fullnode.ip.list")
+ .get(0);
+ private String soliditynode = Configuration.getByPath("testng.conf")
+ .getStringList("solidityNode.ip.list").get(0);
+
+ @BeforeSuite
+ public void beforeSuite() {
+ Wallet wallet = new Wallet();
+ Wallet.setAddressPreFixByte(CommonConstant.ADD_PRE_FIX_BYTE_MAINNET);
+ }
+
+ @BeforeClass
+ public void beforeClass() {
+ channelFull = ManagedChannelBuilder.forTarget(fullnode)
+ .usePlaintext(true)
+ .build();
+ blockingStubFull = WalletGrpc.newBlockingStub(channelFull);
+
+ channelSolidity = ManagedChannelBuilder.forTarget(soliditynode)
+ .usePlaintext(true)
+ .build();
+ blockingStubSolidity = WalletSolidityGrpc.newBlockingStub(channelSolidity);
+ Assert.assertTrue(PublicMethed.sendcoin(witness001Address,1000000L,
+ toAddress,testKey003,blockingStubFull));
+ Assert.assertTrue(PublicMethed.sendcoin(witness002Address,1000000L,
+ toAddress,testKey003,blockingStubFull));
+ }
+
+ @Test(enabled = true)
+ public void testApproveProposal() {
+ //Create a proposal
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(0L, 81000L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+ //Get proposal list
+ ProposalList proposalList = blockingStubFull.listProposals(EmptyMessage.newBuilder().build());
+ Optional listProposals = Optional.ofNullable(proposalList);
+ final Integer proposalId = listProposals.get().getProposalsCount();
+ logger.info(Integer.toString(proposalId));
+
+ Assert.assertTrue(PublicMethed.approveProposal(witness002Address,witnessKey002,proposalId,
+ true,blockingStubFull));
+ //Get proposal list after approve
+ proposalList = blockingStubFull.listProposals(EmptyMessage.newBuilder().build());
+ listProposals = Optional.ofNullable(proposalList);
+ //logger.info(Integer.toString(listProposals.get().getProposals(0).getApprovalsCount()));
+ Assert.assertTrue(listProposals.get().getProposals(0).getApprovalsCount() == 1);
+ //logger.info(Base58.encode58Check(witness002Address));
+ //logger.info(Base58.encode58Check(listProposals.get().getProposals(0).
+ // getApprovalsList().get(0).toByteArray()));
+ Assert.assertTrue(Base58.encode58Check(witness002Address).equals(Base58.encode58Check(
+ listProposals.get().getProposals(0).getApprovalsList().get(0).toByteArray())));
+
+ //Failed to approve proposal when you already approval this proposal
+ Assert.assertFalse(PublicMethed.approveProposal(witness002Address,witnessKey002,proposalId,
+ true,blockingStubFull));
+
+ //Success to change the option from true to false.
+ Assert.assertTrue(PublicMethed.approveProposal(witness002Address,witnessKey002,proposalId,
+ false,blockingStubFull));
+ proposalList = blockingStubFull.listProposals(EmptyMessage.newBuilder().build());
+ listProposals = Optional.ofNullable(proposalList);
+ Assert.assertTrue(listProposals.get().getProposals(0).getApprovalsCount() == 0);
+
+ //Failed to approvel proposal when you already approval this proposal
+ Assert.assertFalse(PublicMethed.approveProposal(witness002Address,witnessKey002,proposalId,
+ false,blockingStubFull));
+
+
+ //Non witness can't approval proposal
+ Assert.assertFalse(PublicMethed.approveProposal(toAddress,testKey003,proposalId,
+ true,blockingStubFull));
+
+ //Muti approval
+ Assert.assertTrue(PublicMethed.approveProposal(witness001Address,witnessKey001,proposalId,
+ true,blockingStubFull));
+ Assert.assertTrue(PublicMethed.approveProposal(witness002Address,witnessKey002,proposalId,
+ true,blockingStubFull));
+ Assert.assertTrue(PublicMethed.approveProposal(witness003Address,witnessKey003,proposalId,
+ true,blockingStubFull));
+ Assert.assertTrue(PublicMethed.approveProposal(witness004Address,witnessKey004,proposalId,
+ true,blockingStubFull));
+ Assert.assertTrue(PublicMethed.approveProposal(witness005Address,witnessKey005,proposalId,
+ true,blockingStubFull));
+ proposalList = blockingStubFull.listProposals(EmptyMessage.newBuilder().build());
+ listProposals = Optional.ofNullable(proposalList);
+ Assert.assertTrue(listProposals.get().getProposals(0).getApprovalsCount() == 5);
+
+
+ }
+
+ @AfterClass
+ public void shutdown() throws InterruptedException {
+ if (channelFull != null) {
+ channelFull.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+ if (channelSolidity != null) {
+ channelSolidity.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+ }
+ }
+}
+
+
diff --git a/src/test/java/stest/tron/wallet/committee/WalletTestCommittee004.java b/src/test/java/stest/tron/wallet/committee/WalletTestCommittee004.java
new file mode 100644
index 00000000000..92da6533543
--- /dev/null
+++ b/src/test/java/stest/tron/wallet/committee/WalletTestCommittee004.java
@@ -0,0 +1,214 @@
+package stest.tron.wallet.committee;
+
+import com.google.protobuf.ByteString;
+import io.grpc.ManagedChannel;
+import io.grpc.ManagedChannelBuilder;
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+import lombok.extern.slf4j.Slf4j;
+import org.testng.Assert;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.Test;
+import org.tron.api.GrpcAPI.BytesMessage;
+import org.tron.api.GrpcAPI.EmptyMessage;
+import org.tron.api.GrpcAPI.ProposalList;
+import org.tron.api.WalletGrpc;
+import org.tron.api.WalletSolidityGrpc;
+import org.tron.common.utils.ByteArray;
+import org.tron.core.Wallet;
+import org.tron.protos.Protocol.ChainParameters;
+import org.tron.protos.Protocol.Proposal;
+import stest.tron.wallet.common.client.Configuration;
+import stest.tron.wallet.common.client.Parameter.CommonConstant;
+import stest.tron.wallet.common.client.utils.Base58;
+import stest.tron.wallet.common.client.utils.PublicMethed;
+
+
+@Slf4j
+public class WalletTestCommittee004 {
+ //from account
+ private final String testKey003 =
+ "6815B367FDDE637E53E9ADC8E69424E07724333C9A2B973CFA469975E20753FC";
+ //Witness 47.93.9.236
+ private final String witnessKey001 =
+ "369F095838EB6EED45D4F6312AF962D5B9DE52927DA9F04174EE49F9AF54BC77";
+ //Witness 47.93.33.201
+ private final String witnessKey002 =
+ "9FD8E129DE181EA44C6129F727A6871440169568ADE002943EAD0E7A16D8EDAC";
+ //Witness 123.56.10.6
+ private final String witnessKey003 =
+ "291C233A5A7660FB148BAE07FCBCF885224F2DF453239BD983F859E8E5AA4602";
+ //Wtiness 39.107.80.135
+ private final String witnessKey004 =
+ "99676348CBF9501D07819BD4618ED885210CB5A03FEAF6BFF28F0AF8E1DE7DBE";
+ //Witness 47.93.184.2
+ private final String witnessKey005 =
+ "FA090CFB9F3A6B00BE95FE185E82BBCFC4DA959CA6A795D275635ECF5D58466D";
+
+
+ private final byte[] toAddress = PublicMethed.getFinalAddress(testKey003);
+ private final byte[] witness001Address = PublicMethed.getFinalAddress(witnessKey001);
+ private final byte[] witness002Address = PublicMethed.getFinalAddress(witnessKey002);
+ private final byte[] witness003Address = PublicMethed.getFinalAddress(witnessKey003);
+ private final byte[] witness004Address = PublicMethed.getFinalAddress(witnessKey004);
+ private final byte[] witness005Address = PublicMethed.getFinalAddress(witnessKey005);
+
+
+ private ManagedChannel channelFull = null;
+ private ManagedChannel channelSolidity = null;
+ private WalletGrpc.WalletBlockingStub blockingStubFull = null;
+ private WalletSolidityGrpc.WalletSolidityBlockingStub blockingStubSolidity = null;
+
+ private static final long now = System.currentTimeMillis();
+
+ private String fullnode = Configuration.getByPath("testng.conf").getStringList("fullnode.ip.list")
+ .get(0);
+ private String soliditynode = Configuration.getByPath("testng.conf")
+ .getStringList("solidityNode.ip.list").get(0);
+
+ @BeforeSuite
+ public void beforeSuite() {
+ Wallet wallet = new Wallet();
+ Wallet.setAddressPreFixByte(CommonConstant.ADD_PRE_FIX_BYTE_MAINNET);
+ }
+
+ @BeforeClass
+ public void beforeClass() {
+ channelFull = ManagedChannelBuilder.forTarget(fullnode)
+ .usePlaintext(true)
+ .build();
+ blockingStubFull = WalletGrpc.newBlockingStub(channelFull);
+
+ channelSolidity = ManagedChannelBuilder.forTarget(soliditynode)
+ .usePlaintext(true)
+ .build();
+ blockingStubSolidity = WalletSolidityGrpc.newBlockingStub(channelSolidity);
+ Assert.assertTrue(PublicMethed.sendcoin(witness001Address,1000000L,
+ toAddress,testKey003,blockingStubFull));
+ Assert.assertTrue(PublicMethed.sendcoin(witness002Address,1000000L,
+ toAddress,testKey003,blockingStubFull));
+ }
+
+ @Test(enabled = true)
+ public void testDeleteProposal() {
+ //Create a proposal and approval it
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(1L, 99999L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+ //Get proposal list
+ ProposalList proposalList = blockingStubFull.listProposals(EmptyMessage.newBuilder().build());
+ Optional listProposals = Optional.ofNullable(proposalList);
+ final Integer proposalId = listProposals.get().getProposalsCount();
+ Assert.assertTrue(PublicMethed.approveProposal(witness001Address,witnessKey001,
+ proposalId,true,blockingStubFull));
+ logger.info(Integer.toString(listProposals.get().getProposals(0).getStateValue()));
+ //The state is "pending", state value == 0
+ Assert.assertTrue(listProposals.get().getProposals(0).getStateValue() == 0);
+
+ //When the proposal isn't created by you, you can't delete it.
+ Assert.assertFalse(PublicMethed.deleteProposal(witness002Address,witnessKey002,
+ proposalId,blockingStubFull));
+ //Cancel the proposal
+ Assert.assertTrue(PublicMethed.deleteProposal(witness001Address,witnessKey001,
+ proposalId,blockingStubFull));
+ //When the state is cancel, you can't delete it again.
+ Assert.assertFalse(PublicMethed.deleteProposal(witness001Address,witnessKey001,
+ proposalId,blockingStubFull));
+ //You can't delete an invalid proposal
+ Assert.assertFalse(PublicMethed.deleteProposal(witness001Address,witnessKey001,
+ proposalId + 100,blockingStubFull));
+
+ proposalList = blockingStubFull.listProposals(EmptyMessage.newBuilder().build());
+ listProposals = Optional.ofNullable(proposalList);
+ logger.info(Integer.toString(listProposals.get().getProposals(0).getStateValue()));
+ //The state is "cancel", state value == 3
+ Assert.assertTrue(listProposals.get().getProposals(0).getStateValue() == 3);
+
+ //When the state is cancel, you can't approval proposal
+ Assert.assertFalse(PublicMethed.approveProposal(witness001Address,witnessKey001,
+ proposalId,true,blockingStubFull));
+ Assert.assertFalse(PublicMethed.approveProposal(witness001Address,witnessKey001,
+ proposalId,false,blockingStubFull));
+ }
+
+ @Test(enabled = true)
+ public void testGetProposal() {
+ //Create a proposal and approval it
+ HashMap proposalMap = new HashMap();
+ proposalMap.put(1L, 99999L);
+ Assert.assertTrue(PublicMethed.createProposal(witness001Address,witnessKey001,
+ proposalMap,blockingStubFull));
+ //Get proposal list
+ ProposalList proposalList = blockingStubFull.listProposals(EmptyMessage.newBuilder().build());
+ Optional listProposals = Optional.ofNullable(proposalList);
+ final Integer proposalId = listProposals.get().getProposalsCount();
+
+ BytesMessage request = BytesMessage.newBuilder().setValue(ByteString.copyFrom(
+ ByteArray.fromLong(Long.parseLong(proposalId.toString()))))
+ .build();
+ Proposal proposal = blockingStubFull.getProposalById(request);
+ Optional getProposal = Optional.ofNullable(proposal);
+
+ Assert.assertTrue(getProposal.isPresent());
+ Assert.assertTrue(getProposal.get().getStateValue() == 0);
+
+ //Invalid get proposal
+ final Integer wrongProposalId = proposalId + 99;
+ request = BytesMessage.newBuilder().setValue(ByteString.copyFrom(
+ ByteArray.fromLong(Long.parseLong(wrongProposalId.toString()))))
+ .build();
+ proposal = blockingStubFull.getProposalById(request);
+ getProposal = Optional.ofNullable(proposal);
+ logger.info(Long.toString(getProposal.get().getCreateTime()));
+ Assert.assertTrue(getProposal.get().getCreateTime() == 0);
+ }
+
+ @Test(enabled = true)
+ public void testGetChainParameters() {
+ //Set the default map
+ HashMap defaultCommitteeMap = new HashMap