diff --git a/chainbase/src/main/java/org/tron/core/db/RevokingDatabase.java b/chainbase/src/main/java/org/tron/core/db/RevokingDatabase.java index ff2f026192c..68671f3155c 100755 --- a/chainbase/src/main/java/org/tron/core/db/RevokingDatabase.java +++ b/chainbase/src/main/java/org/tron/core/db/RevokingDatabase.java @@ -15,6 +15,8 @@ public interface RevokingDatabase { void setCursor(Chainbase.Cursor cursor, long offset); + void setSpecifiedCursor(Long specifiedSnapshotVersion); + void add(IRevokingDB revokingDB); void merge() throws RevokingStoreIllegalStateException; @@ -23,6 +25,8 @@ public interface RevokingDatabase { void commit() throws RevokingStoreIllegalStateException; + boolean hasCommitted(); + void pop() throws RevokingStoreIllegalStateException; void fastPop() throws RevokingStoreIllegalStateException; diff --git a/chainbase/src/main/java/org/tron/core/db2/common/IRevokingDB.java b/chainbase/src/main/java/org/tron/core/db2/common/IRevokingDB.java index 8b0b023e8f4..ac00e14a32b 100644 --- a/chainbase/src/main/java/org/tron/core/db2/common/IRevokingDB.java +++ b/chainbase/src/main/java/org/tron/core/db2/common/IRevokingDB.java @@ -5,6 +5,7 @@ import java.util.Map; import java.util.Set; import org.tron.core.db2.core.Chainbase; +import org.tron.core.db2.core.Snapshot; import org.tron.core.exception.ItemNotFoundException; public interface IRevokingDB extends Iterable> { @@ -29,6 +30,12 @@ public interface IRevokingDB extends Iterable> { void setCursor(Chainbase.Cursor cursor, long offset); + void setSpecifiedSnapshotVersion(Long specifiedSnapshotVersion); + + void onSnapshotAdd(long snapshotVersion, Snapshot snapshot); + + Snapshot onSnapshotRemove(long snapshotVersion); + Chainbase.Cursor getCursor(); // for blockstore @@ -45,4 +52,8 @@ default Map getNext(byte[] key, long limit) { return Collections.emptyMap(); } + Snapshot findSnapshot(byte[] key, byte[] value); + + void printStats(); + } diff --git a/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java b/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java index ba6c77d43a2..b47f63b59fe 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/AbstractSnapshot.java @@ -17,9 +17,13 @@ public abstract class AbstractSnapshot implements Snapshot { protected boolean isOptimized; + @Getter + @Setter + protected long snapVersion; // snapshot version + @Override - public Snapshot advance() { - return new SnapshotImpl(this); + public Snapshot advance(long newSnapVersion) { + return new SnapshotImpl(this, newSnapVersion); } @Override diff --git a/chainbase/src/main/java/org/tron/core/db2/core/Chainbase.java b/chainbase/src/main/java/org/tron/core/db2/core/Chainbase.java index 17a047f78ae..aa3217cfc3f 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/Chainbase.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/Chainbase.java @@ -2,45 +2,43 @@ import com.google.common.collect.Maps; import com.google.common.collect.Streams; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; + +import java.util.*; import java.util.stream.Collectors; +import lombok.extern.slf4j.Slf4j; import org.tron.common.utils.ByteUtil; -import org.tron.common.utils.Pair; import org.tron.core.capsule.utils.MarketUtils; -import org.tron.core.db2.common.IRevokingDB; -import org.tron.core.db2.common.LevelDB; -import org.tron.core.db2.common.RocksDB; -import org.tron.core.db2.common.Value; +import org.tron.core.db2.common.*; import org.tron.core.db2.common.Value.Operator; -import org.tron.core.db2.common.WrappedByteArray; import org.tron.core.exception.ItemNotFoundException; + +@Slf4j public class Chainbase implements IRevokingDB { // public static Map assetsAddress = new HashMap<>(); // key = name , value = address public enum Cursor { HEAD, SOLIDITY, - PBFT + PBFT, + // add a specified block number cursor + SPECIFIED, } //true:fullnode, false:soliditynode private ThreadLocal cursor = new ThreadLocal<>(); private ThreadLocal offset = new ThreadLocal<>(); + private ThreadLocal specifiedSnapshotVersion = new ThreadLocal<>(); + private ThreadLocal specifiedSnapshot = new ThreadLocal<>(); private Snapshot head; + private Map snapshotSet = new HashMap<>(); public Chainbase(Snapshot head) { this.head = head; cursor.set(Cursor.HEAD); offset.set(0L); + onSnapshotAdd(head.getSnapVersion(), head); } public String getDbName() { @@ -58,6 +56,34 @@ public void setCursor(Cursor cursor, long offset) { this.offset.set(offset); } + @Override + public void setSpecifiedSnapshotVersion(Long specifiedSnapshotVersion) { + this.cursor.set(Cursor.SPECIFIED); + this.specifiedSnapshotVersion.set(specifiedSnapshotVersion); + if (specifiedSnapshotVersion == null) { + return; + } + Snapshot tmp = head; + + while (tmp != null && tmp != tmp.getRoot()) { + if (tmp.getSnapVersion() == specifiedSnapshotVersion) { + this.specifiedSnapshot.set(tmp); + return; + } + tmp = tmp.getPrevious(); + } + } + + @Override + public void onSnapshotAdd(long snapshotVersion, Snapshot snapshot) { + snapshotSet.put(snapshotVersion, snapshot); + } + + @Override + public Snapshot onSnapshotRemove(long snapshotVersion) { + return snapshotSet.remove(snapshotVersion); + } + @Override public Cursor getCursor() { if (cursor.get() == null) { @@ -91,6 +117,12 @@ private Snapshot head() { } else { return head.getSolidity(); } + case SPECIFIED: + Snapshot curSnapshot = specifiedSnapshot.get(); + if (curSnapshot != null) { + return curSnapshot; + } + return head; default: return head; } @@ -351,7 +383,7 @@ private Map getNext(Snapshot head, byte[] key, long limit) { public Map prefixQuery(byte[] key) { Map result = prefixQueryRoot(key); - Map snapshot = prefixQuerySnapshot(key); + Map snapshot = prefixQuerySnapshot(key); result.putAll(snapshot); result.entrySet().removeIf(e -> e.getValue() == null); return result; @@ -372,10 +404,42 @@ private Map prefixQuerySnapshot(byte[] key) { Snapshot snapshot = head(); if (!snapshot.equals(head.getRoot())) { Map all = new HashMap<>(); - ((SnapshotImpl) snapshot).collect(all, key); + ((SnapshotImpl) snapshot).collect(all, key, snapshot); all.forEach((k, v) -> result.put(k, v.getBytes())); } return result; } + + public Snapshot findSnapshot(byte[] key, byte[] value) { + Snapshot cur = head; + Value tmpValue; + while (Snapshot.isImpl(cur)) { + if ((tmpValue = ((SnapshotImpl) cur).db.get(Key.of(key))) != null + && Arrays.equals(tmpValue.getBytes(), value)) { + return cur; + } + cur = cur.getPrevious(); + } + return Snapshot.isImpl(cur) ? cur : null; + } + + @Override + public void printStats() { + logger.info("[chainbase]snapshotSet size: {}", snapshotSet.size()); + StringBuilder stringBuilder = new StringBuilder(); + Snapshot tmp = head; + stringBuilder.append("[chainbase]version list: ["); + while (tmp != null && tmp != tmp.getRoot()) { + stringBuilder.append(tmp.getSnapVersion()).append(" -> "); + tmp = tmp.getPrevious(); + } + if (tmp != null) { + stringBuilder.append(tmp.getSnapVersion()); + } + stringBuilder.append("]"); + logger.info("[chainbase]db name={}, {}", getDbName(), stringBuilder.toString()); + + } + } diff --git a/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java b/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java index 75545dc29b4..4a4b443293c 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/Snapshot.java @@ -12,6 +12,7 @@ static boolean isRoot(Snapshot snapshot) { static boolean isImpl(Snapshot snapshot) { return snapshot != null && snapshot.getClass() == SnapshotImpl.class; } + long getSnapVersion(); byte[] get(byte[] key); @@ -21,7 +22,7 @@ static boolean isImpl(Snapshot snapshot) { void merge(Snapshot from); - Snapshot advance(); + Snapshot advance(long newSnapVersion); Snapshot retreat(); @@ -50,4 +51,8 @@ static boolean isImpl(Snapshot snapshot) { boolean isOptimized(); void reloadToMem(); + + void setCommitted(); + + boolean isCommitted(); } diff --git a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java index bc31b406b30..96c4787e2a2 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotImpl.java @@ -5,12 +5,9 @@ import com.google.common.collect.Maps; import com.google.common.collect.Streams; import com.google.common.primitives.Bytes; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Map; -import java.util.Objects; -import java.util.Set; + +import java.util.*; + import lombok.Getter; import org.tron.core.db2.common.HashDB; import org.tron.core.db2.common.Key; @@ -23,7 +20,9 @@ public class SnapshotImpl extends AbstractSnapshot { @Getter protected Snapshot root; - SnapshotImpl(Snapshot snapshot) { + private boolean isCommitted; + + SnapshotImpl(Snapshot snapshot, long newSnapVersion) { root = snapshot.getRoot(); synchronized (this) { db = new HashDB(SnapshotImpl.class.getSimpleName() + ":" + root.getDbName()); @@ -34,6 +33,7 @@ public class SnapshotImpl extends AbstractSnapshot { if (isOptimized && root == previous) { Streams.stream(root.iterator()).forEach( e -> put(e.getKey(),e.getValue())); } + snapVersion = newSnapVersion; } @Override @@ -86,18 +86,19 @@ public void remove(byte[] key) { public void merge(Snapshot from) { SnapshotImpl fromImpl = (SnapshotImpl) from; Streams.stream(fromImpl.db).forEach(e -> db.put(e.getKey(), e.getValue())); + snapVersion = from.getSnapVersion(); } public void mergeAhead(Snapshot from) { if (from instanceof SnapshotRoot) { - return ; + return; } SnapshotImpl fromImpl = (SnapshotImpl) from; Streams.stream(fromImpl.db).forEach(e -> { - if (db.get(e.getKey()) == null) { - db.put(e.getKey(), e.getValue()); - } - } + if (db.get(e.getKey()) == null) { + db.put(e.getKey(), e.getValue()); + } + } ); } @@ -135,13 +136,16 @@ synchronized void collect(Map all) { } } - synchronized void collect(Map all, byte[] prefix) { + synchronized void collect(Map all, byte[] prefix, Snapshot head) { Snapshot next = getRoot().getNext(); while (next != null) { Streams.stream(((SnapshotImpl) next).db).filter(e -> Bytes.indexOf( Objects.requireNonNull(e.getKey().getBytes()), prefix) == 0) .forEach(e -> all.put(WrappedByteArray.of(e.getKey().getBytes()), WrappedByteArray.of(e.getValue().getBytes()))); + if (next == head) { + break; + } next = next.getNext(); } } @@ -153,7 +157,7 @@ synchronized void collect(Map all, byte[] pr * So, if we use list, we need to exclude duplicate keys. * More than that, there will be some item which has been deleted, but just assigned in Operator, * so we need Operator value to determine next step. - * */ + */ synchronized void collectUnique(Map all) { Snapshot next = getRoot().getNext(); while (next != null) { @@ -165,7 +169,6 @@ synchronized void collectUnique(Map all) { } - @Override public void close() { getRoot().close(); @@ -193,11 +196,21 @@ public String getDbName() { @Override public Snapshot newInstance() { - return new SnapshotImpl(this); + return new SnapshotImpl(this, this.getSnapVersion()); } @Override public void reloadToMem() { - mergeAhead(previous); + mergeAhead(previous); + } + + @Override + public void setCommitted() { + isCommitted = true; + } + + @Override + public boolean isCommitted() { + return isCommitted; } } diff --git a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java index eb27141a82c..b387ededfea 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotManager.java @@ -1,6 +1,7 @@ package org.tron.core.db2.core; import com.google.common.collect.Maps; +import com.google.common.collect.Streams; import com.google.common.primitives.Bytes; import com.google.common.primitives.Ints; import com.google.common.util.concurrent.Futures; @@ -35,11 +36,7 @@ import org.tron.core.db.RevokingDatabase; import org.tron.core.db.TronDatabase; import org.tron.core.db2.ISession; -import org.tron.core.db2.common.DB; -import org.tron.core.db2.common.IRevokingDB; -import org.tron.core.db2.common.Key; -import org.tron.core.db2.common.Value; -import org.tron.core.db2.common.WrappedByteArray; +import org.tron.core.db2.common.*; import org.tron.core.exception.RevokingStoreIllegalStateException; import org.tron.core.exception.TronError; import org.tron.core.store.CheckPointV2Store; @@ -73,6 +70,8 @@ public class SnapshotManager implements RevokingDatabase { private Map flushServices = new HashMap<>(); private ScheduledExecutorService pruneCheckpointThread = null; + + private ScheduledExecutorService monitorSnapshotThread = null; private final String pruneName = "checkpoint-prune"; @Autowired @@ -104,6 +103,11 @@ public void init() { } }, 10000, 3600, TimeUnit.MILLISECONDS); } + + monitorSnapshotThread = ExecutorServiceManager.newSingleThreadScheduledExecutor("monitor-snapshot"); + monitorSnapshotThread.scheduleWithFixedDelay(() -> { + dbs.forEach(Chainbase::printStats); + }, 1000, 3000, TimeUnit.MILLISECONDS); } public static String simpleDecode(byte[] bytes) { @@ -149,6 +153,11 @@ public void setCursor(Chainbase.Cursor cursor, long offset) { dbs.forEach(db -> db.setCursor(cursor, offset)); } + @Override + public void setSpecifiedCursor(Long specifiedSnapshotVersion) { + dbs.forEach(db -> db.setSpecifiedSnapshotVersion(specifiedSnapshotVersion)); + } + @Override public void add(IRevokingDB db) { Chainbase revokingDB = (Chainbase) db; @@ -159,12 +168,21 @@ public void add(IRevokingDB db) { } private void advance() { - dbs.forEach(db -> db.setHead(db.getHead().advance())); + final long newVersion = SnapshotVersion.getInstance().addOne(); + dbs.forEach(db -> { + Snapshot advanced = db.getHead().advance(newVersion); + db.setHead(advanced); + db.onSnapshotAdd(newVersion, advanced); + }); ++size; } private void retreat() { - dbs.forEach(db -> db.setHead(db.getHead().retreat())); + dbs.forEach(db -> { + Snapshot oldHead = db.getHead(); + db.setHead(oldHead.retreat()); + db.onSnapshotRemove(oldHead.getSnapVersion()); + }); --size; } @@ -217,6 +235,15 @@ public synchronized void commit() { db.getHead().reloadToMem(); } }); + setHasCommitted(); + } + + private void setHasCommitted() { + dbs.forEach(db -> db.getHead().setCommitted()); + } + + public boolean hasCommitted() { + return dbs.stream().allMatch(db -> db.getHead().isCommitted()); } public synchronized void pop() { @@ -315,7 +342,7 @@ private void refreshOne(Chainbase db) { snapshots.add(next); } - root.merge(snapshots); + merge(db, root, snapshots); root.resetSolidity(); if (db.getHead() == next) { @@ -326,6 +353,26 @@ private void refreshOne(Chainbase db) { } } + private void merge(Chainbase chainbase, SnapshotRoot root, List snapshots) { + Map batch = new HashMap<>(); + for (Snapshot snapshot : snapshots) { + SnapshotImpl from = (SnapshotImpl) snapshot; + Streams.stream(from.db) + .map(e -> Maps.immutableEntry(WrappedByteArray.of(e.getKey().getBytes()), + WrappedByteArray.of(e.getValue().getBytes()))) + .forEach(e -> batch.put(e.getKey(), e.getValue())); + chainbase.onSnapshotRemove(root.getSnapVersion()); + root.setSnapVersion(from.getSnapVersion()); + chainbase.onSnapshotAdd(root.getSnapVersion(), root); + } + if (root.needOptAsset()) { + root.processAccount(batch); + } else { + ((Flusher) root.db).flush(batch); + root.putCache(batch); + } + } + public void flush() { if (unChecked) { return; diff --git a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java index f95cf68dafe..4795f20b342 100644 --- a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java +++ b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotRoot.java @@ -39,9 +39,12 @@ public SnapshotRoot(DB db) { this.cache = CacheManager.allocate(CacheType.findByType(this.db.getDbName())); } isOptimized = "properties".equalsIgnoreCase(db.getDbName()); + + // Set the snapshot version + snapVersion = SnapshotVersion.getInstance().getCurrentVersion(); } - private boolean needOptAsset() { + protected boolean needOptAsset() { return isAccountDB && ChainBaseManager.getInstance().getDynamicPropertiesStore() .getAllowAccountAssetOptimizationFromRoot() == 1; } @@ -102,6 +105,7 @@ public void merge(Snapshot from) { ((Flusher) db).flush(batch); putCache(batch); } + snapVersion = from.getSnapVersion(); } public void merge(List snapshots) { @@ -121,7 +125,7 @@ public void merge(List snapshots) { } } - private void processAccount(Map batch) { + protected void processAccount(Map batch) { AccountAssetStore assetStore = ChainBaseManager.getInstance().getAccountAssetStore(); Map accounts = new HashMap<>(); Map assets = new HashMap<>(); @@ -157,7 +161,7 @@ private void putCache(byte[] key, byte[] value) { } } - private void putCache(Map values) { + protected void putCache(Map values) { if (cached()) { values.forEach(cache::put); } @@ -225,4 +229,14 @@ public Snapshot newInstance() { @Override public void reloadToMem() { } + + @Override + public void setCommitted() { + + } + + @Override + public boolean isCommitted() { + return true; + } } diff --git a/chainbase/src/main/java/org/tron/core/db2/core/SnapshotVersion.java b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotVersion.java new file mode 100644 index 00000000000..9b50f5ca9aa --- /dev/null +++ b/chainbase/src/main/java/org/tron/core/db2/core/SnapshotVersion.java @@ -0,0 +1,31 @@ +package org.tron.core.db2.core; + +import org.tron.common.utils.Time; + +import java.util.concurrent.atomic.AtomicLong; + +public class SnapshotVersion { + private final AtomicLong currentVersion; + + + public SnapshotVersion() { + long defaultVersion = Time.getCurrentMillis(); + this.currentVersion = new AtomicLong(defaultVersion); + } + + public long getCurrentVersion() { + return currentVersion.get(); + } + + public long addOne() { + return currentVersion.incrementAndGet(); + } + + private static class SingletonHolder { + private static final SnapshotVersion INSTANCE = new SnapshotVersion(); + } + + public static SnapshotVersion getInstance() { + return SingletonHolder.INSTANCE; + } +} diff --git a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java index 91b0cff68a0..8cd0ae8168e 100644 --- a/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java +++ b/chainbase/src/main/java/org/tron/core/store/DynamicPropertiesStore.java @@ -20,6 +20,7 @@ import org.tron.core.capsule.BytesCapsule; import org.tron.core.config.Parameter.ChainConstant; import org.tron.core.db.TronStoreWithRevoking; +import org.tron.core.db2.core.Snapshot; import org.tron.core.exception.BadItemException; import org.tron.core.exception.ItemNotFoundException; @@ -2147,6 +2148,14 @@ public long getLatestBlockHeaderNumber() { () -> new IllegalArgumentException("not found latest block header number")); } + public Long getSpecifiedNumberSnapshotVersion(long specifiedNumber) { + Snapshot snapshot = revokingDB.findSnapshot(LATEST_BLOCK_HEADER_NUMBER, new BytesCapsule(ByteArray.fromLong(specifiedNumber)).getData()); + if (snapshot == null) { + return null; + } + return snapshot.getSnapVersion(); + } + public long getLatestBlockHeaderNumberFromDB() { try { return Optional.ofNullable(getFromRoot(LATEST_BLOCK_HEADER_NUMBER)) diff --git a/contract_demo/.gitignore b/contract_demo/.gitignore new file mode 100644 index 00000000000..710eb82d616 --- /dev/null +++ b/contract_demo/.gitignore @@ -0,0 +1,6 @@ + +src/js/metacoin-config.js +node_modules +build +.env + diff --git a/contract_demo/contracts/Migrations.sol b/contract_demo/contracts/Migrations.sol new file mode 100644 index 00000000000..9aac9750f3b --- /dev/null +++ b/contract_demo/contracts/Migrations.sol @@ -0,0 +1,19 @@ +// SPDX-License-Identifier: MIT +pragma solidity >=0.4.22 <0.9.0; + +contract Migrations { + address public owner = msg.sender; + uint public last_completed_migration; + + modifier restricted() { + require( + msg.sender == owner, + "This function is restricted to the contract's owner" + ); + _; + } + + function setCompleted(uint completed) public restricted { + last_completed_migration = completed; + } +} diff --git a/contract_demo/contracts/Storage.sol b/contract_demo/contracts/Storage.sol new file mode 100644 index 00000000000..bf164629a8b --- /dev/null +++ b/contract_demo/contracts/Storage.sol @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-3.0 + +pragma solidity >=0.7.0 <0.9.0; + +/** + * @title Storage + * @dev Store & retrieve value in a variable + */ +contract Storage { + + uint256 number; + + /** + * @dev Store value in variable + * @param num value to store + */ + function store(uint256 num) public { + number = num; + } + + /** + * @dev Return value + * @return value of 'number' + */ + function retrieve() public view returns (uint256){ + return number; + } +} \ No newline at end of file diff --git a/contract_demo/migrations1/1_initial_migration.js b/contract_demo/migrations1/1_initial_migration.js new file mode 100644 index 00000000000..33149039357 --- /dev/null +++ b/contract_demo/migrations1/1_initial_migration.js @@ -0,0 +1,5 @@ +var Migrations = artifacts.require("./Migrations.sol"); + +module.exports = function(deployer) { + // deployer.deploy(Migrations); +}; diff --git a/contract_demo/migrations1/2_deploy_contracts.js b/contract_demo/migrations1/2_deploy_contracts.js new file mode 100644 index 00000000000..2935f2e7e2b --- /dev/null +++ b/contract_demo/migrations1/2_deploy_contracts.js @@ -0,0 +1,5 @@ +var MyContract = artifacts.require("./Storage.sol"); + +module.exports = function(deployer) { + // deployer.deploy(MyContract); +}; diff --git a/contract_demo/sample-env b/contract_demo/sample-env new file mode 100644 index 00000000000..e69de29bb2d diff --git a/contract_demo/test/helpers/wait.js b/contract_demo/test/helpers/wait.js new file mode 100644 index 00000000000..839ca05af16 --- /dev/null +++ b/contract_demo/test/helpers/wait.js @@ -0,0 +1,16 @@ +function sleep(millis) { + return new Promise(resolve => setTimeout(resolve, millis)); +} + +// const chalk = require('chalk'); + +function log(x) { + // process.stdout.write(chalk.yellow(x)); +} + +module.exports = async function (secs) { + secs = secs || 1; + console.log(`Sleeping for ${secs} second${secs === 1 ? '' : 's'}...`); + await sleep(1000 * (secs || 1)); + console.log(' Slept.\n'); +}; diff --git a/contract_demo/test/storage.js b/contract_demo/test/storage.js new file mode 100644 index 00000000000..214f4eab58d --- /dev/null +++ b/contract_demo/test/storage.js @@ -0,0 +1,37 @@ +const StorageContract = artifacts.require('./Storage.sol'); +const wait = require('./helpers/wait'); + +contract('Storage', function (accounts) { + it('xxx', async function () { + const st = await StorageContract.deployed(); + const a = 20250513; + const b = a + 1; + const c = b + 1; + // try { + + const curNumber = await st.retrieve.call() + console.log(`curNumber: ${curNumber.toString()}`) + const res = await st.store(a, { + from: accounts[0] + }) + + // console.log(`res is ${res}`); + // await wait(3); + // st.store(b, { + // from: accounts[0] + // }).then(() => { + // console.log(`store ${b} success`) + // }).catch((err) => { + // console.log(err) + // }); + // await wait(3); + // st.store(c, { + // from: accounts[0] + // }).then(() => { + // console.log(`store ${c} success`) + // }).catch((err) => { + // console.log(err) + // }); + // await wait(3); + }); +}); \ No newline at end of file diff --git a/contract_demo/tronbox-config.js b/contract_demo/tronbox-config.js new file mode 100644 index 00000000000..f4d625303f2 --- /dev/null +++ b/contract_demo/tronbox-config.js @@ -0,0 +1,3 @@ +module.exports = { + +}; diff --git a/contract_demo/tronbox-evm-config.js b/contract_demo/tronbox-evm-config.js new file mode 100644 index 00000000000..b0f2ad4d6cd --- /dev/null +++ b/contract_demo/tronbox-evm-config.js @@ -0,0 +1,44 @@ +module.exports = { + networks: { + bttc: { + // Don't put your private key here: + privateKey: process.env.PRIVATE_KEY_BTTC, + /* +Create a .env file (it must be gitignored) containing something like + + export PRIVATE_KEY_BTTC=4E7FEC...656243 + +Then, run the migration with: + + source .env && tronbox migrate --network bttc --evm + */ + fullHost: 'https://rpc.bt.io', + // gas: 8500000, // Gas sent with each transaction + // gasPrice: '500000000000000', // 500,000 gwei (in wei) + network_id: '1' + }, + donau: { + privateKey: process.env.PRIVATE_KEY_DONAU, + fullHost: 'https://pre-rpc.bt.io', + network_id: '2' + }, + development: { + privateKey: process.env.PRIVATE_KEY_DEV, + fullHost: 'http://127.0.0.1:8545', + network_id: '9' + } + }, + compilers: { + solc: { + version: '0.8.7', + settings: { + // optimizer: { + // enabled: true, + // runs: 200 + // }, + // evmVersion: 'istanbul', + // viaIR: true, + } + } + } +}; diff --git a/contract_demo/tronbox.js b/contract_demo/tronbox.js new file mode 100644 index 00000000000..92639f70521 --- /dev/null +++ b/contract_demo/tronbox.js @@ -0,0 +1,60 @@ +const port = process.env.HOST_PORT || 9090 + +module.exports = { + networks: { + mainnet: { + // Don't put your private key here: + privateKey: process.env.PRIVATE_KEY_MAINNET, + /* +Create a .env file (it must be gitignored) containing something like + + export PRIVATE_KEY_MAINNET=4E7FEC...656243 + +Then, run the migration with: + + source .env && tronbox migrate --network nile + + */ + userFeePercentage: 100, + feeLimit: 1000 * 1e6, + fullHost: 'https://api.trongrid.io', + network_id: '1' + }, + shasta: { + privateKey: process.env.PRIVATE_KEY_SHASTA, + userFeePercentage: 50, + feeLimit: 1000 * 1e6, + fullHost: 'https://api.shasta.trongrid.io', + network_id: '2' + }, + nile: { + privateKey: process.env.PRIVATE_KEY_NILE, + userFeePercentage: 100, + feeLimit: 1000 * 1e6, + fullHost: 'http://127.0.0.1:8099', + network_id: '3' + }, + development: { + // For tronbox/tre docker image + privateKey: '0000000000000000000000000000000000000000000000000000000000000001', + userFeePercentage: 0, + feeLimit: 1000 * 1e6, + fullHost: 'http://127.0.0.1:' + port, + network_id: '9' + }, + compilers: { + solc: { + version: '0.8.6' + } + } + }, + // solc compiler optimize + solc: { + // optimizer: { + // enabled: true, + // runs: 200 + // }, + // evmVersion: 'istanbul', + // viaIR: true, + } +} diff --git a/framework/src/main/java/org/tron/core/Wallet.java b/framework/src/main/java/org/tron/core/Wallet.java index 8dfb18331ff..58ae2ad5bef 100755 --- a/framework/src/main/java/org/tron/core/Wallet.java +++ b/framework/src/main/java/org/tron/core/Wallet.java @@ -557,7 +557,7 @@ public GrpcAPI.Return broadcastTransaction(Transaction signedTransaction) { } TransactionMessage message = new TransactionMessage(trx.getInstance().toByteArray()); trx.checkExpiration(chainBaseManager.getNextBlockSlotTime()); - dbManager.pushTransaction(trx); + dbManager.pushTransaction(trx, false); int num = tronNetService.fastBroadcastTransaction(message); if (num == 0 && minEffectiveConnection != 0) { return builder.setResult(false).setCode(response_code.NOT_ENOUGH_EFFECTIVE_CONNECTION) diff --git a/framework/src/main/java/org/tron/core/db/Manager.java b/framework/src/main/java/org/tron/core/db/Manager.java index 1eecc103874..0adb50bb207 100644 --- a/framework/src/main/java/org/tron/core/db/Manager.java +++ b/framework/src/main/java/org/tron/core/db/Manager.java @@ -752,7 +752,7 @@ private void initAutoStop() { if (exitHeight == headNum && (!Args.getInstance().isP2pDisable())) { logger.info("Auto-stop hit: shutDownBlockHeight: {}, currentHeaderNum: {}, exit now", exitHeight, headNum); - System.exit(0); + // System.exit(0); } if (exitCount > 0) { @@ -862,12 +862,15 @@ private boolean containsTransaction(byte[] transactionId) { /** * push transaction into pending. */ - public boolean pushTransaction(final TransactionCapsule trx) + public boolean pushTransaction(final TransactionCapsule trx, boolean... isBroadcasts) throws ValidateSignatureException, ContractValidateException, ContractExeException, AccountResourceInsufficientException, DupTransactionException, TaposException, TooBigTransactionException, TransactionExpirationException, ReceiptCheckErrException, VMIllegalException, TooBigTransactionResultException { - + boolean isBroadcast = false; + if (isBroadcasts.length > 0 && isBroadcasts[0]) { + isBroadcast = true; + } if (isShieldedTransaction(trx.getInstance()) && !Args.getInstance() .isFullNodeAllowShieldedTransactionArgs()) { return true; @@ -903,6 +906,10 @@ public boolean pushTransaction(final TransactionCapsule trx) } if (!session.valid()) { session.setValue(revokingStore.buildSession()); + if (isBroadcast) { + Thread.sleep(1000 * 10); + logger.info("[test create pending] Create session for transaction."); + } } try (ISession tmpSession = revokingStore.buildSession()) { @@ -911,13 +918,26 @@ public boolean pushTransaction(final TransactionCapsule trx) pendingTransactions.add(trx); Metrics.gaugeInc(MetricKeys.Gauge.MANAGER_QUEUE, 1, MetricLabels.Gauge.QUEUE_PENDING); + if (isBroadcast) { + logger.info("[test create pending] Push transaction to pending queue: {}", + trx.getTransactionId()); + Thread.sleep(1000 * 10); + } tmpSession.merge(); + if (isBroadcast) { + logger.info("[test create pending] Push transaction to pending queue success: {}", + trx.getTransactionId()); + } + } catch (InterruptedException e) { + throw new RuntimeException(e); } if (isShieldedTransaction(trx.getInstance())) { shieldedTransInPendingCounts.incrementAndGet(); } } } + } catch (InterruptedException e) { + throw new RuntimeException(e); } finally { if (pushTransactionQueue.remove(trx)) { Metrics.gaugeInc(MetricKeys.Gauge.MANAGER_QUEUE, -1, @@ -1058,6 +1078,14 @@ private void applyBlock(BlockCapsule block, List txs) ValidateScheduleException, ReceiptCheckErrException, VMIllegalException, TooBigTransactionResultException, ZksnarkException, BadBlockException, EventBloomException { processBlock(block, txs); + // if (block.getNum() == 56798818) { + // logger.info("Block 56798818 is a special block, sleep 10 minutes."); + // try { + // Thread.sleep(1000 * 60 * 10); + // } catch (InterruptedException e) { + // throw new RuntimeException(e); + // } + // } chainBaseManager.getBlockStore().put(block.getBlockId().getBytes(), block); chainBaseManager.getBlockIndexStore().put(block.getBlockId()); if (block.getTransactions().size() != 0) { @@ -1113,6 +1141,8 @@ private void switchFork(BlockCapsule newHead) throw e; } + int count = 0; + int binaryTreeSize = binaryTree.getValue().size(); if (CollectionUtils.isNotEmpty(binaryTree.getValue())) { while (!getDynamicPropertiesStore() .getLatestBlockHeaderHash() @@ -1122,8 +1152,20 @@ private void switchFork(BlockCapsule newHead) } reOrgLogsFilter(); eraseBlock(); + count += 1; + if (count + 1 == binaryTreeSize) { + logger.info( + "Erase {} blocks, binaryTreeSize = {}, blockId = {}", + count + 1, + binaryTreeSize, + binaryTree.getValue().peekLast().getBlk().getBlockId()); + + } } } + if (count > 0) { + logger.info("xxxx Erase {} blocks, binaryTreeSize = {}", count, binaryTreeSize); + } if (CollectionUtils.isNotEmpty(binaryTree.getKey())) { List first = new ArrayList<>(binaryTree.getKey()); diff --git a/framework/src/main/java/org/tron/core/net/TronNetDelegate.java b/framework/src/main/java/org/tron/core/net/TronNetDelegate.java index 100bad179bf..668413ad83a 100644 --- a/framework/src/main/java/org/tron/core/net/TronNetDelegate.java +++ b/framework/src/main/java/org/tron/core/net/TronNetDelegate.java @@ -114,7 +114,7 @@ public void init() { LockSupport.park(); // to Guarantee Some other thread invokes unpark with the current thread as the target if (hitDown && exit) { - System.exit(0); + // System.exit(0); } }); hitThread.setName("hit-thread"); @@ -235,9 +235,7 @@ public Message getData(Sha256Hash hash, InventoryType type) throws P2pException public void processBlock(BlockCapsule block, boolean isSync) throws P2pException { if (!hitDown && dbManager.getLatestSolidityNumShutDown() > 0 - && dbManager.getLatestSolidityNumShutDown() == dbManager.getDynamicPropertiesStore() - .getLatestBlockHeaderNumberFromDB()) { - + && dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber() == 56798818) { logger.info("Begin shutdown, currentBlockNum:{}, DbBlockNum:{}, solidifiedBlockNum:{}", dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumber(), dbManager.getDynamicPropertiesStore().getLatestBlockHeaderNumberFromDB(), diff --git a/framework/src/main/java/org/tron/core/services/WalletOnCursor.java b/framework/src/main/java/org/tron/core/services/WalletOnCursor.java index 62a8ac36a08..eebba8045a4 100755 --- a/framework/src/main/java/org/tron/core/services/WalletOnCursor.java +++ b/framework/src/main/java/org/tron/core/services/WalletOnCursor.java @@ -1,10 +1,14 @@ package org.tron.core.services; import java.util.concurrent.Callable; + import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; +import org.tron.core.ChainBaseManager; import org.tron.core.db.Manager; +import org.tron.core.db.RevokingDatabase; import org.tron.core.db2.core.Chainbase; +import org.tron.core.store.DynamicPropertiesStore; @Slf4j(topic = "API") public abstract class WalletOnCursor { @@ -13,6 +17,9 @@ public abstract class WalletOnCursor { @Autowired private Manager dbManager; + @Autowired + private RevokingDatabase revokingStore; + public T futureGet(TronCallable callable) { try { dbManager.setCursor(cursor); @@ -36,4 +43,34 @@ public interface TronCallable extends Callable { @Override T call(); } + + @FunctionalInterface + public interface ExceptionalRunnable { + void run(boolean statedMayChanged) throws Exception; + } + + public void futureGet(ExceptionalRunnable runnable, Long specifiedNumber) throws Exception { + DynamicPropertiesStore dynamicPropertiesStore = dbManager.getChainBaseManager().getDynamicPropertiesStore(); + logger.info("futureGet specifiedNumber = {}, latest header number = {}, latest solidity number = {}", specifiedNumber, dynamicPropertiesStore.getLatestBlockHeaderNumber(), dynamicPropertiesStore.getLatestSolidifiedBlockNum()); + if (specifiedNumber == null) { + // TODO implement me + runnable.run(false); + return; + } + + try { + ChainBaseManager chainBaseManager = dbManager.getChainBaseManager(); + Long snapshotVersion = chainBaseManager.getDynamicPropertiesStore().getSpecifiedNumberSnapshotVersion(specifiedNumber); + if (snapshotVersion == null) { + logger.warn("Snapshot version is null for specified number: {}, use head", specifiedNumber); + } + // can be null + revokingStore.setSpecifiedCursor(snapshotVersion); + + runnable.run(!revokingStore.hasCommitted()); + } finally { + dbManager.resetCursor(); + } + } + } diff --git a/framework/src/main/java/org/tron/core/services/http/GetAccountBalanceServlet.java b/framework/src/main/java/org/tron/core/services/http/GetAccountBalanceServlet.java index 159c3899666..ed4bf50f1af 100644 --- a/framework/src/main/java/org/tron/core/services/http/GetAccountBalanceServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/GetAccountBalanceServlet.java @@ -1,15 +1,14 @@ package org.tron.core.services.http; -import com.alibaba.fastjson.JSONObject; -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.core.Wallet; -import org.tron.protos.Protocol.Account; import org.tron.protos.contract.BalanceContract; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + @Component @Slf4j(topic = "API") @@ -18,13 +17,16 @@ public class GetAccountBalanceServlet extends RateLimiterServlet { @Autowired private Wallet wallet; + @Autowired + private WalletOnSpecified walletOnSpecified; + protected void doPost(HttpServletRequest request, HttpServletResponse response) { try { PostParams params = PostParams.getPostParams(request); BalanceContract.AccountBalanceRequest.Builder builder = BalanceContract.AccountBalanceRequest.newBuilder(); JsonFormat.merge(params.getParams(), builder, params.isVisible()); - fillResponse(params.isVisible(), builder.build(), response); + walletOnSpecified.futureGet(statedMayChanged -> fillResponse(params.isVisible(), builder.build(), response), params.getSpecifiedNumber()); } catch (Exception e) { Util.processError(e, response); } diff --git a/framework/src/main/java/org/tron/core/services/http/GetBlockByLimitNextServlet.java b/framework/src/main/java/org/tron/core/services/http/GetBlockByLimitNextServlet.java index 3e6700a1fae..653aeebb462 100644 --- a/framework/src/main/java/org/tron/core/services/http/GetBlockByLimitNextServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/GetBlockByLimitNextServlet.java @@ -19,10 +19,14 @@ public class GetBlockByLimitNextServlet extends RateLimiterServlet { @Autowired private Wallet wallet; + @Autowired + private WalletOnSpecified walletOnSpecified; + protected void doGet(HttpServletRequest request, HttpServletResponse response) { try { - fillResponse(Util.getVisible(request), Long.parseLong(request.getParameter("startNum")), - Long.parseLong(request.getParameter("endNum")), response); + Long specifiedNumber = Util.getSpecifiedNumber(request); + walletOnSpecified.futureGet(statedMayChanged -> fillResponse(Util.getVisible(request), Long.parseLong(request.getParameter("startNum")), + Long.parseLong(request.getParameter("endNum")), response), specifiedNumber); } catch (Exception e) { Util.processError(e, response); } @@ -33,7 +37,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) PostParams params = PostParams.getPostParams(request); BlockLimit.Builder build = BlockLimit.newBuilder(); JsonFormat.merge(params.getParams(), build, params.isVisible()); - fillResponse(params.isVisible(), build.getStartNum(), build.getEndNum(), response); + walletOnSpecified.futureGet(statedMayChanged -> fillResponse(params.isVisible(), build.getStartNum(), build.getEndNum(), response), params.getSpecifiedNumber()); } catch (Exception e) { Util.processError(e, response); } diff --git a/framework/src/main/java/org/tron/core/services/http/GetBlockServlet.java b/framework/src/main/java/org/tron/core/services/http/GetBlockServlet.java index 0e0104e8014..ed627a8e6b5 100644 --- a/framework/src/main/java/org/tron/core/services/http/GetBlockServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/GetBlockServlet.java @@ -50,7 +50,7 @@ private PostParams parseParams(HttpServletRequest request) throws Exception { } params.put("detail", Boolean.parseBoolean(request.getParameter("detail"))); return new PostParams(JSON.toJSONString(params), - Boolean.parseBoolean(request.getParameter(Util.VISIBLE))); + Boolean.parseBoolean(request.getParameter(Util.VISIBLE)), Long.parseLong(request.getParameter(Util.SPECIFIED_NUMBER))); } if (HttpMethod.POST.equals(m)) { return PostParams.getPostParams(request); diff --git a/framework/src/main/java/org/tron/core/services/http/GetDelegatedResourceAccountIndexV2Servlet.java b/framework/src/main/java/org/tron/core/services/http/GetDelegatedResourceAccountIndexV2Servlet.java index 3d5bff80941..609589a2e50 100644 --- a/framework/src/main/java/org/tron/core/services/http/GetDelegatedResourceAccountIndexV2Servlet.java +++ b/framework/src/main/java/org/tron/core/services/http/GetDelegatedResourceAccountIndexV2Servlet.java @@ -23,14 +23,21 @@ public class GetDelegatedResourceAccountIndexV2Servlet extends RateLimiterServle @Autowired private Wallet wallet; + @Autowired + private WalletOnSpecified walletOnSpecified; + protected void doGet(HttpServletRequest request, HttpServletResponse response) { try { boolean visible = Util.getVisible(request); String address = request.getParameter(VALUE_FIELD_NAME); + Long specifiedNumber = Util.getSpecifiedNumber(request); if (visible) { address = Util.getHexAddress(address); } - fillResponse(ByteString.copyFrom(ByteArray.fromHexString(address)), visible, response); + String finalAddress = address; + walletOnSpecified.futureGet(statedMayChanged -> { + fillResponse(ByteString.copyFrom(ByteArray.fromHexString(finalAddress)), visible, response); + }, specifiedNumber); } catch (Exception e) { Util.processError(e, response); } @@ -50,8 +57,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) BytesMessage.Builder build = BytesMessage.newBuilder(); JsonFormat.merge(input, build, visible); - - fillResponse(build.getValue(), visible, response); + walletOnSpecified.futureGet(statedMayChanged -> fillResponse(build.getValue(), visible, response), params.getSpecifiedNumber()); } catch (Exception e) { Util.processError(e, response); } diff --git a/framework/src/main/java/org/tron/core/services/http/GetTransactionByIdServlet.java b/framework/src/main/java/org/tron/core/services/http/GetTransactionByIdServlet.java index 49343da9070..82218c6e260 100644 --- a/framework/src/main/java/org/tron/core/services/http/GetTransactionByIdServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/GetTransactionByIdServlet.java @@ -21,11 +21,15 @@ public class GetTransactionByIdServlet extends RateLimiterServlet { @Autowired private Wallet wallet; + @Autowired + private WalletOnSpecified walletOnSpecified; + protected void doGet(HttpServletRequest request, HttpServletResponse response) { try { + Long specifiedNumber = Util.getSpecifiedNumber(request); boolean visible = Util.getVisible(request); String input = request.getParameter("value"); - fillResponse(ByteString.copyFrom(ByteArray.fromHexString(input)), visible, response); + walletOnSpecified.futureGet(statedMayChanged -> fillResponse(ByteString.copyFrom(ByteArray.fromHexString(input)), visible, response), specifiedNumber); } catch (Exception e) { Util.processError(e, response); } @@ -36,7 +40,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) PostParams params = PostParams.getPostParams(request); BytesMessage.Builder build = BytesMessage.newBuilder(); JsonFormat.merge(params.getParams(), build, params.isVisible()); - fillResponse(build.getValue(), params.isVisible(), response); + walletOnSpecified.futureGet(statedMayChanged -> fillResponse(build.getValue(), params.isVisible(), response), params.getSpecifiedNumber()); } catch (Exception e) { Util.processError(e, response); } diff --git a/framework/src/main/java/org/tron/core/services/http/JsonFormat.java b/framework/src/main/java/org/tron/core/services/http/JsonFormat.java index 96dedb1e20c..e8686221ee0 100644 --- a/framework/src/main/java/org/tron/core/services/http/JsonFormat.java +++ b/framework/src/main/java/org/tron/core/services/http/JsonFormat.java @@ -46,12 +46,7 @@ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT import java.nio.CharBuffer; import java.text.CharacterIterator; import java.text.StringCharacterIterator; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; +import java.util.*; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang3.StringUtils; @@ -95,11 +90,11 @@ public class JsonFormat { * (This representation is the new version of the classic "ProtocolPrinter" output from the * original Protocol Buffer system) */ - public static void print(Message message, Appendable output, boolean selfType) + public static void print(Message message, Appendable output, boolean selfType, boolean... statedMayChanged) throws IOException { JsonGenerator generator = new JsonGenerator(output); generator.print("{"); - print(message, generator, selfType); + print(message, generator, selfType, statedMayChanged); generator.print("}"); } @@ -114,7 +109,7 @@ public static void print(UnknownFieldSet fields, Appendable output, boolean self generator.print("}"); } - protected static void print(Message message, JsonGenerator generator, boolean selfType) + protected static void print(Message message, JsonGenerator generator, boolean selfType, boolean... statedMayChanged) throws IOException { Map fieldsToPrint = new TreeMap<>(message.getAllFields()); if (ALWAYS_OUTPUT_DEFAULT_VALUE_FIELDS && MESSAGES.contains(message.getClass())) { @@ -147,6 +142,10 @@ protected static void print(Message message, JsonGenerator generator, boolean se generator.print(","); } } + if (!fieldsToPrint.entrySet().isEmpty() && Objects.nonNull(statedMayChanged) && statedMayChanged.length > 0 && statedMayChanged[0]) { + generator.print(","); + generator.print("\"statedMayChanged\": true"); + } // do not print unknown fields // if (message.getUnknownFields().asMap().size() > 0) { @@ -158,10 +157,10 @@ protected static void print(Message message, JsonGenerator generator, boolean se /** * Like {@code print()}, but writes directly to a {@code String} and returns it. */ - public static String printToString(Message message, boolean selfType) { + public static String printToString(Message message, boolean selfType, boolean... statedMayChanged) { try { StringBuilder text = new StringBuilder(); - print(message, text, selfType); + print(message, text, selfType, statedMayChanged); return text.toString(); } catch (IOException e) { throw new RuntimeException(WRITING_STRING_BUILDER_EXCEPTION, e); @@ -385,7 +384,7 @@ private static void printFieldValue(FieldDescriptor field, Object value, case MESSAGE: case GROUP: generator.print("{"); - print((Message) value, generator, selfType); + print((Message) value, generator, selfType, false); generator.print("}"); break; default: diff --git a/framework/src/main/java/org/tron/core/services/http/PostParams.java b/framework/src/main/java/org/tron/core/services/http/PostParams.java index 7dcb0be6ae3..240ebbb5782 100644 --- a/framework/src/main/java/org/tron/core/services/http/PostParams.java +++ b/framework/src/main/java/org/tron/core/services/http/PostParams.java @@ -16,9 +16,13 @@ public class PostParams { @Getter private boolean visible; - public PostParams(String params, boolean visible) { + @Getter + private Long specifiedNumber; + + public PostParams(String params, boolean visible, Long specifiedNumber) { this.params = params; this.visible = visible; + this.specifiedNumber = specifiedNumber; } public static PostParams getPostParams(HttpServletRequest request) throws Exception { @@ -28,6 +32,6 @@ public static PostParams getPostParams(HttpServletRequest request) throws Except input = getJsonString(input); } boolean visible = Util.getVisiblePost(input); - return new PostParams(input, visible); + return new PostParams(input, visible, Util.getSpecifiedPost(input)); } } diff --git a/framework/src/main/java/org/tron/core/services/http/TriggerConstantContractServlet.java b/framework/src/main/java/org/tron/core/services/http/TriggerConstantContractServlet.java index 8a46ee1ed74..69b96ec0341 100644 --- a/framework/src/main/java/org/tron/core/services/http/TriggerConstantContractServlet.java +++ b/framework/src/main/java/org/tron/core/services/http/TriggerConstantContractServlet.java @@ -3,10 +3,12 @@ import com.alibaba.fastjson.JSONObject; import com.google.protobuf.ByteString; import io.netty.util.internal.StringUtil; + import java.io.IOException; import java.util.stream.Collectors; 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; @@ -29,6 +31,9 @@ public class TriggerConstantContractServlet extends RateLimiterServlet { @Autowired private Wallet wallet; + @Autowired + private WalletOnSpecified walletOnSpecified; + protected void doGet(HttpServletRequest request, HttpServletResponse response) { } @@ -37,14 +42,14 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) TriggerSmartContract.Builder build = TriggerSmartContract.newBuilder(); TransactionExtention.Builder trxExtBuilder = TransactionExtention.newBuilder(); Return.Builder retBuilder = Return.newBuilder(); - boolean visible = false; + final boolean[] visible = new boolean[1]; try { String contract = request.getReader().lines() .collect(Collectors.joining(System.lineSeparator())); Util.checkBodySize(contract); - visible = Util.getVisiblePost(contract); + visible[0] = Util.getVisiblePost(contract); Util.validateParameter(contract); - JsonFormat.merge(contract, build, visible); + JsonFormat.merge(contract, build, visible[0]); JSONObject jsonObject = JSONObject.parseObject(contract); boolean isFunctionSelectorSet = @@ -55,18 +60,20 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) String data = Util.parseMethod(selector, parameter); build.setData(ByteString.copyFrom(ByteArray.fromHexString(data))); } + Long specifiedNumber = jsonObject.getLong(Util.SPECIFIED_NUMBER); + walletOnSpecified.futureGet(statedMayChanged -> { + TransactionCapsule trxCap = wallet + .createTransactionCapsule(build.build(), ContractType.TriggerSmartContract); - TransactionCapsule trxCap = wallet - .createTransactionCapsule(build.build(), ContractType.TriggerSmartContract); - - Transaction trx = wallet - .triggerConstantContract(build.build(),trxCap, - trxExtBuilder, - retBuilder); - trx = Util.setTransactionPermissionId(jsonObject, trx); - trx = Util.setTransactionExtraData(jsonObject, trx, visible); - trxExtBuilder.setTransaction(trx); - retBuilder.setResult(true).setCode(response_code.SUCCESS); + Transaction trx = wallet + .triggerConstantContract(build.build(), trxCap, + trxExtBuilder, + retBuilder); + trx = Util.setTransactionPermissionId(jsonObject, trx); + trx = Util.setTransactionExtraData(jsonObject, trx, visible[0]); + trxExtBuilder.setTransaction(trx); + retBuilder.setResult(true).setCode(response_code.SUCCESS); + }, specifiedNumber); } catch (ContractValidateException e) { retBuilder.setResult(false).setCode(response_code.CONTRACT_VALIDATE_ERROR) .setMessage(ByteString.copyFromUtf8(e.getMessage())); @@ -79,6 +86,6 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) .setMessage(ByteString.copyFromUtf8(e.getClass() + " : " + errString)); } trxExtBuilder.setResult(retBuilder); - response.getWriter().println(Util.printTransactionExtention(trxExtBuilder.build(), visible)); + response.getWriter().println(Util.printTransactionExtention(trxExtBuilder.build(), visible[0])); } } diff --git a/framework/src/main/java/org/tron/core/services/http/Util.java b/framework/src/main/java/org/tron/core/services/http/Util.java index 2b6b929d8a0..e6036c6eb88 100644 --- a/framework/src/main/java/org/tron/core/services/http/Util.java +++ b/framework/src/main/java/org/tron/core/services/http/Util.java @@ -20,10 +20,7 @@ import java.math.BigDecimal; import java.nio.charset.Charset; import java.security.InvalidParameterException; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Objects; +import java.util.*; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import lombok.extern.slf4j.Slf4j; @@ -66,6 +63,7 @@ public class Util { public static final String PERMISSION_ID = "Permission_id"; public static final String VISIBLE = "visible"; + public static final String SPECIFIED_NUMBER = "specified_number"; public static final String TRANSACTION = "transaction"; public static final String TRANSACTION_EXTENSION = "transactionExtension"; public static final String VALUE = "value"; @@ -342,6 +340,15 @@ public static boolean getVisible(final HttpServletRequest request) { return visible; } + // getSpecifiedNumber + public static Long getSpecifiedNumber(final HttpServletRequest request) { + Long res = null; + if (StringUtil.isNotBlank(request.getParameter(SPECIFIED_NUMBER))) { + res = Long.parseLong(request.getParameter(SPECIFIED_NUMBER)); + } + return res; + } + public static boolean existVisible(final HttpServletRequest request) { return Objects.nonNull(request.getParameter(VISIBLE)); } @@ -358,6 +365,17 @@ public static boolean getVisiblePost(final String input) { return visible; } + public static Long getSpecifiedPost(final String input) { + Long res = null; + if (StringUtil.isNotBlank(input)) { + JSONObject jsonObject = JSON.parseObject(input); + if (jsonObject.containsKey(SPECIFIED_NUMBER)) { + res = Long.parseLong(jsonObject.getString(SPECIFIED_NUMBER)); + } + } + return res; + } + public static String getContractType(final String input) { String contractType = null; JSONObject jsonObject = JSON.parseObject(input); diff --git a/framework/src/main/java/org/tron/core/services/http/WalletOnSpecified.java b/framework/src/main/java/org/tron/core/services/http/WalletOnSpecified.java new file mode 100755 index 00000000000..398dd4d0b7b --- /dev/null +++ b/framework/src/main/java/org/tron/core/services/http/WalletOnSpecified.java @@ -0,0 +1,33 @@ +/* + * 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.core.services.http; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; +import org.tron.core.db2.core.Chainbase; +import org.tron.core.services.WalletOnCursor; + +@Slf4j(topic = "API") +@Component +public class WalletOnSpecified extends WalletOnCursor { + + public WalletOnSpecified() { + super.cursor = Chainbase.Cursor.SPECIFIED; + } +} diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java index 52a3a2380d1..65c0c471f64 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpc.java @@ -124,7 +124,7 @@ String estimateGas(CallArguments args) throws JsonRpcInvalidRequestException, @JsonRpcErrors({ @JsonRpcError(exception = JsonRpcInvalidParamsException.class, code = -32602, data = "{}"), }) - TransactionResult getTransactionByHash(String txId) throws JsonRpcInvalidParamsException; + TransactionResult getTransactionByHash(String txId, Long specifiedNumber) throws JsonRpcInvalidParamsException; @JsonRpcMethod("eth_getTransactionByBlockHashAndIndex") @JsonRpcErrors({ diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java index eb432432a1c..2993cf4bee4 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/TronJsonRpcImpl.java @@ -13,6 +13,7 @@ import com.alibaba.fastjson.JSON; import com.google.protobuf.ByteString; import com.google.protobuf.GeneratedMessageV3; + import java.io.Closeable; import java.io.IOException; import java.util.Arrays; @@ -26,6 +27,7 @@ import java.util.concurrent.ExecutorService; import java.util.regex.Matcher; import java.util.regex.Pattern; + import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.collections4.CollectionUtils; @@ -66,6 +68,7 @@ import org.tron.core.services.NodeInfoService; import org.tron.core.services.http.JsonFormat; import org.tron.core.services.http.Util; +import org.tron.core.services.http.WalletOnSpecified; import org.tron.core.services.jsonrpc.filters.BlockFilterAndResult; import org.tron.core.services.jsonrpc.filters.LogBlockQuery; import org.tron.core.services.jsonrpc.filters.LogFilter; @@ -159,6 +162,9 @@ public enum RequestSource { private final Manager manager; private final String esName = "query-section"; + @Autowired + WalletOnSpecified walletOnSpecified; + @Autowired public TronJsonRpcImpl(@Autowired NodeInfoService nodeInfoService, @Autowired Wallet wallet, @Autowired Manager manager) { @@ -381,8 +387,8 @@ public String getTrxBalance(String address, String blockNumOrTag) } private void callTriggerConstantContract(byte[] ownerAddressByte, byte[] contractAddressByte, - long value, byte[] data, TransactionExtention.Builder trxExtBuilder, - Return.Builder retBuilder) + long value, byte[] data, TransactionExtention.Builder trxExtBuilder, + Return.Builder retBuilder) throws ContractValidateException, ContractExeException, HeaderNotFound, VMIllegalException { TriggerSmartContract triggerContract = triggerCallContract( @@ -406,8 +412,8 @@ private void callTriggerConstantContract(byte[] ownerAddressByte, byte[] contrac } private void estimateEnergy(byte[] ownerAddressByte, byte[] contractAddressByte, - long value, byte[] data, TransactionExtention.Builder trxExtBuilder, - Return.Builder retBuilder, EstimateEnergyMessage.Builder estimateBuilder) + long value, byte[] data, TransactionExtention.Builder trxExtBuilder, + Return.Builder retBuilder, EstimateEnergyMessage.Builder estimateBuilder) throws ContractValidateException, ContractExeException, HeaderNotFound, VMIllegalException { TriggerSmartContract triggerContract = triggerCallContract( @@ -432,10 +438,10 @@ private void estimateEnergy(byte[] ownerAddressByte, byte[] contractAddressByte, /** * @param data Hash of the method signature and encoded parameters. for example: - * getMethodSign(methodName(uint256,uint256)) || data1 || data2 + * getMethodSign(methodName(uint256,uint256)) || data1 || data2 */ private String call(byte[] ownerAddressByte, byte[] contractAddressByte, long value, - byte[] data) throws JsonRpcInvalidRequestException, JsonRpcInternalException { + byte[] data) throws JsonRpcInvalidRequestException, JsonRpcInternalException { TransactionExtention.Builder trxExtBuilder = TransactionExtention.newBuilder(); Return.Builder retBuilder = Return.newBuilder(); @@ -657,41 +663,58 @@ public String estimateGas(CallArguments args) throws JsonRpcInvalidRequestExcept } @Override - public TransactionResult getTransactionByHash(String txId) throws JsonRpcInvalidParamsException { - ByteString transactionId = ByteString.copyFrom(hashToByteArray(txId)); - - TransactionInfo transactionInfo = wallet.getTransactionInfoById(transactionId); - if (transactionInfo == null) { - TransactionCapsule transactionCapsule = wallet.getTransactionCapsuleById(transactionId); - if (transactionCapsule == null) { - return null; - } - - BlockCapsule blockCapsule = wallet.getBlockCapsuleByNum(transactionCapsule.getBlockNum()); - if (blockCapsule == null) { - return new TransactionResult(transactionCapsule.getInstance(), wallet); - } else { - int transactionIndex = getTransactionIndex( - ByteArray.toHexString(transactionCapsule.getTransactionId().getBytes()), - blockCapsule.getInstance().getTransactionsList()); - - if (transactionIndex == -1) { - return null; + public TransactionResult getTransactionByHash(String txId, Long specifiedNumber) throws JsonRpcInvalidParamsException { + final TransactionResult[] result = {null}; + final boolean[] statedMayChangedArr = {false}; + try { + walletOnSpecified.futureGet(statedMayChanged -> { + statedMayChangedArr[0] = statedMayChanged; + ByteString transactionId = ByteString.copyFrom(hashToByteArray(txId)); + + TransactionInfo transactionInfo = wallet.getTransactionInfoById(transactionId); + if (transactionInfo == null) { + TransactionCapsule transactionCapsule = wallet.getTransactionCapsuleById(transactionId); + if (transactionCapsule == null) { + result[0] = null; + return; + } + + BlockCapsule blockCapsule = wallet.getBlockCapsuleByNum(transactionCapsule.getBlockNum()); + if (blockCapsule == null) { + result[0] = new TransactionResult(transactionCapsule.getInstance(), wallet); + return; + } else { + int transactionIndex = getTransactionIndex( + ByteArray.toHexString(transactionCapsule.getTransactionId().getBytes()), + blockCapsule.getInstance().getTransactionsList()); + + if (transactionIndex == -1) { + return; + } + + long energyUsageTotal = 0; + result[0] = new TransactionResult(blockCapsule, transactionIndex, + transactionCapsule.getInstance(), energyUsageTotal, + wallet.getEnergyFee(blockCapsule.getTimeStamp()), wallet); + return; + } + } else { + Block block = wallet.getBlockByNum(transactionInfo.getBlockNumber()); + if (block == null) { + return; + } + + result[0] = formatTransactionResult(transactionInfo, block); + return; } - - long energyUsageTotal = 0; - return new TransactionResult(blockCapsule, transactionIndex, - transactionCapsule.getInstance(), energyUsageTotal, - wallet.getEnergyFee(blockCapsule.getTimeStamp()), wallet); - } - } else { - Block block = wallet.getBlockByNum(transactionInfo.getBlockNumber()); - if (block == null) { - return null; - } - - return formatTransactionResult(transactionInfo, block); + }, specifiedNumber); + } catch (JsonRpcInvalidParamsException e) { + throw e; + } catch (Exception e) { + throw new RuntimeException(e); } + result[0].setStatedMayChanged(statedMayChangedArr[0]); + return result[0]; } private TransactionResult formatTransactionResult(TransactionInfo transactioninfo, Block block) { @@ -928,7 +951,7 @@ public String[] getAccounts() { } private TransactionJson buildCreateSmartContractTransaction(byte[] ownerAddress, - BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, + BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, JsonRpcInternalException { try { CreateSmartContract.Builder build = CreateSmartContract.newBuilder(); @@ -986,7 +1009,7 @@ private TransactionJson buildCreateSmartContractTransaction(byte[] ownerAddress, // from and to should not be null private TransactionJson buildTriggerSmartContractTransaction(byte[] ownerAddress, - BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, + BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, JsonRpcInternalException { byte[] contractAddress = addressCompatibleToByteArray(args.getTo()); @@ -1044,7 +1067,7 @@ private TransactionJson buildTriggerSmartContractTransaction(byte[] ownerAddress } private TransactionJson createTransactionJson(GeneratedMessageV3.Builder build, - ContractType contractTyp, BuildArguments args) + ContractType contractTyp, BuildArguments args) throws JsonRpcInvalidRequestException, JsonRpcInternalException { try { Transaction tx = wallet @@ -1066,7 +1089,7 @@ private TransactionJson createTransactionJson(GeneratedMessageV3.Builder buil } private TransactionJson buildTransferContractTransaction(byte[] ownerAddress, - BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, + BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, JsonRpcInternalException { long amount = args.parseValue(); @@ -1080,7 +1103,7 @@ private TransactionJson buildTransferContractTransaction(byte[] ownerAddress, // tokenId and tokenValue should not be null private TransactionJson buildTransferAssetContractTransaction(byte[] ownerAddress, - BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, + BuildArguments args) throws JsonRpcInvalidParamsException, JsonRpcInvalidRequestException, JsonRpcInternalException { byte[] tokenIdArr = ByteArray.fromString(String.valueOf(args.getTokenId())); if (tokenIdArr == null) { @@ -1357,7 +1380,7 @@ public LogFilterElement[] getFilterLogs(String filterId) throws ExecutionExcepti } private LogFilterElement[] getLogsByLogFilterWrapper(LogFilterWrapper logFilterWrapper, - long currentMaxBlockNum) throws JsonRpcTooManyResultException, ExecutionException, + long currentMaxBlockNum) throws JsonRpcTooManyResultException, ExecutionException, InterruptedException, BadItemException, ItemNotFoundException { //query possible block LogBlockQuery logBlockQuery = new LogBlockQuery(logFilterWrapper, manager.getChainBaseManager() diff --git a/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionResult.java b/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionResult.java index 389c58505cd..054615170ed 100644 --- a/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionResult.java +++ b/framework/src/main/java/org/tron/core/services/jsonrpc/types/TransactionResult.java @@ -7,6 +7,7 @@ import com.google.protobuf.ByteString; import java.util.Arrays; import lombok.Getter; +import lombok.Setter; import lombok.ToString; import org.tron.common.utils.ByteArray; import org.tron.core.Wallet; @@ -54,6 +55,9 @@ public class TransactionResult { private String r; @Getter private String s; + @Getter + @Setter + private boolean statedMayChanged; private void parseSignature(Transaction tx) { diff --git a/framework/src/main/resources/nile.conf b/framework/src/main/resources/nile.conf new file mode 100644 index 00000000000..ac4cb6dc08a --- /dev/null +++ b/framework/src/main/resources/nile.conf @@ -0,0 +1,588 @@ +net { + type = mainnet + # type = testnet +} + +storage { + # Directory for storing persistent data + db.version = 2, + db.engine = "LEVELDB", + db.sync = false, + db.directory = "database", + index.directory = "index", + transHistory.switch = "on", + # You can custom these 14 databases' configs: + + # account, account-index, asset-issue, block, block-index, + # block_KDB, peers, properties, recent-block, trans, + # utxo, votes, witness, witness_schedule. + + # Otherwise, db configs will remain defualt and data will be stored in + # the path of "output-directory" or which is set by "-d" ("--output-directory"). + + # Attention: name is a required field that must be set !!! + properties = [ + // { + // name = "account", + // path = "storage_directory_test", + // createIfMissing = true, + // paranoidChecks = true, + // verifyChecksums = true, + // compressionType = 1, // compressed with snappy + // blockSize = 4096, // 4 KB = 4 * 1024 B + // writeBufferSize = 10485760, // 10 MB = 10 * 1024 * 1024 B + // cacheSize = 10485760, // 10 MB = 10 * 1024 * 1024 B + // maxOpenFiles = 100 + // }, + // { + // name = "account-index", + // path = "storage_directory_test", + // createIfMissing = true, + // paranoidChecks = true, + // verifyChecksums = true, + // compressionType = 1, // compressed with snappy + // blockSize = 4096, // 4 KB = 4 * 1024 B + // writeBufferSize = 10485760, // 10 MB = 10 * 1024 * 1024 B + // cacheSize = 10485760, // 10 MB = 10 * 1024 * 1024 B + // maxOpenFiles = 100 + // }, + ] + + needToUpdateAsset = true + + //dbsettings is needed when using rocksdb as the storage implement (db.version=2 and db.engine="ROCKSDB"). + //we'd strongly recommend that do not modify it unless you know every item's meaning clearly. + dbSettings = { + levelNumber = 7 + //compactThreads = 32 + blocksize = 64 // n * KB + maxBytesForLevelBase = 256 // n * MB + maxBytesForLevelMultiplier = 10 + level0FileNumCompactionTrigger = 4 + targetFileSizeBase = 256 // n * MB + targetFileSizeMultiplier = 1 + } + + //backup settings when using rocks db as the storage implement (db.version=2 and db.engine="ROCKSDB"). + //if you want to use the backup plugin, please confirm set the db.version=2 and db.engine="ROCKSDB" above. + backup = { + enable = false // indicate whether enable the backup plugin + propPath = "prop.properties" // record which bak directory is valid + bak1path = "bak1/database" // you must set two backup directories to prevent application halt unexpected(e.g. kill -9). + bak2path = "bak2/database" + frequency = 10000 // indicate backup db once every 10000 blocks processed. + } + + # if true, transaction cache initialization will be faster. default false + # txCache.initOptimization = true + + # data root setting, for check data, currently, only reward-vi is used. + merkleRoot = { + reward-vi = b474b61f93824cd70106f8f5283fa740d61b83a7d57a3c12401d627f1fae0a77 + } +} + +node.discovery = { + enable = true + persist = true + bind.ip = "" + external.ip = null +} + +storage.balance.history.lookup = true + +node.shutdown = { + BlockHeight = 56798806 +} +#56798818 + +node.backup { + port = 10001 + + # my priority, each member should use different priority + priority = 8 + + # peer's ip list, can't contain mine + members = [ + # "ip", + # "ip" + ] +} + + + +node { + # trust node for solidity node + # trustNode = "ip:port" + trustNode = "127.0.0.1:50051" + + # expose extension api to public or not + walletExtensionApi = true + + listen.port = 18888 + + connection.timeout = 2 + + tcpNettyWorkThreadNum = 0 + + udpNettyWorkThreadNum = 1 + + # Number of validate sign thread, default availableProcessors / 2 + # validateSignThreadNum = 16 + + maxConnections = 30 + + minConnections = 8 + + minActiveConnections = 3 + + maxActiveNodesWithSameIp = 2 + + maxHttpConnectNumber = 50 + + minParticipationRate = 15 + + zenTokenId = 1000016 + + # check the peer data transfer ,disconnect factor + disconnectNumberFactor = 0.4 + maxConnectNumberFactor = 0.8 + receiveTcpMinDataLength = 2048 + isOpenFullTcpDisconnect = true + + p2p { + version = 201910292 + } + + active = [ + # Active establish connection in any case + # Sample entries: + # "ip:port", + # "ip:port" + ] + + passive = [ + # Passive accept connection in any case + # Sample entries: + # "ip:port", + # "ip:port" + ] + + # read node.active and node.passive periodically, default false + # checkInterval unit: second + dynamicConfig { + # enable = false + # checkInterval = 600 + } + + fastForward = [ + ] + + http { + fullNodePort = 8090 + solidityPort = 8091 + } + + jsonrpc { + httpFullNodeEnable = true + httpFullNodePort = 8190 + } + + # use your ipv6 address for node discovery and tcp connection, default false + # enableIpv6 = false + + # if your node's highest block num is below than all your pees', try to acquire new connection. default false + # effectiveCheckEnable = false + + # Enable node detect + # nodeDetectEnable = false + + dns { + # dns urls to get nodes, url format tree://{pubkey}@{domain}, default empty + treeUrls = [ + #"tree://APFGGTFOBVE2ZNAB3CSMNNX6RRK3ODIRLP2AA5U4YFAA6MSYZUYTQ@nodes1.example.org", + ] + } + + rpc { + port = 50051 + #solidityPort = 50061 + # Number of gRPC thread, default availableProcessors / 2 + # thread = 16 + + # The maximum number of concurrent calls permitted for each incoming connection + # maxConcurrentCallsPerConnection = + + # The HTTP/2 flow control window, default 1MB + # flowControlWindow = + + # Connection being idle for longer than which will be gracefully terminated + maxConnectionIdleInMillis = 60000 + + # Connection lasting longer than which will be gracefully terminated + # maxConnectionAgeInMillis = + + # The maximum message size allowed to be received on the server, default 4MB + # maxMessageSize = + + # The maximum size of header list allowed to be received, default 8192 + # maxHeaderListSize = + + # Transactions can only be broadcast if the number of effective connections is reached. + minEffectiveConnection = 0 + + # The switch of the reflection service, effective for all gRPC services + # reflectionService = true + } + + # number of solidity thread in the FullNode. + # If accessing solidity rpc and http interface timeout, could increase the number of threads, + # The default value is the number of cpu cores of the machine. + #solidity.threads = 8 + + # Limits the maximum percentage (default 75%) of producing block interval + # to provide sufficient time to perform other operations e.g. broadcast block + # blockProducedTimeOut = 75 + + # Limits the maximum number (default 700) of transaction from network layer + # netMaxTrxPerSecond = 700 + +} + +## rate limiter config +rate.limiter = { + # Use global settings to limit the QPS of the entire node or every ip address + # global.qps = 1000 + # global.ip.qps = 100 + + # Every api could be set a specific rate limit strategy. Three strategy are supported:GlobalPreemptibleAdapter、IPQPSRateLimiterAdapte、QpsRateLimiterAdapter + # GlobalPreemptibleAdapter: permit is the number of preemptible resource, every client must apply one resourse + # before do the request and release the resource after got the reponse automaticlly. permit should be a Integer. + # QpsRateLimiterAdapter: qps is the average request count in one second supported by the server, it could be a Double or a Integer. + # IPQPSRateLimiterAdapter: similar to the QpsRateLimiterAdapter, qps could be a Double or a Integer. + # If do not set, the "default strategy" is set.The "default startegy" is based on QpsRateLimiterAdapter, the qps is set as 10000. + # + # Sample entries: + # + http = [ + # { + # component = "GetNowBlockServlet", + # strategy = "GlobalPreemptibleAdapter", + # paramString = "permit=1" + # }, + + # { + # component = "GetAccountServlet", + # strategy = "IPQPSRateLimiterAdapter", + # paramString = "qps=1" + # }, + + # { + # component = "ListWitnessesServlet", + # strategy = "QpsRateLimiterAdapter", + # paramString = "qps=1" + # } + ], + + rpc = [ + # { + # component = "protocol.Wallet/GetBlockByLatestNum2", + # strategy = "GlobalPreemptibleAdapter", + # paramString = "permit=1" + # }, + + # { + # component = "protocol.Wallet/GetAccount", + # strategy = "IPQPSRateLimiterAdapter", + # paramString = "qps=1" + # }, + + # { + # component = "protocol.Wallet/ListWitnesses", + # strategy = "QpsRateLimiterAdapter", + # paramString = "qps=1" + # }, + ] +} + + +seed.node = { + # List of the seed nodes + # Seed nodes are stable full nodes + # example: + # ip.list = [ + # "ip:port", + # "ip:port" + # ] + ip.list = [ + "44.236.192.97:18888", + "44.236.125.107:18888", + "44.232.119.174:18888", + "52.39.105.180:18888", + "54.70.52.47:18888" + ] +} + +genesis.block = { + # Reserve balance + assets = [ + { + accountName = "Zion" + accountType = "AssetIssue" + address = "TMWXhuxiT1KczhBxCseCDDsrhmpYGUcoA9" + balance = "99000000000000000" + }, + { + accountName = "Sun" + accountType = "AssetIssue" + address = "TN21Wx2yoNYiZ7znuQonmZMJnH5Vdfxu78" + balance = "99000000000000000" + }, + { + accountName = "Blackhole" + accountType = "AssetIssue" + address = "TDPJULRzVtzVjnBmZvfaTcTNQ2tsVi6XxQ" + balance = "-9223372036854775808" + } + ] + + witnesses = [ + { + address: TD23EqH3ixYMYh8CMXKdHyQWjePi3KQvxV, + url = "http://GR1.com", + voteCount = 100000026 + }, + { + address: TCm4Lz1uP3tQm3jzpwFTG6o5UvSTA2XEHc, + url = "http://GR2.com", + voteCount = 100000025 + }, + { + address: TTgDUgREiPBeY3iudD5e2eEibE4v4CE8C9, + url = "http://GR3.com", + voteCount = 100000024 + }, + { + address: TFVDe7kMEmb8EuUxxp42kocQY1fFY727WS, + url = "http://GR4.com", + voteCount = 100000023 + }, + { + address: TY4NSjctzTchHkhaCskVc5zQtnX9s1uxAX, + url = "http://GR5.com", + voteCount = 100000022 + }, + { + address: TWSMPrm6aizvsJmPnjMB7x3UExJfRhyQhd, + url = "http://GR6.com", + voteCount = 100000021 + }, + { + address: TKwLkSaCvqqpAB44qaHGTohCTCFoYw7ecy, + url = "http://GR7.com", + voteCount = 100000020 + }, + { + address: TDsYmm1St9r4UZebDGWBcTMtfYTw9YX5h4, + url = "http://GR8.com", + voteCount = 100000019 + }, + { + address: TFEQbWAPxhbUr1P14y9UJBUZo3LgtdqTS7, + url = "http://GR9.com", + voteCount = 100000018 + }, + { + address: TCynAi8tb7UWP7uhLv6fe971KLm2KT8tcs, + url = "http://GR10.com", + voteCount = 100000017 + }, + { + address: TC2YsLp4rzrt3AbeN3EryoSywrBjEUVCq3, + url = "http://GR11.com", + voteCount = 100000016 + }, + { + address: THxMKH1uaL5FpURujkQR7u2sNZ2n5PSsiH, + url = "http://GR12.com", + voteCount = 100000015 + }, + { + address: TWbzgoHimDcXWy19ts1An8bxA4JKjcYHeG, + url = "http://GR13.com", + voteCount = 100000014 + }, + { + address: TW2LmXnVCEaxuVtQN8gZR1ixT5PNm4QLft, + url = "http://GR14.com", + voteCount = 100000013 + }, + { + address: TVuqk4rYYVHVA6j6sSEnaLexhhoQhN8nyZ, + url = "http://GR15.com", + voteCount = 100000012 + }, + { + address: TVMZu5ptZPhhkZ3Kaagkq35FmyuKNvUKJV, + url = "http://GR16.com", + voteCount = 100000011 + }, + { + address: TFDHT8PqUrL2Bd8DeysSiHHBAEMidZgkhx, + url = "http://GR17.com", + voteCount = 100000010 + }, + { + address: TVqz5Bj3M1uEenaSsw2NnXvTWChPj6K3hb, + url = "http://GR18.com", + voteCount = 100000009 + }, + { + address: TSt8YNpARJkhdMdEV4C7ajH1tFHpZWzF1T, + url = "http://GR19.com", + voteCount = 100000008 + }, + { + address: TTxWDjEb3Be1Ax8BCvK48cnaorZofLq2C9, + url = "http://GR20.com", + voteCount = 100000007 + }, + { + address: TU5T838YtyZtEQKpnXEdRz3d8hJn6WHhjw, + url = "http://GR21.com", + voteCount = 100000006 + }, + { + address: TRuSs1MpL3o2hzhU8r6HLC7WtDyVE9hsF6, + url = "http://GR22.com", + voteCount = 100000005 + }, + { + address: TYMCoCZyAjWkWdUfEHg1oZQYbLKev282ou, + url = "http://GR23.com", + voteCount = 100000004 + }, + { + address: TQvAyGATpLZymHbpeaRozJCKqSeRWVNhCJ, + url = "http://GR24.com", + voteCount = 100000003 + }, + { + address: TYDd9nskbhJmLLNoe4yV2Z1SYtGjNa8wyg, + url = "http://GR25.com", + voteCount = 100000002 + }, + { + address: TS5991Geh2qeHtw46rskpJyn6hFNbuZGGc, + url = "http://GR26.com", + voteCount = 100000001 + }, + { + address: TKnn5MBnmXXeKdu9dxKVfKk4n1YdCeSRGr, + url = "http://GR27.com", + voteCount = 100000000 + } + ] + + timestamp = "0" #2017-8-26 12:00:00 + + parentHash = "0xe58f33f9baf9305dc6f82b9f1934ea8f0ade2defb951258d50167028c780351f" +} + +// Optional.The default is empty. +// It is used when the witness account has set the witnessPermission. +// When it is not empty, the localWitnessAccountAddress represents the address of the witness account, +// and the localwitness is configured with the private key of the witnessPermissionAddress in the witness account. +// When it is empty,the localwitness is configured with the private key of the witness account. + +//localWitnessAccountAddress = + +#localwitnesskeystore = [ +# "localwitnesskeystore.json" +#] + +block = { + needSyncCheck = false + maintenanceTimeInterval = 600000 + proposalExpireTime = 600000 // +} + +# Transaction reference block, default is "head", configure to "solid" can avoid TaPos error +# trx.reference.block = "head" // head;solid; + +# This property sets the number of milliseconds after the creation of the transaction that is expired, default value is 60000. +# trx.expiration.timeInMilliseconds = 60000 + +vm = { + supportConstant =true + minTimeRatio = 0.0 + maxTimeRatio = 5.0 + saveInternalTx = true + + # In rare cases, transactions that will be within the specified maximum execution time (default 10(ms)) are re-executed and packaged + # longRunningTime = 10 +} + +committee = { + allowCreationOfContracts = 0 //mainnet:0 (reset by committee),test:1 + allowAdaptiveEnergy = 0 //mainnet:0 (reset by committee),test:1 +} + +event.subscribe = { + path = "/home/pang/Workspace/java-tron-outputs/nile/plugin-mongodb-1.0.0.zip" // absolute path of plugin + server = "localhost:27017" // target server address to receive event triggers + dbconfig = "eventlog|tron|123456" // dbname|username|password + contractParse = true, + topics = [ + { + triggerName = "block" // block trigger, the value can't be modified + enable = false + topic = "block" // plugin topic, the value could be modified + }, + { + triggerName = "transaction" + enable = false + topic = "transaction" + }, + { + triggerName = "contractevent" + enable = false + topic = "contractevent" + }, + { + triggerName = "contractlog" + enable = true + topic = "contractlog" + redundancy = true + }, + { + triggerName = "solidity" + enable = false + topic = "solidity" + }, + { + triggerName = "solidityevent" + enable = false + topic = "solidityevent" + }, + { + triggerName = "soliditylog" + enable = true + topic = "soliditylog" + redundancy = true + } + ] + + filter = { + fromblock = "" // the value could be "", "earliest" or a specified block number as the beginning of the queried range + toblock = "" // the value could be "", "latest" or a specified block number as end of the queried range + contractAddress = [ + "" // contract address you want to subscribe, if it's set to "", you will receive contract logs/events with any contract address. + ] + + contractTopic = [ + "" // contract topic you want to subscribe, if it's set to "", you will receive contract logs/events with any contract topic. + ] + } +} + diff --git a/framework/src/test/java/org/tron/core/jsonrpc/JsonrpcServiceTest.java b/framework/src/test/java/org/tron/core/jsonrpc/JsonrpcServiceTest.java index 0f2214c5c9c..64655d3c78b 100644 --- a/framework/src/test/java/org/tron/core/jsonrpc/JsonrpcServiceTest.java +++ b/framework/src/test/java/org/tron/core/jsonrpc/JsonrpcServiceTest.java @@ -322,7 +322,7 @@ public void testGetTransactionByHash() { TransactionResult transactionResult = null; try { transactionResult = tronJsonRpc.getTransactionByHash( - "0x1111111111111111111111111111111111111111111111111111111111111111"); + "0x1111111111111111111111111111111111111111111111111111111111111111", null); } catch (Exception e) { Assert.fail(); } @@ -330,7 +330,7 @@ public void testGetTransactionByHash() { try { transactionResult = tronJsonRpc.getTransactionByHash( - ByteArray.toJsonHex(transactionCapsule1.getTransactionId().getBytes())); + ByteArray.toJsonHex(transactionCapsule1.getTransactionId().getBytes()), null); } catch (Exception e) { Assert.fail(); } diff --git a/stop.sh b/stop.sh new file mode 100755 index 00000000000..466ab2f739d --- /dev/null +++ b/stop.sh @@ -0,0 +1,26 @@ +#!/bin/bash + +# Step 1: Get FullNode process ID +pid=$(jps | grep FullNode | awk '{print $1}') + +if [ -z "$pid" ]; then + echo "FullNode process not found." + exit 1 +fi + +echo "Found FullNode process with PID: $pid" + +# Step 2: Send SIGTERM +kill -15 "$pid" +echo "Sent SIGTERM (kill -15) to process $pid" + +# Step 3: Sleep for 3 second +sleep 3 +echo "Waiting for 3 seconds to allow process to terminate..." + +# Step 4: Check if process is terminated +if ps -p "$pid" > /dev/null; then + echo "Process $pid is still running." +else + echo "Process $pid has terminated successfully." +fi