From fbab702f3d95d0f7c1f3017c22c1ddc3d8220480 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 9 Jul 2019 18:21:48 +0200 Subject: [PATCH 01/56] Factorise metrics code for KeyValueStorage database - introduce `MonitorableKeyValueStorage` - factorise code - remove metrics instanciation in `RocksDbKeyValueStorage` and `ColumnarRocksDbKeyValueStorage` --- .../ColumnarRocksDbKeyValueStorage.java | 89 ++--------- .../kvstore/MonitorableKeyValueStorage.java | 150 ++++++++++++++++++ .../kvstore/RocksDbKeyValueStorage.java | 102 ++---------- 3 files changed, 176 insertions(+), 165 deletions(-) create mode 100644 services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/MonitorableKeyValueStorage.java diff --git a/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/ColumnarRocksDbKeyValueStorage.java b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/ColumnarRocksDbKeyValueStorage.java index e530548f56..5fbe0d101f 100644 --- a/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/ColumnarRocksDbKeyValueStorage.java +++ b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/ColumnarRocksDbKeyValueStorage.java @@ -12,12 +12,8 @@ */ package tech.pegasys.pantheon.services.kvstore; -import tech.pegasys.pantheon.metrics.Counter; import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.metrics.OperationTimer; -import tech.pegasys.pantheon.metrics.PantheonMetricCategory; -import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem; -import tech.pegasys.pantheon.metrics.rocksdb.RocksDBStats; import tech.pegasys.pantheon.services.util.RocksDbUtil; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -58,14 +54,8 @@ public class ColumnarRocksDbKeyValueStorage private final TransactionDBOptions txOptions; private final TransactionDB db; private final AtomicBoolean closed = new AtomicBoolean(false); - - private final OperationTimer readLatency; - private final OperationTimer removeLatency; - private final OperationTimer writeLatency; - private final OperationTimer commitLatency; - private final Counter rollbackCount; - private final Statistics stats; private final Map columnHandlesByName; + private final MonitorableKeyValueStorage monitorableKeyValueStorage; public static ColumnarRocksDbKeyValueStorage create( final RocksDbConfiguration rocksDbConfiguration, @@ -91,7 +81,7 @@ private ColumnarRocksDbKeyValueStorage( new ColumnFamilyOptions() .setTableFormatConfig(createBlockBasedTableConfig(rocksDbConfiguration)))); - stats = new Statistics(); + final Statistics stats = new Statistics(); options = new DBOptions() .setCreateIfMissing(true) @@ -112,7 +102,8 @@ private ColumnarRocksDbKeyValueStorage( rocksDbConfiguration.getDatabaseDir().toString(), columnDescriptors, columnHandles); - + monitorableKeyValueStorage = + MonitorableKeyValueStorage.of(metricsSystem, rocksDbConfiguration, db, stats); final Map segmentsById = segments.stream() .collect( @@ -129,64 +120,6 @@ private ColumnarRocksDbKeyValueStorage( } columnHandlesByName = builder.build(); - readLatency = - metricsSystem - .createLabelledTimer( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "read_latency_seconds", - "Latency for read from RocksDB.", - "database") - .labels(rocksDbConfiguration.getLabel()); - removeLatency = - metricsSystem - .createLabelledTimer( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "remove_latency_seconds", - "Latency of remove requests from RocksDB.", - "database") - .labels(rocksDbConfiguration.getLabel()); - writeLatency = - metricsSystem - .createLabelledTimer( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "write_latency_seconds", - "Latency for write to RocksDB.", - "database") - .labels(rocksDbConfiguration.getLabel()); - commitLatency = - metricsSystem - .createLabelledTimer( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "commit_latency_seconds", - "Latency for commits to RocksDB.", - "database") - .labels(rocksDbConfiguration.getLabel()); - - if (metricsSystem instanceof PrometheusMetricsSystem) { - RocksDBStats.registerRocksDBMetrics(stats, (PrometheusMetricsSystem) metricsSystem); - } - - metricsSystem.createLongGauge( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "rocks_db_table_readers_memory_bytes", - "Estimated memory used for RocksDB index and filter blocks in bytes", - () -> { - try { - return db.getLongProperty("rocksdb.estimate-table-readers-mem"); - } catch (final RocksDBException e) { - LOG.debug("Failed to get RocksDB metric", e); - return 0L; - } - }); - - rollbackCount = - metricsSystem - .createLabelledCounter( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "rollback_count", - "Number of RocksDB transactions rolled back.", - "database") - .labels(rocksDbConfiguration.getLabel()); } catch (final RocksDBException e) { throw new StorageException(e); } @@ -207,7 +140,8 @@ public Optional get(final ColumnFamilyHandle segment, final BytesVal throws StorageException { throwIfClosed(); - try (final OperationTimer.TimingContext ignored = readLatency.startTimer()) { + try (final OperationTimer.TimingContext ignored = + monitorableKeyValueStorage.getReadLatency().startTimer()) { return Optional.ofNullable(db.get(segment, key.getArrayUnsafe())).map(BytesValue::wrap); } catch (final RocksDBException e) { throw new StorageException(e); @@ -286,7 +220,8 @@ private class RocksDbTransaction extends AbstractTransaction @Override protected void doPut( final ColumnFamilyHandle segment, final BytesValue key, final BytesValue value) { - try (final OperationTimer.TimingContext ignored = writeLatency.startTimer()) { + try (final OperationTimer.TimingContext ignored = + monitorableKeyValueStorage.getWriteLatency().startTimer()) { innerTx.put(segment, key.getArrayUnsafe(), value.getArrayUnsafe()); } catch (final RocksDBException e) { throw new StorageException(e); @@ -295,7 +230,8 @@ protected void doPut( @Override protected void doRemove(final ColumnFamilyHandle segment, final BytesValue key) { - try (final OperationTimer.TimingContext ignored = removeLatency.startTimer()) { + try (final OperationTimer.TimingContext ignored = + monitorableKeyValueStorage.getRemoveLatency().startTimer()) { innerTx.delete(segment, key.getArrayUnsafe()); } catch (final RocksDBException e) { throw new StorageException(e); @@ -304,7 +240,8 @@ protected void doRemove(final ColumnFamilyHandle segment, final BytesValue key) @Override protected void doCommit() throws StorageException { - try (final OperationTimer.TimingContext ignored = commitLatency.startTimer()) { + try (final OperationTimer.TimingContext ignored = + monitorableKeyValueStorage.getCommitLatency().startTimer()) { innerTx.commit(); } catch (final RocksDBException e) { throw new StorageException(e); @@ -317,7 +254,7 @@ protected void doCommit() throws StorageException { protected void doRollback() { try { innerTx.rollback(); - rollbackCount.inc(); + monitorableKeyValueStorage.getRollbackCount().inc(); } catch (final RocksDBException e) { throw new StorageException(e); } finally { diff --git a/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/MonitorableKeyValueStorage.java b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/MonitorableKeyValueStorage.java new file mode 100644 index 0000000000..8d9d3d9159 --- /dev/null +++ b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/MonitorableKeyValueStorage.java @@ -0,0 +1,150 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.services.kvstore; + +import tech.pegasys.pantheon.metrics.Counter; +import tech.pegasys.pantheon.metrics.MetricsSystem; +import tech.pegasys.pantheon.metrics.OperationTimer; +import tech.pegasys.pantheon.metrics.PantheonMetricCategory; +import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem; +import tech.pegasys.pantheon.metrics.rocksdb.RocksDBStats; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.rocksdb.RocksDBException; +import org.rocksdb.Statistics; +import org.rocksdb.TransactionDB; + +public class MonitorableKeyValueStorage { + private static final Logger LOG = LogManager.getLogger(); + + private final OperationTimer readLatency; + private final OperationTimer removeLatency; + private final OperationTimer writeLatency; + private final OperationTimer commitLatency; + private final Counter rollbackCount; + + private MonitorableKeyValueStorage( + final OperationTimer readLatency, + final OperationTimer removeLatency, + final OperationTimer writeLatency, + final OperationTimer commitLatency, + final Counter rollbackCount) { + this.readLatency = readLatency; + this.removeLatency = removeLatency; + this.writeLatency = writeLatency; + this.commitLatency = commitLatency; + this.rollbackCount = rollbackCount; + } + + public static MonitorableKeyValueStorage of( + final MetricsSystem metricsSystem, + final RocksDbConfiguration rocksDbConfiguration, + final TransactionDB db, + final Statistics stats) { + final OperationTimer readLatency = + metricsSystem + .createLabelledTimer( + PantheonMetricCategory.KVSTORE_ROCKSDB, + "read_latency_seconds", + "Latency for read from RocksDB.", + "database") + .labels(rocksDbConfiguration.getLabel()); + final OperationTimer removeLatency = + metricsSystem + .createLabelledTimer( + PantheonMetricCategory.KVSTORE_ROCKSDB, + "remove_latency_seconds", + "Latency of remove requests from RocksDB.", + "database") + .labels(rocksDbConfiguration.getLabel()); + final OperationTimer writeLatency = + metricsSystem + .createLabelledTimer( + PantheonMetricCategory.KVSTORE_ROCKSDB, + "write_latency_seconds", + "Latency for write to RocksDB.", + "database") + .labels(rocksDbConfiguration.getLabel()); + final OperationTimer commitLatency = + metricsSystem + .createLabelledTimer( + PantheonMetricCategory.KVSTORE_ROCKSDB, + "commit_latency_seconds", + "Latency for commits to RocksDB.", + "database") + .labels(rocksDbConfiguration.getLabel()); + + if (metricsSystem instanceof PrometheusMetricsSystem) { + RocksDBStats.registerRocksDBMetrics(stats, (PrometheusMetricsSystem) metricsSystem); + } + + metricsSystem.createLongGauge( + PantheonMetricCategory.KVSTORE_ROCKSDB, + "rocks_db_table_readers_memory_bytes", + "Estimated memory used for RocksDB index and filter blocks in bytes", + () -> { + try { + return db.getLongProperty("rocksdb.estimate-table-readers-mem"); + } catch (final RocksDBException e) { + LOG.debug("Failed to get RocksDB metric", e); + return 0L; + } + }); + + metricsSystem.createLongGauge( + PantheonMetricCategory.KVSTORE_ROCKSDB, + "rocks_db_files_size_bytes", + "Estimated database size in bytes", + () -> { + try { + return db.getLongProperty("rocksdb.live-sst-files-size"); + } catch (final RocksDBException e) { + LOG.debug("Failed to get RocksDB metric", e); + return 0L; + } + }); + + final Counter rollbackCount = + metricsSystem + .createLabelledCounter( + PantheonMetricCategory.KVSTORE_ROCKSDB, + "rollback_count", + "Number of RocksDB transactions rolled back.", + "database") + .labels(rocksDbConfiguration.getLabel()); + + return new MonitorableKeyValueStorage( + readLatency, removeLatency, writeLatency, commitLatency, rollbackCount); + } + + public OperationTimer getReadLatency() { + return readLatency; + } + + public OperationTimer getRemoveLatency() { + return removeLatency; + } + + public OperationTimer getWriteLatency() { + return writeLatency; + } + + public OperationTimer getCommitLatency() { + return commitLatency; + } + + public Counter getRollbackCount() { + return rollbackCount; + } +} diff --git a/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDbKeyValueStorage.java b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDbKeyValueStorage.java index af605e3c7f..885c8cefe9 100644 --- a/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDbKeyValueStorage.java +++ b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDbKeyValueStorage.java @@ -12,12 +12,8 @@ */ package tech.pegasys.pantheon.services.kvstore; -import tech.pegasys.pantheon.metrics.Counter; import tech.pegasys.pantheon.metrics.MetricsSystem; import tech.pegasys.pantheon.metrics.OperationTimer; -import tech.pegasys.pantheon.metrics.PantheonMetricCategory; -import tech.pegasys.pantheon.metrics.prometheus.PrometheusMetricsSystem; -import tech.pegasys.pantheon.metrics.rocksdb.RocksDBStats; import tech.pegasys.pantheon.services.util.RocksDbUtil; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -46,13 +42,7 @@ public class RocksDbKeyValueStorage implements KeyValueStorage, Closeable { private final TransactionDBOptions txOptions; private final TransactionDB db; private final AtomicBoolean closed = new AtomicBoolean(false); - - private final OperationTimer readLatency; - private final OperationTimer removeLatency; - private final OperationTimer writeLatency; - private final OperationTimer commitLatency; - private final Counter rollbackCount; - private final Statistics stats; + private final MonitorableKeyValueStorage monitorableKeyValueStorage; public static KeyValueStorage create( final RocksDbConfiguration rocksDbConfiguration, final MetricsSystem metricsSystem) @@ -64,7 +54,7 @@ private RocksDbKeyValueStorage( final RocksDbConfiguration rocksDbConfiguration, final MetricsSystem metricsSystem) { RocksDbUtil.loadNativeLibrary(); try { - stats = new Statistics(); + final Statistics stats = new Statistics(); options = new Options() .setCreateIfMissing(true) @@ -76,78 +66,8 @@ private RocksDbKeyValueStorage( txOptions = new TransactionDBOptions(); db = TransactionDB.open(options, txOptions, rocksDbConfiguration.getDatabaseDir().toString()); - - readLatency = - metricsSystem - .createLabelledTimer( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "read_latency_seconds", - "Latency for read from RocksDB.", - "database") - .labels(rocksDbConfiguration.getLabel()); - removeLatency = - metricsSystem - .createLabelledTimer( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "remove_latency_seconds", - "Latency of remove requests from RocksDB.", - "database") - .labels(rocksDbConfiguration.getLabel()); - writeLatency = - metricsSystem - .createLabelledTimer( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "write_latency_seconds", - "Latency for write to RocksDB.", - "database") - .labels(rocksDbConfiguration.getLabel()); - commitLatency = - metricsSystem - .createLabelledTimer( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "commit_latency_seconds", - "Latency for commits to RocksDB.", - "database") - .labels(rocksDbConfiguration.getLabel()); - - if (metricsSystem instanceof PrometheusMetricsSystem) { - RocksDBStats.registerRocksDBMetrics(stats, (PrometheusMetricsSystem) metricsSystem); - } - - metricsSystem.createLongGauge( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "rocks_db_table_readers_memory_bytes", - "Estimated memory used for RocksDB index and filter blocks in bytes", - () -> { - try { - return db.getLongProperty("rocksdb.estimate-table-readers-mem"); - } catch (final RocksDBException e) { - LOG.debug("Failed to get RocksDB metric", e); - return 0L; - } - }); - - metricsSystem.createLongGauge( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "rocks_db_files_size_bytes", - "Estimated database size in bytes", - () -> { - try { - return db.getLongProperty("rocksdb.live-sst-files-size"); - } catch (final RocksDBException e) { - LOG.debug("Failed to get RocksDB metric", e); - return 0L; - } - }); - - rollbackCount = - metricsSystem - .createLabelledCounter( - PantheonMetricCategory.KVSTORE_ROCKSDB, - "rollback_count", - "Number of RocksDB transactions rolled back.", - "database") - .labels(rocksDbConfiguration.getLabel()); + monitorableKeyValueStorage = + MonitorableKeyValueStorage.of(metricsSystem, rocksDbConfiguration, db, stats); } catch (final RocksDBException e) { throw new StorageException(e); } @@ -162,7 +82,8 @@ private BlockBasedTableConfig createBlockBasedTableConfig(final RocksDbConfigura public Optional get(final BytesValue key) throws StorageException { throwIfClosed(); - try (final OperationTimer.TimingContext ignored = readLatency.startTimer()) { + try (final OperationTimer.TimingContext ignored = + monitorableKeyValueStorage.getReadLatency().startTimer()) { return Optional.ofNullable(db.get(key.getArrayUnsafe())).map(BytesValue::wrap); } catch (final RocksDBException e) { throw new StorageException(e); @@ -240,7 +161,8 @@ private class RocksDbTransaction extends AbstractTransaction { @Override protected void doPut(final BytesValue key, final BytesValue value) { - try (final OperationTimer.TimingContext ignored = writeLatency.startTimer()) { + try (final OperationTimer.TimingContext ignored = + monitorableKeyValueStorage.getWriteLatency().startTimer()) { innerTx.put(key.getArrayUnsafe(), value.getArrayUnsafe()); } catch (final RocksDBException e) { throw new StorageException(e); @@ -249,7 +171,8 @@ protected void doPut(final BytesValue key, final BytesValue value) { @Override protected void doRemove(final BytesValue key) { - try (final OperationTimer.TimingContext ignored = removeLatency.startTimer()) { + try (final OperationTimer.TimingContext ignored = + monitorableKeyValueStorage.getRemoveLatency().startTimer()) { innerTx.delete(key.getArrayUnsafe()); } catch (final RocksDBException e) { throw new StorageException(e); @@ -258,7 +181,8 @@ protected void doRemove(final BytesValue key) { @Override protected void doCommit() throws StorageException { - try (final OperationTimer.TimingContext ignored = commitLatency.startTimer()) { + try (final OperationTimer.TimingContext ignored = + monitorableKeyValueStorage.getCommitLatency().startTimer()) { innerTx.commit(); } catch (final RocksDBException e) { throw new StorageException(e); @@ -271,7 +195,7 @@ protected void doCommit() throws StorageException { protected void doRollback() { try { innerTx.rollback(); - rollbackCount.inc(); + monitorableKeyValueStorage.getRollbackCount().inc(); } catch (final RocksDBException e) { throw new StorageException(e); } finally { From 4037f7418b9fbf32d5bde0576062a722eed7e991 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 9 Jul 2019 18:31:06 +0200 Subject: [PATCH 02/56] Rename class --- .../kvstore/ColumnarRocksDbKeyValueStorage.java | 16 ++++++++-------- ...lueStorage.java => RocksDBMetricsHelper.java} | 8 ++++---- .../services/kvstore/RocksDbKeyValueStorage.java | 16 ++++++++-------- 3 files changed, 20 insertions(+), 20 deletions(-) rename services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/{MonitorableKeyValueStorage.java => RocksDBMetricsHelper.java} (96%) diff --git a/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/ColumnarRocksDbKeyValueStorage.java b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/ColumnarRocksDbKeyValueStorage.java index 5fbe0d101f..8e76019dac 100644 --- a/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/ColumnarRocksDbKeyValueStorage.java +++ b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/ColumnarRocksDbKeyValueStorage.java @@ -55,7 +55,7 @@ public class ColumnarRocksDbKeyValueStorage private final TransactionDB db; private final AtomicBoolean closed = new AtomicBoolean(false); private final Map columnHandlesByName; - private final MonitorableKeyValueStorage monitorableKeyValueStorage; + private final RocksDBMetricsHelper rocksDBMetricsHelper; public static ColumnarRocksDbKeyValueStorage create( final RocksDbConfiguration rocksDbConfiguration, @@ -102,8 +102,8 @@ private ColumnarRocksDbKeyValueStorage( rocksDbConfiguration.getDatabaseDir().toString(), columnDescriptors, columnHandles); - monitorableKeyValueStorage = - MonitorableKeyValueStorage.of(metricsSystem, rocksDbConfiguration, db, stats); + rocksDBMetricsHelper = + RocksDBMetricsHelper.of(metricsSystem, rocksDbConfiguration, db, stats); final Map segmentsById = segments.stream() .collect( @@ -141,7 +141,7 @@ public Optional get(final ColumnFamilyHandle segment, final BytesVal throwIfClosed(); try (final OperationTimer.TimingContext ignored = - monitorableKeyValueStorage.getReadLatency().startTimer()) { + rocksDBMetricsHelper.getReadLatency().startTimer()) { return Optional.ofNullable(db.get(segment, key.getArrayUnsafe())).map(BytesValue::wrap); } catch (final RocksDBException e) { throw new StorageException(e); @@ -221,7 +221,7 @@ private class RocksDbTransaction extends AbstractTransaction protected void doPut( final ColumnFamilyHandle segment, final BytesValue key, final BytesValue value) { try (final OperationTimer.TimingContext ignored = - monitorableKeyValueStorage.getWriteLatency().startTimer()) { + rocksDBMetricsHelper.getWriteLatency().startTimer()) { innerTx.put(segment, key.getArrayUnsafe(), value.getArrayUnsafe()); } catch (final RocksDBException e) { throw new StorageException(e); @@ -231,7 +231,7 @@ protected void doPut( @Override protected void doRemove(final ColumnFamilyHandle segment, final BytesValue key) { try (final OperationTimer.TimingContext ignored = - monitorableKeyValueStorage.getRemoveLatency().startTimer()) { + rocksDBMetricsHelper.getRemoveLatency().startTimer()) { innerTx.delete(segment, key.getArrayUnsafe()); } catch (final RocksDBException e) { throw new StorageException(e); @@ -241,7 +241,7 @@ protected void doRemove(final ColumnFamilyHandle segment, final BytesValue key) @Override protected void doCommit() throws StorageException { try (final OperationTimer.TimingContext ignored = - monitorableKeyValueStorage.getCommitLatency().startTimer()) { + rocksDBMetricsHelper.getCommitLatency().startTimer()) { innerTx.commit(); } catch (final RocksDBException e) { throw new StorageException(e); @@ -254,7 +254,7 @@ protected void doCommit() throws StorageException { protected void doRollback() { try { innerTx.rollback(); - monitorableKeyValueStorage.getRollbackCount().inc(); + rocksDBMetricsHelper.getRollbackCount().inc(); } catch (final RocksDBException e) { throw new StorageException(e); } finally { diff --git a/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/MonitorableKeyValueStorage.java b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDBMetricsHelper.java similarity index 96% rename from services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/MonitorableKeyValueStorage.java rename to services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDBMetricsHelper.java index 8d9d3d9159..a323e880ac 100644 --- a/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/MonitorableKeyValueStorage.java +++ b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDBMetricsHelper.java @@ -25,7 +25,7 @@ import org.rocksdb.Statistics; import org.rocksdb.TransactionDB; -public class MonitorableKeyValueStorage { +public class RocksDBMetricsHelper { private static final Logger LOG = LogManager.getLogger(); private final OperationTimer readLatency; @@ -34,7 +34,7 @@ public class MonitorableKeyValueStorage { private final OperationTimer commitLatency; private final Counter rollbackCount; - private MonitorableKeyValueStorage( + private RocksDBMetricsHelper( final OperationTimer readLatency, final OperationTimer removeLatency, final OperationTimer writeLatency, @@ -47,7 +47,7 @@ private MonitorableKeyValueStorage( this.rollbackCount = rollbackCount; } - public static MonitorableKeyValueStorage of( + public static RocksDBMetricsHelper of( final MetricsSystem metricsSystem, final RocksDbConfiguration rocksDbConfiguration, final TransactionDB db, @@ -124,7 +124,7 @@ public static MonitorableKeyValueStorage of( "database") .labels(rocksDbConfiguration.getLabel()); - return new MonitorableKeyValueStorage( + return new RocksDBMetricsHelper( readLatency, removeLatency, writeLatency, commitLatency, rollbackCount); } diff --git a/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDbKeyValueStorage.java b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDbKeyValueStorage.java index 885c8cefe9..e767f45085 100644 --- a/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDbKeyValueStorage.java +++ b/services/kvstore/src/main/java/tech/pegasys/pantheon/services/kvstore/RocksDbKeyValueStorage.java @@ -42,7 +42,7 @@ public class RocksDbKeyValueStorage implements KeyValueStorage, Closeable { private final TransactionDBOptions txOptions; private final TransactionDB db; private final AtomicBoolean closed = new AtomicBoolean(false); - private final MonitorableKeyValueStorage monitorableKeyValueStorage; + private final RocksDBMetricsHelper rocksDBMetricsHelper; public static KeyValueStorage create( final RocksDbConfiguration rocksDbConfiguration, final MetricsSystem metricsSystem) @@ -66,8 +66,8 @@ private RocksDbKeyValueStorage( txOptions = new TransactionDBOptions(); db = TransactionDB.open(options, txOptions, rocksDbConfiguration.getDatabaseDir().toString()); - monitorableKeyValueStorage = - MonitorableKeyValueStorage.of(metricsSystem, rocksDbConfiguration, db, stats); + rocksDBMetricsHelper = + RocksDBMetricsHelper.of(metricsSystem, rocksDbConfiguration, db, stats); } catch (final RocksDBException e) { throw new StorageException(e); } @@ -83,7 +83,7 @@ public Optional get(final BytesValue key) throws StorageException { throwIfClosed(); try (final OperationTimer.TimingContext ignored = - monitorableKeyValueStorage.getReadLatency().startTimer()) { + rocksDBMetricsHelper.getReadLatency().startTimer()) { return Optional.ofNullable(db.get(key.getArrayUnsafe())).map(BytesValue::wrap); } catch (final RocksDBException e) { throw new StorageException(e); @@ -162,7 +162,7 @@ private class RocksDbTransaction extends AbstractTransaction { @Override protected void doPut(final BytesValue key, final BytesValue value) { try (final OperationTimer.TimingContext ignored = - monitorableKeyValueStorage.getWriteLatency().startTimer()) { + rocksDBMetricsHelper.getWriteLatency().startTimer()) { innerTx.put(key.getArrayUnsafe(), value.getArrayUnsafe()); } catch (final RocksDBException e) { throw new StorageException(e); @@ -172,7 +172,7 @@ protected void doPut(final BytesValue key, final BytesValue value) { @Override protected void doRemove(final BytesValue key) { try (final OperationTimer.TimingContext ignored = - monitorableKeyValueStorage.getRemoveLatency().startTimer()) { + rocksDBMetricsHelper.getRemoveLatency().startTimer()) { innerTx.delete(key.getArrayUnsafe()); } catch (final RocksDBException e) { throw new StorageException(e); @@ -182,7 +182,7 @@ protected void doRemove(final BytesValue key) { @Override protected void doCommit() throws StorageException { try (final OperationTimer.TimingContext ignored = - monitorableKeyValueStorage.getCommitLatency().startTimer()) { + rocksDBMetricsHelper.getCommitLatency().startTimer()) { innerTx.commit(); } catch (final RocksDBException e) { throw new StorageException(e); @@ -195,7 +195,7 @@ protected void doCommit() throws StorageException { protected void doRollback() { try { innerTx.rollback(); - monitorableKeyValueStorage.getRollbackCount().inc(); + rocksDBMetricsHelper.getRollbackCount().inc(); } catch (final RocksDBException e) { throw new StorageException(e); } finally { From 08cc7ca5b785c666acd8d2b34d5f672837cd78fe Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Mon, 5 Aug 2019 18:25:22 +0200 Subject: [PATCH 03/56] [PAN-2995] Make account.getAddress() return an Optional
--- .../vm/TraceTransactionIntegrationTest.java | 2 +- .../ethereum/core/AbstractWorldUpdater.java | 9 +++++---- .../pegasys/pantheon/ethereum/core/Account.java | 5 +++-- .../mainnet/AbstractMessageProcessor.java | 9 +++++---- .../mainnet/MainnetTransactionProcessor.java | 2 +- .../privacy/PrivateTransactionProcessor.java | 2 +- .../worldstate/DefaultMutableWorldState.java | 17 ++++++++++------- .../vm/GeneralStateReferenceTestTools.java | 2 +- .../worldstate/WorldStateDownloaderTest.java | 4 ++-- .../internal/pojoadapter/AccountAdapter.java | 2 +- 10 files changed, 30 insertions(+), 24 deletions(-) diff --git a/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/vm/TraceTransactionIntegrationTest.java b/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/vm/TraceTransactionIntegrationTest.java index a0cecb33d7..52eab473af 100644 --- a/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/vm/TraceTransactionIntegrationTest.java +++ b/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/vm/TraceTransactionIntegrationTest.java @@ -112,7 +112,7 @@ public void shouldTraceSStoreOperation() { .gasPrice(Wei.ZERO) .nonce(1) .payload(BytesValue.fromHexString(CALL_SET_OTHER)) - .to(createdContract.getAddress()) + .to(createdContract.getAddress().get()) .value(Wei.ZERO) .signAndBuild(keyPair); final WorldUpdater storeUpdater = worldState.updater(); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java index 65cc473d5d..d6c7069e52 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java @@ -24,6 +24,7 @@ import java.util.HashSet; import java.util.Map; import java.util.NavigableMap; +import java.util.Optional; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; @@ -50,7 +51,7 @@ protected AbstractWorldUpdater(final W world) { protected abstract A getForMutation(Address address); protected UpdateTrackingAccount track(final UpdateTrackingAccount account) { - final Address address = account.getAddress(); + final Address address = account.getAddress().orElse(Address.ZERO); updatedAccounts.put(address, account); deletedAccounts.remove(address); return account; @@ -189,7 +190,7 @@ public static class UpdateTrackingAccount implements MutableA UpdateTrackingAccount(final A account) { checkNotNull(account); - this.address = account.getAddress(); + this.address = account.getAddress().orElse(Address.ZERO); this.account = account; this.nonce = account.getNonce(); @@ -230,8 +231,8 @@ public SortedMap getUpdatedStorage() { } @Override - public Address getAddress() { - return address; + public Optional
getAddress() { + return Optional.ofNullable(address); } @Override diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Account.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Account.java index 8fd80eac9b..305a3d1223 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Account.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Account.java @@ -17,6 +17,7 @@ import tech.pegasys.pantheon.util.uint.UInt256; import java.util.NavigableMap; +import java.util.Optional; /** * A world state account. @@ -51,7 +52,7 @@ public interface Account { * @return the Keccak-256 hash of the account address. */ default Hash getAddressHash() { - return Hash.hash(getAddress()); + return Hash.hash(getAddress().orElse(Address.ZERO)); } /** @@ -59,7 +60,7 @@ default Hash getAddressHash() { * * @return the account address */ - Address getAddress(); + Optional
getAddress(); /** * The account nonce, that is the number of transactions sent from that account. diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/AbstractMessageProcessor.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/AbstractMessageProcessor.java index 801eeeff5e..d3a707f764 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/AbstractMessageProcessor.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/AbstractMessageProcessor.java @@ -12,7 +12,6 @@ */ package tech.pegasys.pantheon.ethereum.mainnet; -import tech.pegasys.pantheon.ethereum.core.Account; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.vm.EVM; import tech.pegasys.pantheon.ethereum.vm.MessageFrame; @@ -83,10 +82,12 @@ protected AbstractMessageProcessor( private void clearAccumulatedStateBesidesGasAndOutput(final MessageFrame frame) { final Collection
addressesToForceCommit = frame.getWorldState().getTouchedAccounts().stream() - .filter(a -> forceDeleteAccountsWhenEmpty.contains(a.getAddress()) && a.isEmpty()) - .map(Account::getAddress) + .filter( + account -> + forceDeleteAccountsWhenEmpty.contains(account.getAddress().get()) + && account.isEmpty()) + .map(account -> account.getAddress().get()) .collect(Collectors.toCollection(ArrayList::new)); - // Clear any pending changes. frame.getWorldState().revert(); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionProcessor.java index a52a938489..c3b81038e2 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionProcessor.java @@ -335,7 +335,7 @@ public Result processTransaction( private static void clearEmptyAccounts(final WorldUpdater worldState) { worldState.getTouchedAccounts().stream() .filter(Account::isEmpty) - .forEach(a -> worldState.deleteAccount(a.getAddress())); + .forEach(account -> worldState.deleteAccount(account.getAddress().get())); } private void process(final MessageFrame frame, final OperationTracer operationTracer) { diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionProcessor.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionProcessor.java index 0fab1032df..11876945f4 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionProcessor.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionProcessor.java @@ -304,7 +304,7 @@ public Result processTransaction( private static void clearEmptyAccounts(final WorldUpdater worldState) { worldState.getTouchedAccounts().stream() .filter(Account::isEmpty) - .forEach(a -> worldState.deleteAccount(a.getAddress())); + .forEach(account -> worldState.deleteAccount(account.getAddress().get())); } private void process(final MessageFrame frame, final OperationTracer operationTracer) { diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java index 50d54b17fb..1b744184b3 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java @@ -233,8 +233,8 @@ private MerklePatriciaTrie storageTrie() { } @Override - public Address getAddress() { - return address; + public Optional
getAddress() { + return Optional.ofNullable(address); } @Override @@ -381,9 +381,9 @@ public void commit() { // Save the code in key-value storage ... Hash codeHash = origin == null ? Hash.EMPTY : origin.getCodeHash(); - if (updated.codeWasUpdated()) { + if (updated.codeWasUpdated() && updated.getAddress().isPresent()) { codeHash = Hash.hash(updated.getCode()); - wrapped.updatedAccountCode.put(updated.getAddress(), updated.getCode()); + wrapped.updatedAccountCode.put(updated.getAddress().get(), updated.getCode()); } // ...and storage in the account trie first. final boolean freshState = origin == null || updated.getStorageWasCleared(); @@ -392,13 +392,13 @@ public void commit() { wrapped.updatedStorageTries.remove(updated.getAddress()); } final SortedMap updatedStorage = updated.getUpdatedStorage(); - if (!updatedStorage.isEmpty()) { + if (!updatedStorage.isEmpty() && updated.getAddress().isPresent()) { // Apply any storage updates final MerklePatriciaTrie storageTrie = freshState ? wrapped.newAccountStorageTrie(Hash.EMPTY_TRIE_HASH) : origin.storageTrie(); - wrapped.updatedStorageTries.put(updated.getAddress(), storageTrie); + wrapped.updatedStorageTries.put(updated.getAddress().get(), storageTrie); for (final Map.Entry entry : updatedStorage.entrySet()) { final UInt256 value = entry.getValue(); final Hash keyHash = Hash.hash(entry.getKey().getBytes()); @@ -413,7 +413,10 @@ public void commit() { } // Save address preimage - wrapped.newAccountKeyPreimages.put(updated.getAddressHash(), updated.getAddress()); + updated + .getAddress() + .ifPresent( + address -> wrapped.newAccountKeyPreimages.put(updated.getAddressHash(), address)); // Lastly, save the new account. final BytesValue account = serializeAccount( diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTestTools.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTestTools.java index ba7fc250f9..edf804ab62 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTestTools.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTestTools.java @@ -122,7 +122,7 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { TransactionValidationParams.processingBlock()); final Account coinbase = worldStateUpdater.getOrCreate(spec.blockHeader().getCoinbase()); if (coinbase != null && coinbase.isEmpty() && shouldClearEmptyAccounts(spec.eip())) { - worldStateUpdater.deleteAccount(coinbase.getAddress()); + worldStateUpdater.deleteAccount(coinbase.getAddress().get()); } worldStateUpdater.commit(); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java index 3e6b1630a5..e9873528a0 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java @@ -881,7 +881,7 @@ private void downloadAvailableWorldStateFromPeers( // We shouldn't have any extra data locally assertThat(localStorage.contains(otherHeader.getStateRoot())).isFalse(); for (final Account otherAccount : otherAccounts) { - assertThat(localWorldState.get(otherAccount.getAddress())).isNull(); + assertThat(localWorldState.get(otherAccount.getAddress().get())).isNull(); } } @@ -933,7 +933,7 @@ private void respondPartially( private void assertAccountsMatch( final WorldState worldState, final List expectedAccounts) { for (final Account expectedAccount : expectedAccounts) { - final Account actualAccount = worldState.get(expectedAccount.getAddress()); + final Account actualAccount = worldState.get(expectedAccount.getAddress().get()); assertThat(actualAccount).isNotNull(); // Check each field assertThat(actualAccount.getNonce()).isEqualTo(expectedAccount.getNonce()); diff --git a/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/internal/pojoadapter/AccountAdapter.java b/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/internal/pojoadapter/AccountAdapter.java index eea734b953..7332f0eac2 100644 --- a/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/internal/pojoadapter/AccountAdapter.java +++ b/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/internal/pojoadapter/AccountAdapter.java @@ -31,7 +31,7 @@ public AccountAdapter(final Account account) { } public Optional
getAddress() { - return Optional.of(account.getAddress()); + return account.getAddress(); } public Optional getBalance() { From 15f90ea5e214ac624b891225bd096466c2ce1111 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Mon, 5 Aug 2019 18:49:59 +0200 Subject: [PATCH 04/56] fix Jenkins failure --- .../pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java | 4 ++-- .../ethereum/worldstate/DefaultMutableWorldState.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java index d6c7069e52..8b21aa7b50 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java @@ -409,13 +409,13 @@ public void commit() { // may kill some of "their" updates, and our updates may review some of the account "they" // deleted. deletedAccounts().forEach(wrapped.updatedAccounts::remove); - updatedAccounts().forEach(a -> wrapped.deletedAccounts.remove(a.getAddress())); + updatedAccounts().forEach(a -> wrapped.deletedAccounts.remove(a.getAddress().get())); // Then push our deletes and updates to the stacked ones. wrapped.deletedAccounts.addAll(deletedAccounts()); for (final UpdateTrackingAccount> update : updatedAccounts()) { - UpdateTrackingAccount existing = wrapped.updatedAccounts.get(update.getAddress()); + UpdateTrackingAccount existing = wrapped.updatedAccounts.get(update.getAddress().get()); if (existing == null) { // If we don't track this account, it's either a new one or getForMutation above had // created a tracker to satisfy the type system above and we can reuse that now. diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java index 1b744184b3..489ba55bf9 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java @@ -389,7 +389,7 @@ public void commit() { final boolean freshState = origin == null || updated.getStorageWasCleared(); Hash storageRoot = freshState ? Hash.EMPTY_TRIE_HASH : origin.getStorageRoot(); if (freshState) { - wrapped.updatedStorageTries.remove(updated.getAddress()); + wrapped.updatedStorageTries.remove(updated.getAddress().get()); } final SortedMap updatedStorage = updated.getUpdatedStorage(); if (!updatedStorage.isEmpty() && updated.getAddress().isPresent()) { From e5dc3fa073ef968bc017e513d15657204f54e519 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 6 Aug 2019 09:17:00 +0200 Subject: [PATCH 05/56] fix failing test --- .../jsonrpc/internal/methods/DebugAccountRange.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/DebugAccountRange.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/DebugAccountRange.java index 8b58c6c1e8..d49bde9495 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/DebugAccountRange.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/DebugAccountRange.java @@ -102,7 +102,13 @@ public JsonRpcResponse response(final JsonRpcRequest request) { .collect( Collectors.toMap( account -> account.getAddressHash().toString(), - account -> account.getAddress().toString())), + account -> { + if (account.getAddress().isPresent()) { + return account.getAddress().get().toString(); + } else { + return "null"; + } + })), nextKey.toString())); } } From e2bb261a185d20f75e33be0ec72f5b5851c40461 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 6 Aug 2019 09:34:37 +0200 Subject: [PATCH 06/56] fix failing test --- .../ethereum/worldstate/DefaultMutableWorldStateTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldStateTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldStateTest.java index 2916e3ec8c..2ace4d6522 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldStateTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldStateTest.java @@ -181,14 +181,14 @@ public void streamAccounts_singleAccount() { List accounts = worldState.streamAccounts(Bytes32.ZERO, 10).collect(Collectors.toList()); assertThat(accounts.size()).isEqualTo(1L); - assertThat(accounts.get(0).getAddress()).isEqualTo(ADDRESS); + assertThat(accounts.get(0).getAddress().get()).isEqualTo(ADDRESS); assertThat(accounts.get(0).getBalance()).isEqualTo(Wei.of(100000)); // Check again after persisting worldState.persist(); accounts = worldState.streamAccounts(Bytes32.ZERO, 10).collect(Collectors.toList()); assertThat(accounts.size()).isEqualTo(1L); - assertThat(accounts.get(0).getAddress()).isEqualTo(ADDRESS); + assertThat(accounts.get(0).getAddress().get()).isEqualTo(ADDRESS); assertThat(accounts.get(0).getBalance()).isEqualTo(Wei.of(100000)); } From 727cede86416b6159bf81ce65827b60fd5629ab3 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 6 Aug 2019 10:00:43 +0200 Subject: [PATCH 07/56] Revert "fix failing test" This reverts commit e2bb261a185d20f75e33be0ec72f5b5851c40461. --- .../ethereum/worldstate/DefaultMutableWorldStateTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldStateTest.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldStateTest.java index 2ace4d6522..2916e3ec8c 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldStateTest.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldStateTest.java @@ -181,14 +181,14 @@ public void streamAccounts_singleAccount() { List accounts = worldState.streamAccounts(Bytes32.ZERO, 10).collect(Collectors.toList()); assertThat(accounts.size()).isEqualTo(1L); - assertThat(accounts.get(0).getAddress().get()).isEqualTo(ADDRESS); + assertThat(accounts.get(0).getAddress()).isEqualTo(ADDRESS); assertThat(accounts.get(0).getBalance()).isEqualTo(Wei.of(100000)); // Check again after persisting worldState.persist(); accounts = worldState.streamAccounts(Bytes32.ZERO, 10).collect(Collectors.toList()); assertThat(accounts.size()).isEqualTo(1L); - assertThat(accounts.get(0).getAddress().get()).isEqualTo(ADDRESS); + assertThat(accounts.get(0).getAddress()).isEqualTo(ADDRESS); assertThat(accounts.get(0).getBalance()).isEqualTo(Wei.of(100000)); } From 093b1704cd60139b47b6c16a8465d553ed5c745e Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 6 Aug 2019 10:00:48 +0200 Subject: [PATCH 08/56] Revert "fix failing test" This reverts commit e5dc3fa073ef968bc017e513d15657204f54e519. --- .../jsonrpc/internal/methods/DebugAccountRange.java | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/DebugAccountRange.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/DebugAccountRange.java index d49bde9495..8b58c6c1e8 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/DebugAccountRange.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/DebugAccountRange.java @@ -102,13 +102,7 @@ public JsonRpcResponse response(final JsonRpcRequest request) { .collect( Collectors.toMap( account -> account.getAddressHash().toString(), - account -> { - if (account.getAddress().isPresent()) { - return account.getAddress().get().toString(); - } else { - return "null"; - } - })), + account -> account.getAddress().toString())), nextKey.toString())); } } From f6ff8987405518670553df9e405192d2ea54aaa7 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 6 Aug 2019 10:00:52 +0200 Subject: [PATCH 09/56] Revert "fix Jenkins failure" This reverts commit 15f90ea5e214ac624b891225bd096466c2ce1111. --- .../pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java | 4 ++-- .../ethereum/worldstate/DefaultMutableWorldState.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java index 8b21aa7b50..d6c7069e52 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java @@ -409,13 +409,13 @@ public void commit() { // may kill some of "their" updates, and our updates may review some of the account "they" // deleted. deletedAccounts().forEach(wrapped.updatedAccounts::remove); - updatedAccounts().forEach(a -> wrapped.deletedAccounts.remove(a.getAddress().get())); + updatedAccounts().forEach(a -> wrapped.deletedAccounts.remove(a.getAddress())); // Then push our deletes and updates to the stacked ones. wrapped.deletedAccounts.addAll(deletedAccounts()); for (final UpdateTrackingAccount> update : updatedAccounts()) { - UpdateTrackingAccount existing = wrapped.updatedAccounts.get(update.getAddress().get()); + UpdateTrackingAccount existing = wrapped.updatedAccounts.get(update.getAddress()); if (existing == null) { // If we don't track this account, it's either a new one or getForMutation above had // created a tracker to satisfy the type system above and we can reuse that now. diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java index 489ba55bf9..1b744184b3 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java @@ -389,7 +389,7 @@ public void commit() { final boolean freshState = origin == null || updated.getStorageWasCleared(); Hash storageRoot = freshState ? Hash.EMPTY_TRIE_HASH : origin.getStorageRoot(); if (freshState) { - wrapped.updatedStorageTries.remove(updated.getAddress().get()); + wrapped.updatedStorageTries.remove(updated.getAddress()); } final SortedMap updatedStorage = updated.getUpdatedStorage(); if (!updatedStorage.isEmpty() && updated.getAddress().isPresent()) { From 8ac0dc6320afc9463333eb52fc39d7e1d8ece579 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 6 Aug 2019 10:00:55 +0200 Subject: [PATCH 10/56] Revert "[PAN-2995] Make account.getAddress() return an Optional
" This reverts commit 08cc7ca5b785c666acd8d2b34d5f672837cd78fe. --- .../vm/TraceTransactionIntegrationTest.java | 2 +- .../ethereum/core/AbstractWorldUpdater.java | 9 ++++----- .../pegasys/pantheon/ethereum/core/Account.java | 5 ++--- .../mainnet/AbstractMessageProcessor.java | 9 ++++----- .../mainnet/MainnetTransactionProcessor.java | 2 +- .../privacy/PrivateTransactionProcessor.java | 2 +- .../worldstate/DefaultMutableWorldState.java | 17 +++++++---------- .../vm/GeneralStateReferenceTestTools.java | 2 +- .../worldstate/WorldStateDownloaderTest.java | 4 ++-- .../internal/pojoadapter/AccountAdapter.java | 2 +- 10 files changed, 24 insertions(+), 30 deletions(-) diff --git a/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/vm/TraceTransactionIntegrationTest.java b/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/vm/TraceTransactionIntegrationTest.java index 52eab473af..a0cecb33d7 100644 --- a/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/vm/TraceTransactionIntegrationTest.java +++ b/ethereum/core/src/integration-test/java/tech/pegasys/pantheon/ethereum/vm/TraceTransactionIntegrationTest.java @@ -112,7 +112,7 @@ public void shouldTraceSStoreOperation() { .gasPrice(Wei.ZERO) .nonce(1) .payload(BytesValue.fromHexString(CALL_SET_OTHER)) - .to(createdContract.getAddress().get()) + .to(createdContract.getAddress()) .value(Wei.ZERO) .signAndBuild(keyPair); final WorldUpdater storeUpdater = worldState.updater(); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java index d6c7069e52..65cc473d5d 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/AbstractWorldUpdater.java @@ -24,7 +24,6 @@ import java.util.HashSet; import java.util.Map; import java.util.NavigableMap; -import java.util.Optional; import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; @@ -51,7 +50,7 @@ protected AbstractWorldUpdater(final W world) { protected abstract A getForMutation(Address address); protected UpdateTrackingAccount track(final UpdateTrackingAccount account) { - final Address address = account.getAddress().orElse(Address.ZERO); + final Address address = account.getAddress(); updatedAccounts.put(address, account); deletedAccounts.remove(address); return account; @@ -190,7 +189,7 @@ public static class UpdateTrackingAccount implements MutableA UpdateTrackingAccount(final A account) { checkNotNull(account); - this.address = account.getAddress().orElse(Address.ZERO); + this.address = account.getAddress(); this.account = account; this.nonce = account.getNonce(); @@ -231,8 +230,8 @@ public SortedMap getUpdatedStorage() { } @Override - public Optional
getAddress() { - return Optional.ofNullable(address); + public Address getAddress() { + return address; } @Override diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Account.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Account.java index 305a3d1223..8fd80eac9b 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Account.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Account.java @@ -17,7 +17,6 @@ import tech.pegasys.pantheon.util.uint.UInt256; import java.util.NavigableMap; -import java.util.Optional; /** * A world state account. @@ -52,7 +51,7 @@ public interface Account { * @return the Keccak-256 hash of the account address. */ default Hash getAddressHash() { - return Hash.hash(getAddress().orElse(Address.ZERO)); + return Hash.hash(getAddress()); } /** @@ -60,7 +59,7 @@ default Hash getAddressHash() { * * @return the account address */ - Optional
getAddress(); + Address getAddress(); /** * The account nonce, that is the number of transactions sent from that account. diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/AbstractMessageProcessor.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/AbstractMessageProcessor.java index d3a707f764..801eeeff5e 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/AbstractMessageProcessor.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/AbstractMessageProcessor.java @@ -12,6 +12,7 @@ */ package tech.pegasys.pantheon.ethereum.mainnet; +import tech.pegasys.pantheon.ethereum.core.Account; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.vm.EVM; import tech.pegasys.pantheon.ethereum.vm.MessageFrame; @@ -82,12 +83,10 @@ protected AbstractMessageProcessor( private void clearAccumulatedStateBesidesGasAndOutput(final MessageFrame frame) { final Collection
addressesToForceCommit = frame.getWorldState().getTouchedAccounts().stream() - .filter( - account -> - forceDeleteAccountsWhenEmpty.contains(account.getAddress().get()) - && account.isEmpty()) - .map(account -> account.getAddress().get()) + .filter(a -> forceDeleteAccountsWhenEmpty.contains(a.getAddress()) && a.isEmpty()) + .map(Account::getAddress) .collect(Collectors.toCollection(ArrayList::new)); + // Clear any pending changes. frame.getWorldState().revert(); diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionProcessor.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionProcessor.java index c3b81038e2..a52a938489 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionProcessor.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/MainnetTransactionProcessor.java @@ -335,7 +335,7 @@ public Result processTransaction( private static void clearEmptyAccounts(final WorldUpdater worldState) { worldState.getTouchedAccounts().stream() .filter(Account::isEmpty) - .forEach(account -> worldState.deleteAccount(account.getAddress().get())); + .forEach(a -> worldState.deleteAccount(a.getAddress())); } private void process(final MessageFrame frame, final OperationTracer operationTracer) { diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionProcessor.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionProcessor.java index 11876945f4..0fab1032df 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionProcessor.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/privacy/PrivateTransactionProcessor.java @@ -304,7 +304,7 @@ public Result processTransaction( private static void clearEmptyAccounts(final WorldUpdater worldState) { worldState.getTouchedAccounts().stream() .filter(Account::isEmpty) - .forEach(account -> worldState.deleteAccount(account.getAddress().get())); + .forEach(a -> worldState.deleteAccount(a.getAddress())); } private void process(final MessageFrame frame, final OperationTracer operationTracer) { diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java index 1b744184b3..50d54b17fb 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/worldstate/DefaultMutableWorldState.java @@ -233,8 +233,8 @@ private MerklePatriciaTrie storageTrie() { } @Override - public Optional
getAddress() { - return Optional.ofNullable(address); + public Address getAddress() { + return address; } @Override @@ -381,9 +381,9 @@ public void commit() { // Save the code in key-value storage ... Hash codeHash = origin == null ? Hash.EMPTY : origin.getCodeHash(); - if (updated.codeWasUpdated() && updated.getAddress().isPresent()) { + if (updated.codeWasUpdated()) { codeHash = Hash.hash(updated.getCode()); - wrapped.updatedAccountCode.put(updated.getAddress().get(), updated.getCode()); + wrapped.updatedAccountCode.put(updated.getAddress(), updated.getCode()); } // ...and storage in the account trie first. final boolean freshState = origin == null || updated.getStorageWasCleared(); @@ -392,13 +392,13 @@ public void commit() { wrapped.updatedStorageTries.remove(updated.getAddress()); } final SortedMap updatedStorage = updated.getUpdatedStorage(); - if (!updatedStorage.isEmpty() && updated.getAddress().isPresent()) { + if (!updatedStorage.isEmpty()) { // Apply any storage updates final MerklePatriciaTrie storageTrie = freshState ? wrapped.newAccountStorageTrie(Hash.EMPTY_TRIE_HASH) : origin.storageTrie(); - wrapped.updatedStorageTries.put(updated.getAddress().get(), storageTrie); + wrapped.updatedStorageTries.put(updated.getAddress(), storageTrie); for (final Map.Entry entry : updatedStorage.entrySet()) { final UInt256 value = entry.getValue(); final Hash keyHash = Hash.hash(entry.getKey().getBytes()); @@ -413,10 +413,7 @@ public void commit() { } // Save address preimage - updated - .getAddress() - .ifPresent( - address -> wrapped.newAccountKeyPreimages.put(updated.getAddressHash(), address)); + wrapped.newAccountKeyPreimages.put(updated.getAddressHash(), updated.getAddress()); // Lastly, save the new account. final BytesValue account = serializeAccount( diff --git a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTestTools.java b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTestTools.java index edf804ab62..ba7fc250f9 100644 --- a/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTestTools.java +++ b/ethereum/core/src/test/java/tech/pegasys/pantheon/ethereum/vm/GeneralStateReferenceTestTools.java @@ -122,7 +122,7 @@ public static void executeTest(final GeneralStateTestCaseEipSpec spec) { TransactionValidationParams.processingBlock()); final Account coinbase = worldStateUpdater.getOrCreate(spec.blockHeader().getCoinbase()); if (coinbase != null && coinbase.isEmpty() && shouldClearEmptyAccounts(spec.eip())) { - worldStateUpdater.deleteAccount(coinbase.getAddress().get()); + worldStateUpdater.deleteAccount(coinbase.getAddress()); } worldStateUpdater.commit(); diff --git a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java index e9873528a0..3e6b1630a5 100644 --- a/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java +++ b/ethereum/eth/src/test/java/tech/pegasys/pantheon/ethereum/eth/sync/worldstate/WorldStateDownloaderTest.java @@ -881,7 +881,7 @@ private void downloadAvailableWorldStateFromPeers( // We shouldn't have any extra data locally assertThat(localStorage.contains(otherHeader.getStateRoot())).isFalse(); for (final Account otherAccount : otherAccounts) { - assertThat(localWorldState.get(otherAccount.getAddress().get())).isNull(); + assertThat(localWorldState.get(otherAccount.getAddress())).isNull(); } } @@ -933,7 +933,7 @@ private void respondPartially( private void assertAccountsMatch( final WorldState worldState, final List expectedAccounts) { for (final Account expectedAccount : expectedAccounts) { - final Account actualAccount = worldState.get(expectedAccount.getAddress().get()); + final Account actualAccount = worldState.get(expectedAccount.getAddress()); assertThat(actualAccount).isNotNull(); // Check each field assertThat(actualAccount.getNonce()).isEqualTo(expectedAccount.getNonce()); diff --git a/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/internal/pojoadapter/AccountAdapter.java b/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/internal/pojoadapter/AccountAdapter.java index 7332f0eac2..eea734b953 100644 --- a/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/internal/pojoadapter/AccountAdapter.java +++ b/ethereum/graphql/src/main/java/tech/pegasys/pantheon/ethereum/graphql/internal/pojoadapter/AccountAdapter.java @@ -31,7 +31,7 @@ public AccountAdapter(final Account account) { } public Optional
getAddress() { - return account.getAddress(); + return Optional.of(account.getAddress()); } public Optional getBalance() { From 545426595c8ede0b30ab1025bbdd262ce51281b7 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Mon, 26 Aug 2019 18:57:15 +0200 Subject: [PATCH 11/56] init trace_replayBlockTransactions --- .../pegasys/pantheon/ethereum/core/Gas.java | 4 ++ .../jsonrpc/JsonRpcMethodsFactory.java | 14 +++++ .../pantheon/ethereum/jsonrpc/RpcApis.java | 3 + .../methods/TraceReplayBlockTransactions.java | 61 ++++++++++++++++--- .../parameters/TraceTypeParameter.java | 2 +- 5 files changed, 73 insertions(+), 11 deletions(-) diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java index 94ef1ca977..003375b049 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java @@ -149,4 +149,8 @@ public boolean equals(final Object obj) { public String toString() { return Long.toString(value); } + + public String toHexString() { + return String.format("0x%s", Long.toHexString(value)); + } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java index 9e61c3f154..60103deed5 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java @@ -79,6 +79,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.NetServices; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.NetVersion; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.RpcModules; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.TraceReplayBlockTransactions; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.TxPoolPantheonStatistics; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.TxPoolPantheonTransactions; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.Web3ClientVersion; @@ -333,6 +334,19 @@ blockchainQueries, new TransactionTracer(blockReplay), parameter), new AdminChangeLogLevel(parameter)); } + if (rpcApis.contains(RpcApis.TRACE)) { + addMethods( + enabledMethods, + new TraceReplayBlockTransactions( + parameter, + new BlockTracer( + new BlockReplay( + protocolSchedule, + blockchainQueries.getBlockchain(), + blockchainQueries.getWorldStateArchive())), + blockchainQueries)); + } + boolean eea = rpcApis.contains(RpcApis.EEA), priv = rpcApis.contains(RpcApis.PRIV); if (eea || priv) { final PrivateMarkerTransactionFactory markerTransactionFactory = diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java index 3d17901110..dc9ee078aa 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java @@ -28,6 +28,7 @@ public class RpcApis { public static final RpcApi EEA = new RpcApi("EEA"); public static final RpcApi PRIV = new RpcApi("PRIV"); public static final RpcApi TX_POOL = new RpcApi("TXPOOL"); + public static final RpcApi TRACE = new RpcApi("TRACE"); public static final List DEFAULT_JSON_RPC_APIS = Arrays.asList(ETH, NET, WEB3); @@ -52,6 +53,8 @@ public static Optional valueOf(final String name) { return Optional.of(PRIV); } else if (name.equals(TX_POOL.getCliValue())) { return Optional.of(TX_POOL); + } else if (name.equals(TRACE.getCliValue())) { + return Optional.of(TRACE); } else { return Optional.empty(); } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 1dcd29207f..2c1e4a6731 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -12,8 +12,11 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockHeader; +import tech.pegasys.pantheon.ethereum.core.Gas; import tech.pegasys.pantheon.ethereum.debug.TraceOptions; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; @@ -27,10 +30,12 @@ import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import tech.pegasys.pantheon.util.bytes.BytesValue; public class TraceReplayBlockTransactions extends AbstractBlockParameterMethod { @@ -82,23 +87,59 @@ private Object traceBlock(final Block block, final TraceTypeParameter traceTypeP .orElse(null); } - private List formatTraces( + private JsonNode formatTraces( final List traces, final TraceTypeParameter traceTypeParameter) { - return traces.stream() - .map((trace) -> formatTrace(trace, traceTypeParameter)) - .collect(Collectors.toList()); + final Set traceTypes = traceTypeParameter.getTraceTypes(); + final ObjectMapper mapper = new ObjectMapper(); + final ArrayNode resultArrayNode = mapper.createArrayNode(); + final ObjectNode resultNode = mapper.createObjectNode(); + if (traceTypes.contains(TraceTypeParameter.TraceType.TRACE)) { + final ArrayNode tracesNode = resultNode.putArray("trace"); + traces.forEach((trace) -> formatWithTraceOption(trace, mapper, tracesNode)); + } + + resultArrayNode.add(resultNode); + return resultArrayNode; } @SuppressWarnings("unused") - private JsonNode formatTrace( - final TransactionTrace trace, final TraceTypeParameter traceTypeParameter) { - // TODO: generate result - ObjectMapper mapper = new ObjectMapper(); - return mapper.createObjectNode(); + private void formatWithTraceOption( + final TransactionTrace trace, final ObjectMapper mapper, final ArrayNode tracesNode) { + final ObjectNode traceNode = mapper.createObjectNode(); + generateActionNode(traceNode, trace); + generateResultNode(traceNode, trace); + traceNode.put("type", "call"); + tracesNode.add(traceNode); + } + + private void generateResultNode(final ObjectNode traceNode, final TransactionTrace trace) { + final ObjectNode traceResultNode = traceNode.putObject("result"); + traceResultNode.put("output", "0x"); + traceResultNode.put("gasUsed", Gas.of(trace.getGas()).toHexString()); + } + + private void generateActionNode(final ObjectNode traceNode, final TransactionTrace trace) { + final ObjectNode actionResultNode = traceNode.putObject("action"); + actionResultNode.put("callType", "call"); + actionResultNode.put("from", trace.getTransaction().getSender().toString()); + actionResultNode.put( + "gas", trace.getTransaction().getUpfrontGasCost().toStrictShortHexString()); + actionResultNode.put( + "input", + trace + .getTransaction() + .getData() + .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) + .toString()); + trace + .getTransaction() + .getTo() + .ifPresent(address -> actionResultNode.put("to", address.toString())); + actionResultNode.put("value", trace.getTransaction().getValue().toStrictShortHexString()); } private Object emptyResult() { - ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = new ObjectMapper(); return mapper.createArrayNode(); } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java index 059cc0677f..8b13ba9dc5 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java @@ -25,7 +25,7 @@ public class TraceTypeParameter { - enum TraceType { + public enum TraceType { TRACE, VM_TRACE, STATE_DIFF; From 756f52bb019c0e0c61aac4a97269d40198341c86 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 27 Aug 2019 09:48:05 +0200 Subject: [PATCH 12/56] Revert "init trace_replayBlockTransactions" This reverts commit 545426595c8ede0b30ab1025bbdd262ce51281b7. --- .../pegasys/pantheon/ethereum/core/Gas.java | 4 -- .../jsonrpc/JsonRpcMethodsFactory.java | 14 ----- .../pantheon/ethereum/jsonrpc/RpcApis.java | 3 - .../methods/TraceReplayBlockTransactions.java | 61 +++---------------- .../parameters/TraceTypeParameter.java | 2 +- 5 files changed, 11 insertions(+), 73 deletions(-) diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java index 003375b049..94ef1ca977 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java @@ -149,8 +149,4 @@ public boolean equals(final Object obj) { public String toString() { return Long.toString(value); } - - public String toHexString() { - return String.format("0x%s", Long.toHexString(value)); - } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java index 60103deed5..9e61c3f154 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java @@ -79,7 +79,6 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.NetServices; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.NetVersion; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.RpcModules; -import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.TraceReplayBlockTransactions; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.TxPoolPantheonStatistics; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.TxPoolPantheonTransactions; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.Web3ClientVersion; @@ -334,19 +333,6 @@ blockchainQueries, new TransactionTracer(blockReplay), parameter), new AdminChangeLogLevel(parameter)); } - if (rpcApis.contains(RpcApis.TRACE)) { - addMethods( - enabledMethods, - new TraceReplayBlockTransactions( - parameter, - new BlockTracer( - new BlockReplay( - protocolSchedule, - blockchainQueries.getBlockchain(), - blockchainQueries.getWorldStateArchive())), - blockchainQueries)); - } - boolean eea = rpcApis.contains(RpcApis.EEA), priv = rpcApis.contains(RpcApis.PRIV); if (eea || priv) { final PrivateMarkerTransactionFactory markerTransactionFactory = diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java index dc9ee078aa..3d17901110 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java @@ -28,7 +28,6 @@ public class RpcApis { public static final RpcApi EEA = new RpcApi("EEA"); public static final RpcApi PRIV = new RpcApi("PRIV"); public static final RpcApi TX_POOL = new RpcApi("TXPOOL"); - public static final RpcApi TRACE = new RpcApi("TRACE"); public static final List DEFAULT_JSON_RPC_APIS = Arrays.asList(ETH, NET, WEB3); @@ -53,8 +52,6 @@ public static Optional valueOf(final String name) { return Optional.of(PRIV); } else if (name.equals(TX_POOL.getCliValue())) { return Optional.of(TX_POOL); - } else if (name.equals(TRACE.getCliValue())) { - return Optional.of(TRACE); } else { return Optional.empty(); } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 2c1e4a6731..1dcd29207f 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -12,11 +12,8 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockHeader; -import tech.pegasys.pantheon.ethereum.core.Gas; import tech.pegasys.pantheon.ethereum.debug.TraceOptions; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; @@ -30,12 +27,10 @@ import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import tech.pegasys.pantheon.util.bytes.BytesValue; public class TraceReplayBlockTransactions extends AbstractBlockParameterMethod { @@ -87,59 +82,23 @@ private Object traceBlock(final Block block, final TraceTypeParameter traceTypeP .orElse(null); } - private JsonNode formatTraces( + private List formatTraces( final List traces, final TraceTypeParameter traceTypeParameter) { - final Set traceTypes = traceTypeParameter.getTraceTypes(); - final ObjectMapper mapper = new ObjectMapper(); - final ArrayNode resultArrayNode = mapper.createArrayNode(); - final ObjectNode resultNode = mapper.createObjectNode(); - if (traceTypes.contains(TraceTypeParameter.TraceType.TRACE)) { - final ArrayNode tracesNode = resultNode.putArray("trace"); - traces.forEach((trace) -> formatWithTraceOption(trace, mapper, tracesNode)); - } - - resultArrayNode.add(resultNode); - return resultArrayNode; + return traces.stream() + .map((trace) -> formatTrace(trace, traceTypeParameter)) + .collect(Collectors.toList()); } @SuppressWarnings("unused") - private void formatWithTraceOption( - final TransactionTrace trace, final ObjectMapper mapper, final ArrayNode tracesNode) { - final ObjectNode traceNode = mapper.createObjectNode(); - generateActionNode(traceNode, trace); - generateResultNode(traceNode, trace); - traceNode.put("type", "call"); - tracesNode.add(traceNode); - } - - private void generateResultNode(final ObjectNode traceNode, final TransactionTrace trace) { - final ObjectNode traceResultNode = traceNode.putObject("result"); - traceResultNode.put("output", "0x"); - traceResultNode.put("gasUsed", Gas.of(trace.getGas()).toHexString()); - } - - private void generateActionNode(final ObjectNode traceNode, final TransactionTrace trace) { - final ObjectNode actionResultNode = traceNode.putObject("action"); - actionResultNode.put("callType", "call"); - actionResultNode.put("from", trace.getTransaction().getSender().toString()); - actionResultNode.put( - "gas", trace.getTransaction().getUpfrontGasCost().toStrictShortHexString()); - actionResultNode.put( - "input", - trace - .getTransaction() - .getData() - .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) - .toString()); - trace - .getTransaction() - .getTo() - .ifPresent(address -> actionResultNode.put("to", address.toString())); - actionResultNode.put("value", trace.getTransaction().getValue().toStrictShortHexString()); + private JsonNode formatTrace( + final TransactionTrace trace, final TraceTypeParameter traceTypeParameter) { + // TODO: generate result + ObjectMapper mapper = new ObjectMapper(); + return mapper.createObjectNode(); } private Object emptyResult() { - final ObjectMapper mapper = new ObjectMapper(); + ObjectMapper mapper = new ObjectMapper(); return mapper.createArrayNode(); } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java index 8b13ba9dc5..059cc0677f 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java @@ -25,7 +25,7 @@ public class TraceTypeParameter { - public enum TraceType { + enum TraceType { TRACE, VM_TRACE, STATE_DIFF; From 03ee39b0434d6e4b5510aa665620bb7d4005fc66 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 27 Aug 2019 09:48:33 +0200 Subject: [PATCH 13/56] Revert "Revert "init trace_replayBlockTransactions"" This reverts commit 756f52bb019c0e0c61aac4a97269d40198341c86. --- .../pegasys/pantheon/ethereum/core/Gas.java | 4 ++ .../jsonrpc/JsonRpcMethodsFactory.java | 14 +++++ .../pantheon/ethereum/jsonrpc/RpcApis.java | 3 + .../methods/TraceReplayBlockTransactions.java | 61 ++++++++++++++++--- .../parameters/TraceTypeParameter.java | 2 +- 5 files changed, 73 insertions(+), 11 deletions(-) diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java index 94ef1ca977..003375b049 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/core/Gas.java @@ -149,4 +149,8 @@ public boolean equals(final Object obj) { public String toString() { return Long.toString(value); } + + public String toHexString() { + return String.format("0x%s", Long.toHexString(value)); + } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java index 9e61c3f154..60103deed5 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java @@ -79,6 +79,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.NetServices; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.NetVersion; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.RpcModules; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.TraceReplayBlockTransactions; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.TxPoolPantheonStatistics; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.TxPoolPantheonTransactions; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods.Web3ClientVersion; @@ -333,6 +334,19 @@ blockchainQueries, new TransactionTracer(blockReplay), parameter), new AdminChangeLogLevel(parameter)); } + if (rpcApis.contains(RpcApis.TRACE)) { + addMethods( + enabledMethods, + new TraceReplayBlockTransactions( + parameter, + new BlockTracer( + new BlockReplay( + protocolSchedule, + blockchainQueries.getBlockchain(), + blockchainQueries.getWorldStateArchive())), + blockchainQueries)); + } + boolean eea = rpcApis.contains(RpcApis.EEA), priv = rpcApis.contains(RpcApis.PRIV); if (eea || priv) { final PrivateMarkerTransactionFactory markerTransactionFactory = diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java index 3d17901110..dc9ee078aa 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/RpcApis.java @@ -28,6 +28,7 @@ public class RpcApis { public static final RpcApi EEA = new RpcApi("EEA"); public static final RpcApi PRIV = new RpcApi("PRIV"); public static final RpcApi TX_POOL = new RpcApi("TXPOOL"); + public static final RpcApi TRACE = new RpcApi("TRACE"); public static final List DEFAULT_JSON_RPC_APIS = Arrays.asList(ETH, NET, WEB3); @@ -52,6 +53,8 @@ public static Optional valueOf(final String name) { return Optional.of(PRIV); } else if (name.equals(TX_POOL.getCliValue())) { return Optional.of(TX_POOL); + } else if (name.equals(TRACE.getCliValue())) { + return Optional.of(TRACE); } else { return Optional.empty(); } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 1dcd29207f..2c1e4a6731 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -12,8 +12,11 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockHeader; +import tech.pegasys.pantheon.ethereum.core.Gas; import tech.pegasys.pantheon.ethereum.debug.TraceOptions; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; @@ -27,10 +30,12 @@ import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer; import java.util.List; +import java.util.Set; import java.util.stream.Collectors; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; +import tech.pegasys.pantheon.util.bytes.BytesValue; public class TraceReplayBlockTransactions extends AbstractBlockParameterMethod { @@ -82,23 +87,59 @@ private Object traceBlock(final Block block, final TraceTypeParameter traceTypeP .orElse(null); } - private List formatTraces( + private JsonNode formatTraces( final List traces, final TraceTypeParameter traceTypeParameter) { - return traces.stream() - .map((trace) -> formatTrace(trace, traceTypeParameter)) - .collect(Collectors.toList()); + final Set traceTypes = traceTypeParameter.getTraceTypes(); + final ObjectMapper mapper = new ObjectMapper(); + final ArrayNode resultArrayNode = mapper.createArrayNode(); + final ObjectNode resultNode = mapper.createObjectNode(); + if (traceTypes.contains(TraceTypeParameter.TraceType.TRACE)) { + final ArrayNode tracesNode = resultNode.putArray("trace"); + traces.forEach((trace) -> formatWithTraceOption(trace, mapper, tracesNode)); + } + + resultArrayNode.add(resultNode); + return resultArrayNode; } @SuppressWarnings("unused") - private JsonNode formatTrace( - final TransactionTrace trace, final TraceTypeParameter traceTypeParameter) { - // TODO: generate result - ObjectMapper mapper = new ObjectMapper(); - return mapper.createObjectNode(); + private void formatWithTraceOption( + final TransactionTrace trace, final ObjectMapper mapper, final ArrayNode tracesNode) { + final ObjectNode traceNode = mapper.createObjectNode(); + generateActionNode(traceNode, trace); + generateResultNode(traceNode, trace); + traceNode.put("type", "call"); + tracesNode.add(traceNode); + } + + private void generateResultNode(final ObjectNode traceNode, final TransactionTrace trace) { + final ObjectNode traceResultNode = traceNode.putObject("result"); + traceResultNode.put("output", "0x"); + traceResultNode.put("gasUsed", Gas.of(trace.getGas()).toHexString()); + } + + private void generateActionNode(final ObjectNode traceNode, final TransactionTrace trace) { + final ObjectNode actionResultNode = traceNode.putObject("action"); + actionResultNode.put("callType", "call"); + actionResultNode.put("from", trace.getTransaction().getSender().toString()); + actionResultNode.put( + "gas", trace.getTransaction().getUpfrontGasCost().toStrictShortHexString()); + actionResultNode.put( + "input", + trace + .getTransaction() + .getData() + .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) + .toString()); + trace + .getTransaction() + .getTo() + .ifPresent(address -> actionResultNode.put("to", address.toString())); + actionResultNode.put("value", trace.getTransaction().getValue().toStrictShortHexString()); } private Object emptyResult() { - ObjectMapper mapper = new ObjectMapper(); + final ObjectMapper mapper = new ObjectMapper(); return mapper.createArrayNode(); } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java index 059cc0677f..8b13ba9dc5 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/parameters/TraceTypeParameter.java @@ -25,7 +25,7 @@ public class TraceTypeParameter { - enum TraceType { + public enum TraceType { TRACE, VM_TRACE, STATE_DIFF; From 2f6e05591c89f76e1f64ca2ec80499ad0851eac7 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 27 Aug 2019 13:15:05 +0200 Subject: [PATCH 14/56] Update TraceReplayBlockTransactions.java --- .../internal/methods/TraceReplayBlockTransactions.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 2c1e4a6731..985f40dbcc 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -12,6 +12,8 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import tech.pegasys.pantheon.ethereum.core.Block; @@ -28,14 +30,10 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer; +import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.List; import java.util.Set; -import java.util.stream.Collectors; - -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import tech.pegasys.pantheon.util.bytes.BytesValue; public class TraceReplayBlockTransactions extends AbstractBlockParameterMethod { From 055c6729ca8ade68b66dec58223cd9f6a63f651c Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 27 Aug 2019 13:46:56 +0200 Subject: [PATCH 15/56] Check request parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Method returns an error if any option other than “trace” is supplied. --- .../methods/TraceReplayBlockTransactions.java | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 985f40dbcc..05dc9c3fe4 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -12,16 +12,13 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; -import com.fasterxml.jackson.databind.node.ObjectNode; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockHeader; import tech.pegasys.pantheon.ethereum.core.Gas; import tech.pegasys.pantheon.ethereum.debug.TraceOptions; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.exception.InvalidJsonRpcParameters; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.BlockParameter; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.JsonRpcParameter; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.parameters.TraceTypeParameter; @@ -35,7 +32,15 @@ import java.util.List; import java.util.Set; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public class TraceReplayBlockTransactions extends AbstractBlockParameterMethod { + private static final Logger LOG = LogManager.getLogger(); private final BlockTracer blockTracer; @@ -62,6 +67,14 @@ protected Object resultByBlockNumber(final JsonRpcRequest request, final long bl final TraceTypeParameter traceTypeParameter = getParameters().required(request.getParams(), 1, TraceTypeParameter.class); + // TODO : as mentioned in https://pegasys1.atlassian.net/browse/PIE-1805 + // method returns an error if any option other than “trace” is supplied. + if (traceTypeParameter.getTraceTypes().contains(TraceTypeParameter.TraceType.STATE_DIFF) + || traceTypeParameter.getTraceTypes().contains(TraceTypeParameter.TraceType.VM_TRACE)) { + LOG.warn("Unsupported trace option"); + throw new InvalidJsonRpcParameters("Invalid trace types supplied."); + } + if (blockNumber == BlockHeader.GENESIS_BLOCK_NUMBER) { // Nothing to trace for the genesis block return emptyResult(); From fb0860422cf01bccb19c994faa2e295a1d3667b5 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 27 Aug 2019 15:57:31 +0200 Subject: [PATCH 16/56] Update TraceReplayBlockTransactions.java --- .../methods/TraceReplayBlockTransactions.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 05dc9c3fe4..cadf26a23f 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -116,13 +116,22 @@ private JsonNode formatTraces( @SuppressWarnings("unused") private void formatWithTraceOption( final TransactionTrace trace, final ObjectMapper mapper, final ArrayNode tracesNode) { + int numberOfTraceNodes = 0; + trace.getTraceFrames().forEach(traceFrame -> { + + }); final ObjectNode traceNode = mapper.createObjectNode(); generateActionNode(traceNode, trace); - generateResultNode(traceNode, trace); + /*generateResultNode(traceNode, trace);*/ traceNode.put("type", "call"); tracesNode.add(traceNode); } + private void generateActionNode(final ObjectNode traceNode, final TransactionTrace trace) { + + } + + /* private void generateResultNode(final ObjectNode traceNode, final TransactionTrace trace) { final ObjectNode traceResultNode = traceNode.putObject("result"); traceResultNode.put("output", "0x"); @@ -147,7 +156,7 @@ private void generateActionNode(final ObjectNode traceNode, final TransactionTra .getTo() .ifPresent(address -> actionResultNode.put("to", address.toString())); actionResultNode.put("value", trace.getTransaction().getValue().toStrictShortHexString()); - } + }*/ private Object emptyResult() { final ObjectMapper mapper = new ObjectMapper(); From bcda14aafb648f2c8ba490f18e894023fabc122e Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 27 Aug 2019 18:25:07 +0200 Subject: [PATCH 17/56] implement trace_replayBlockTransactions - start business logic implementation - iterate through `TraceFrame` and transform to parity style - detect `CALL` opcode to retrieve contract address required in parity format --- .../methods/TraceReplayBlockTransactions.java | 88 +++++++++--- .../internal/results/tracing/Action.java | 127 ++++++++++++++++++ .../internal/results/tracing/FlatTrace.java | 119 ++++++++++++++++ .../internal/results/tracing/Result.java | 62 +++++++++ 4 files changed, 379 insertions(+), 17 deletions(-) create mode 100644 ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java create mode 100644 ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java create mode 100644 ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index cadf26a23f..724980694d 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -12,9 +12,10 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods; +import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockHeader; -import tech.pegasys.pantheon.ethereum.core.Gas; +import tech.pegasys.pantheon.ethereum.debug.TraceFrame; import tech.pegasys.pantheon.ethereum.debug.TraceOptions; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; @@ -26,11 +27,18 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockTracer; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.Action; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.FlatTrace; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.Result; import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer; +import tech.pegasys.pantheon.util.bytes.Bytes32; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.util.ArrayList; import java.util.List; import java.util.Set; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -67,8 +75,8 @@ protected Object resultByBlockNumber(final JsonRpcRequest request, final long bl final TraceTypeParameter traceTypeParameter = getParameters().required(request.getParams(), 1, TraceTypeParameter.class); - // TODO : as mentioned in https://pegasys1.atlassian.net/browse/PIE-1805 - // method returns an error if any option other than “trace” is supplied. + // TODO : method returns an error if any option other than “trace” is supplied. + // remove when others options are implemented if (traceTypeParameter.getTraceTypes().contains(TraceTypeParameter.TraceType.STATE_DIFF) || traceTypeParameter.getTraceTypes().contains(TraceTypeParameter.TraceType.VM_TRACE)) { LOG.warn("Unsupported trace option"); @@ -104,9 +112,10 @@ private JsonNode formatTraces( final ObjectMapper mapper = new ObjectMapper(); final ArrayNode resultArrayNode = mapper.createArrayNode(); final ObjectNode resultNode = mapper.createObjectNode(); + final AtomicInteger traceCounter = new AtomicInteger(0); if (traceTypes.contains(TraceTypeParameter.TraceType.TRACE)) { final ArrayNode tracesNode = resultNode.putArray("trace"); - traces.forEach((trace) -> formatWithTraceOption(trace, mapper, tracesNode)); + traces.forEach((trace) -> formatWithTraceOption(trace, traceCounter, mapper, tracesNode)); } resultArrayNode.add(resultNode); @@ -115,21 +124,66 @@ private JsonNode formatTraces( @SuppressWarnings("unused") private void formatWithTraceOption( - final TransactionTrace trace, final ObjectMapper mapper, final ArrayNode tracesNode) { - int numberOfTraceNodes = 0; - trace.getTraceFrames().forEach(traceFrame -> { - - }); - final ObjectNode traceNode = mapper.createObjectNode(); - generateActionNode(traceNode, trace); - /*generateResultNode(traceNode, trace);*/ - traceNode.put("type", "call"); - tracesNode.add(traceNode); + final TransactionTrace trace, + final AtomicInteger traceCounter, + final ObjectMapper mapper, + final ArrayNode tracesNode) { + final ObjectNode currentTraceNode = mapper.createObjectNode(); + final FlatTrace.Builder firstFlatTraceBuilder = FlatTrace.builder(); + String lastContractAddress = trace.getTransaction().getTo().orElse(Address.ZERO).getHexString(); + final Action.Builder firstFlatTraceActionBuilder = + Action.builder() + .from(trace.getTransaction().getSender().getHexString()) + .to(trace.getTransaction().getTo().orElse(Address.ZERO).toString()) + .input( + trace + .getTransaction() + .getData() + .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) + .getHexString()) + .gas(trace.getTransaction().getUpfrontGasCost().toShortHexString()) + .callType("call") + .value(trace.getTransaction().getValue().toShortHexString()); + final Result.Builder firstFlatTraceResultBuilder = Result.builder(); + final List subTracesBuilders = new ArrayList<>(); + FlatTrace.Builder previousTraceBuilder = firstFlatTraceBuilder; + final List currentTraceAddressVector = new ArrayList<>(); + currentTraceAddressVector.add(traceCounter.get()); + final AtomicInteger subTracesCounter = new AtomicInteger(0); + for (TraceFrame traceFrame : trace.getTraceFrames()) { + if ("CALL".equals(traceFrame.getOpcode())) { + final Bytes32[] stack = traceFrame.getStack().orElseThrow(); + final Bytes32 contractCallAddress = stack[stack.length - 2]; + LOG.info("Call detected to contract: {}", contractCallAddress.toString()); + final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); + final Bytes32 contractCallInput = memory[0]; + final FlatTrace.Builder subTraceBuilder = + FlatTrace.builder().traceAddress(currentTraceAddressVector.toArray(new Integer[0])); + final Action.Builder subTraceActionBuilder = + Action.builder() + .from(lastContractAddress) + .to(contractCallAddress.toString()) + .input(contractCallInput.getHexString()) + .callType("call") + .value(trace.getTransaction().getValue().toShortHexString()); + subTracesBuilders.add(subTraceBuilder.action(subTraceActionBuilder.build())); + previousTraceBuilder.incSubTraces(); + previousTraceBuilder = subTraceBuilder; + IntStream.of(subTracesCounter.incrementAndGet()) + .forEach(value -> currentTraceAddressVector.add(value)); + } + if ("RETURN".equals(traceFrame.getOpcode())) {} + } + tracesNode.addPOJO( + firstFlatTraceBuilder + .action(firstFlatTraceActionBuilder.build()) + .result(firstFlatTraceResultBuilder.build()) + .build()); + subTracesBuilders.forEach(flatTraceBuilder -> tracesNode.addPOJO(flatTraceBuilder.build())); + traceCounter.incrementAndGet(); } - private void generateActionNode(final ObjectNode traceNode, final TransactionTrace trace) { - - } + private void generateActionNode(final ObjectNode traceNode, final TransactionTrace trace) {} /* private void generateResultNode(final ObjectNode traceNode, final TransactionTrace trace) { diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java new file mode 100644 index 0000000000..d2aaf095be --- /dev/null +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -0,0 +1,127 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; + +public class Action { + + private String callType; + private String from; + private String gas; + private String input; + private String to; + private String value; + + public String getCallType() { + return callType; + } + + public void setCallType(final String callType) { + this.callType = callType; + } + + public String getFrom() { + return from; + } + + public void setFrom(final String from) { + this.from = from; + } + + public String getGas() { + return gas; + } + + public void setGas(final String gas) { + this.gas = gas; + } + + public String getInput() { + return input; + } + + public void setInput(final String input) { + this.input = input; + } + + public String getTo() { + return to; + } + + public void setTo(final String to) { + this.to = to; + } + + public String getValue() { + return value; + } + + public void setValue(final String value) { + this.value = value; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private String callType = "call"; + private String from; + private String gas; + private String input; + private String to; + private String value; + + private Builder() {} + + public Builder callType(final String callType) { + this.callType = callType; + return this; + } + + public Builder from(final String from) { + this.from = from; + return this; + } + + public Builder gas(final String gas) { + this.gas = gas; + return this; + } + + public Builder input(final String input) { + this.input = input; + return this; + } + + public Builder to(final String to) { + this.to = to; + return this; + } + + public Builder value(final String value) { + this.value = value; + return this; + } + + public Action build() { + final Action action = new Action(); + action.setCallType(callType); + action.setFrom(from); + action.setGas(gas); + action.setInput(input); + action.setTo(to); + action.setValue(value); + return action; + } + } +} diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java new file mode 100644 index 0000000000..7e6da73fb6 --- /dev/null +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -0,0 +1,119 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; + +public class FlatTrace { + private Action action; + private Result result; + private int subtraces; + private Integer[] traceAddress = new Integer[0]; + private String type; + + public Action getAction() { + return action; + } + + public void setAction(final Action action) { + this.action = action; + } + + public Result getResult() { + return result; + } + + public void setResult(final Result result) { + this.result = result; + } + + public int getSubtraces() { + return subtraces; + } + + public void setSubtraces(final int subtraces) { + this.subtraces = subtraces; + } + + public Integer[] getTraceAddress() { + return traceAddress; + } + + public void setTraceAddress(final Integer[] traceAddress) { + this.traceAddress = traceAddress; + } + + public String getType() { + return type; + } + + public void setType(final String type) { + this.type = type; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private Action action; + private Result result; + private int subtraces; + private Integer[] traceAddress = new Integer[0]; + private String type = "call"; + + private Builder() {} + + public Builder action(final Action action) { + this.action = action; + return this; + } + + public Builder result(final Result result) { + this.result = result; + return this; + } + + public Builder subtraces(int subtraces) { + this.subtraces = subtraces; + return this; + } + + public Builder traceAddress(Integer[] traceAddress) { + this.traceAddress = traceAddress; + return this; + } + + public Builder type(final String type) { + this.type = type; + return this; + } + + public Builder incSubTraces() { + return incSubTraces(1); + } + + public Builder incSubTraces(final int n) { + this.subtraces += n; + return this; + } + + public FlatTrace build() { + FlatTrace flatTrace = new FlatTrace(); + flatTrace.setAction(action); + flatTrace.setResult(result); + flatTrace.setSubtraces(subtraces); + flatTrace.setTraceAddress(traceAddress); + flatTrace.setType(type); + return flatTrace; + } + } +} diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java new file mode 100644 index 0000000000..607acf7954 --- /dev/null +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java @@ -0,0 +1,62 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; + +public class Result { + private String gasUsed; + private String output; + + public String getGasUsed() { + return gasUsed; + } + + public void setGasUsed(final String gasUsed) { + this.gasUsed = gasUsed; + } + + public String getOutput() { + return output; + } + + public void setOutput(final String output) { + this.output = output; + } + + public static Builder builder() { + return new Builder(); + } + + public static final class Builder { + private String gasUsed; + private String output; + + private Builder() {} + + public Builder gasUsed(final String gasUsed) { + this.gasUsed = gasUsed; + return this; + } + + public Builder output(final String output) { + this.output = output; + return this; + } + + public Result build() { + Result result = new Result(); + result.setGasUsed(gasUsed); + result.setOutput(output); + return result; + } + } +} From 9e2cde221059258f5407babecb833deea2c78ee2 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 27 Aug 2019 18:35:26 +0200 Subject: [PATCH 18/56] remove comments --- .../methods/TraceReplayBlockTransactions.java | 29 ------------------- 1 file changed, 29 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 724980694d..964e14f3b5 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -183,35 +183,6 @@ private void formatWithTraceOption( traceCounter.incrementAndGet(); } - private void generateActionNode(final ObjectNode traceNode, final TransactionTrace trace) {} - - /* - private void generateResultNode(final ObjectNode traceNode, final TransactionTrace trace) { - final ObjectNode traceResultNode = traceNode.putObject("result"); - traceResultNode.put("output", "0x"); - traceResultNode.put("gasUsed", Gas.of(trace.getGas()).toHexString()); - } - - private void generateActionNode(final ObjectNode traceNode, final TransactionTrace trace) { - final ObjectNode actionResultNode = traceNode.putObject("action"); - actionResultNode.put("callType", "call"); - actionResultNode.put("from", trace.getTransaction().getSender().toString()); - actionResultNode.put( - "gas", trace.getTransaction().getUpfrontGasCost().toStrictShortHexString()); - actionResultNode.put( - "input", - trace - .getTransaction() - .getData() - .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) - .toString()); - trace - .getTransaction() - .getTo() - .ifPresent(address -> actionResultNode.put("to", address.toString())); - actionResultNode.put("value", trace.getTransaction().getValue().toStrictShortHexString()); - }*/ - private Object emptyResult() { final ObjectMapper mapper = new ObjectMapper(); return mapper.createArrayNode(); From 49955f8231e718c9a100db355d266a1bd6bd1480 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 27 Aug 2019 18:42:01 +0200 Subject: [PATCH 19/56] add final modifier for method parameters --- .../ethereum/jsonrpc/internal/results/tracing/FlatTrace.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index 7e6da73fb6..70968baee7 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -82,12 +82,12 @@ public Builder result(final Result result) { return this; } - public Builder subtraces(int subtraces) { + public Builder subtraces(final int subtraces) { this.subtraces = subtraces; return this; } - public Builder traceAddress(Integer[] traceAddress) { + public Builder traceAddress(final Integer[] traceAddress) { this.traceAddress = traceAddress; return this; } From a6b2fe07bf3121a27a4faa9d46266bd1218fa139 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Wed, 28 Aug 2019 09:32:33 +0200 Subject: [PATCH 20/56] fix unit tests --- .../jsonrpc/trace/trace_replayBlockTransactions_0x0.json | 4 +--- .../jsonrpc/trace/trace_replayBlockTransactions_0x1.json | 6 ++---- .../trace/trace_replayBlockTransactions_earliest.json | 2 +- 3 files changed, 4 insertions(+), 8 deletions(-) diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json index 261a9af17b..e0831e7a4b 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json @@ -5,9 +5,7 @@ "params": [ "0x0", [ - "trace", - "vmTrace", - "stateDiff" + "trace" ] ], "id": 415 diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json index 1107db0cb5..cca4e59d86 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json @@ -5,16 +5,14 @@ "params": [ "0x1", [ - "trace", - "vmTrace", - "stateDiff" + "trace" ] ], "id": 415 }, "response": { "jsonrpc": "2.0", - "result": [], + "result": [{"trace":[]}], "id": 415 }, "statusCode": 200 diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json index 944b6409a0..adb967aace 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json @@ -5,7 +5,7 @@ "method": "trace_replayBlockTransactions", "params": [ "earliest", - ["trace","vmTrace","stateDiff"] + ["trace"] ] }, "response": { From 08473b3ff5852df32b1fba9b47d706c8b31c39bf Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Wed, 28 Aug 2019 09:37:50 +0200 Subject: [PATCH 21/56] remove useless log --- .../internal/methods/TraceReplayBlockTransactions.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 964e14f3b5..966f6add7a 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -154,7 +154,6 @@ private void formatWithTraceOption( if ("CALL".equals(traceFrame.getOpcode())) { final Bytes32[] stack = traceFrame.getStack().orElseThrow(); final Bytes32 contractCallAddress = stack[stack.length - 2]; - LOG.info("Call detected to contract: {}", contractCallAddress.toString()); final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); final Bytes32 contractCallInput = memory[0]; final FlatTrace.Builder subTraceBuilder = @@ -169,8 +168,7 @@ private void formatWithTraceOption( subTracesBuilders.add(subTraceBuilder.action(subTraceActionBuilder.build())); previousTraceBuilder.incSubTraces(); previousTraceBuilder = subTraceBuilder; - IntStream.of(subTracesCounter.incrementAndGet()) - .forEach(value -> currentTraceAddressVector.add(value)); + IntStream.of(subTracesCounter.incrementAndGet()).forEach(currentTraceAddressVector::add); } if ("RETURN".equals(traceFrame.getOpcode())) {} } From 158d29af9b9596e786c60f72d250bbbebf344951 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Wed, 28 Aug 2019 09:46:32 +0200 Subject: [PATCH 22/56] transform address from stack (Bytes32) to an Address --- .../internal/methods/TraceReplayBlockTransactions.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 966f6add7a..51ffad4fff 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -35,6 +35,7 @@ import tech.pegasys.pantheon.util.bytes.BytesValue; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; @@ -153,7 +154,7 @@ private void formatWithTraceOption( for (TraceFrame traceFrame : trace.getTraceFrames()) { if ("CALL".equals(traceFrame.getOpcode())) { final Bytes32[] stack = traceFrame.getStack().orElseThrow(); - final Bytes32 contractCallAddress = stack[stack.length - 2]; + final Address contractCallAddress = toAddress(stack[stack.length - 2]); final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); final Bytes32 contractCallInput = memory[0]; final FlatTrace.Builder subTraceBuilder = @@ -185,4 +186,10 @@ private Object emptyResult() { final ObjectMapper mapper = new ObjectMapper(); return mapper.createArrayNode(); } + + private static Address toAddress(final Bytes32 value) { + return Address.wrap( + BytesValue.of( + Arrays.copyOfRange(value.extractArray(), Bytes32.SIZE - Address.SIZE, Bytes32.SIZE))); + } } From e0387033bb01af64b0d4dfdb2eb62fdfcbac79e3 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Wed, 28 Aug 2019 11:45:38 +0200 Subject: [PATCH 23/56] trace_replayBlockTransactions new features - compute gas used for each sub trace - detect `RETURN` opcode - to get `ouput` value from `memory` - detect end of subtrace --- .../methods/TraceReplayBlockTransactions.java | 78 +++++++++++++++---- .../internal/results/tracing/Action.java | 11 +++ .../internal/results/tracing/FlatTrace.java | 54 ++++++++++++- .../internal/results/tracing/Result.java | 7 ++ 4 files changed, 135 insertions(+), 15 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 51ffad4fff..ffc624bbab 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -15,6 +15,8 @@ import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockHeader; +import tech.pegasys.pantheon.ethereum.core.Gas; +import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.debug.TraceFrame; import tech.pegasys.pantheon.ethereum.debug.TraceOptions; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod; @@ -34,8 +36,10 @@ import tech.pegasys.pantheon.util.bytes.Bytes32; import tech.pegasys.pantheon.util.bytes.BytesValue; +import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; +import java.util.Deque; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; @@ -114,6 +118,17 @@ private JsonNode formatTraces( final ArrayNode resultArrayNode = mapper.createArrayNode(); final ObjectNode resultNode = mapper.createObjectNode(); final AtomicInteger traceCounter = new AtomicInteger(0); + traces.stream() + .findFirst() + .ifPresent( + transactionTrace -> { + resultNode.put( + "transactionHash", transactionTrace.getTransaction().hash().getHexString()); + resultNode.put("output", transactionTrace.getResult().getOutput().toString()); + }); + resultNode.put("stateDiff", (String) null); + resultNode.put("vmTrace", (String) null); + if (traceTypes.contains(TraceTypeParameter.TraceType.TRACE)) { final ArrayNode tracesNode = resultNode.putArray("trace"); traces.forEach((trace) -> formatWithTraceOption(trace, traceCounter, mapper, tracesNode)); @@ -129,8 +144,8 @@ private void formatWithTraceOption( final AtomicInteger traceCounter, final ObjectMapper mapper, final ArrayNode tracesNode) { - final ObjectNode currentTraceNode = mapper.createObjectNode(); - final FlatTrace.Builder firstFlatTraceBuilder = FlatTrace.builder(); + final FlatTrace.Builder firstFlatTraceBuilder = + FlatTrace.builder().resultBuilder(Result.builder()); String lastContractAddress = trace.getTransaction().getTo().orElse(Address.ZERO).getHexString(); final Action.Builder firstFlatTraceActionBuilder = Action.builder() @@ -142,43 +157,78 @@ private void formatWithTraceOption( .getData() .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) .getHexString()) - .gas(trace.getTransaction().getUpfrontGasCost().toShortHexString()) + .gas( + trace + .getTransaction() + .getUpfrontGasCost() + .minus(Wei.of(trace.getResult().getGasRemaining())) + .toShortHexString()) .callType("call") .value(trace.getTransaction().getValue().toShortHexString()); - final Result.Builder firstFlatTraceResultBuilder = Result.builder(); - final List subTracesBuilders = new ArrayList<>(); + firstFlatTraceBuilder.actionBuilder(firstFlatTraceActionBuilder); + final Deque tracesContexts = new ArrayDeque<>(); + tracesContexts.addLast(new FlatTrace.Context(firstFlatTraceBuilder)); FlatTrace.Builder previousTraceBuilder = firstFlatTraceBuilder; final List currentTraceAddressVector = new ArrayList<>(); currentTraceAddressVector.add(traceCounter.get()); final AtomicInteger subTracesCounter = new AtomicInteger(0); + long cumulativeGasCost = 0; for (TraceFrame traceFrame : trace.getTraceFrames()) { + cumulativeGasCost += traceFrame.getGasCost().orElse(Gas.ZERO).toLong(); if ("CALL".equals(traceFrame.getOpcode())) { final Bytes32[] stack = traceFrame.getStack().orElseThrow(); final Address contractCallAddress = toAddress(stack[stack.length - 2]); final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); final Bytes32 contractCallInput = memory[0]; final FlatTrace.Builder subTraceBuilder = - FlatTrace.builder().traceAddress(currentTraceAddressVector.toArray(new Integer[0])); + FlatTrace.builder() + .traceAddress(currentTraceAddressVector.toArray(new Integer[0])) + .resultBuilder(Result.builder()); final Action.Builder subTraceActionBuilder = Action.builder() .from(lastContractAddress) .to(contractCallAddress.toString()) .input(contractCallInput.getHexString()) + .gas(traceFrame.getGasRemaining().toHexString()) .callType("call") .value(trace.getTransaction().getValue().toShortHexString()); - subTracesBuilders.add(subTraceBuilder.action(subTraceActionBuilder.build())); + tracesContexts.addLast( + new FlatTrace.Context(subTraceBuilder.action(subTraceActionBuilder.build()))); previousTraceBuilder.incSubTraces(); + previousTraceBuilder + .getResultBuilder() + .orElse(Result.builder()) + .gasUsed(Gas.of(cumulativeGasCost).toHexString()); previousTraceBuilder = subTraceBuilder; + // compute trace addresses IntStream.of(subTracesCounter.incrementAndGet()).forEach(currentTraceAddressVector::add); + cumulativeGasCost = 0; + } + if ("RETURN".equals(traceFrame.getOpcode())) { + final Deque polledContexts = new ArrayDeque<>(); + FlatTrace.Context ctx; + boolean continueToPollContexts = true; + // find last non returned trace + while (continueToPollContexts && (ctx = tracesContexts.pollLast()) != null) { + polledContexts.addFirst(ctx); + if (!ctx.isReturned()) { + final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); + ctx.getBuilder() + .getResultBuilder() + .orElse(Result.builder()) + .gasUsed(Gas.of(cumulativeGasCost).toHexString()) + .output(memory[0].toString()); + previousTraceBuilder = ctx.getBuilder(); + ctx.markAsReturned(); + continueToPollContexts = false; + } + } + // reinsert polled contexts add the end of the queue + polledContexts.forEach(tracesContexts::addLast); + cumulativeGasCost = 0; } - if ("RETURN".equals(traceFrame.getOpcode())) {} } - tracesNode.addPOJO( - firstFlatTraceBuilder - .action(firstFlatTraceActionBuilder.build()) - .result(firstFlatTraceResultBuilder.build()) - .build()); - subTracesBuilders.forEach(flatTraceBuilder -> tracesNode.addPOJO(flatTraceBuilder.build())); + tracesContexts.forEach(context -> tracesNode.addPOJO(context.getBuilder().build())); traceCounter.incrementAndGet(); } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index d2aaf095be..e7bd89dd9f 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -83,6 +83,17 @@ public static final class Builder { private Builder() {} + public static Builder of(final Action action) { + final Builder builder = new Builder(); + builder.callType = action.callType; + builder.from = action.from; + builder.gas = action.gas; + builder.input = action.input; + builder.to = action.to; + builder.value = action.value; + return builder; + } + public Builder callType(final String callType) { this.callType = callType; return this; diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index 70968baee7..cc4a26b70c 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -12,6 +12,8 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; +import java.util.Optional; + public class FlatTrace { private Action action; private Result result; @@ -63,9 +65,39 @@ public static Builder builder() { return new Builder(); } + public static class Context { + + private Builder builder; + private boolean returned; + + public Context(Builder builder) { + this.builder = builder; + this.returned = false; + } + + public Context(Builder builder, boolean returned) { + this.builder = builder; + this.returned = returned; + } + + public Builder getBuilder() { + return builder; + } + + public boolean isReturned() { + return returned; + } + + public void markAsReturned() { + this.returned = true; + } + } + public static final class Builder { private Action action; + private Optional actionBuilder = Optional.empty(); private Result result; + private Optional resultBuilder = Optional.empty(); private int subtraces; private Integer[] traceAddress = new Integer[0]; private String type = "call"; @@ -82,6 +114,16 @@ public Builder result(final Result result) { return this; } + public Builder resultBuilder(final Result.Builder resultBuilder) { + this.resultBuilder = Optional.ofNullable(resultBuilder); + return this; + } + + public Builder actionBuilder(final Action.Builder actionBuilder) { + this.actionBuilder = Optional.ofNullable(actionBuilder); + return this; + } + public Builder subtraces(final int subtraces) { this.subtraces = subtraces; return this; @@ -109,11 +151,21 @@ public Builder incSubTraces(final int n) { public FlatTrace build() { FlatTrace flatTrace = new FlatTrace(); flatTrace.setAction(action); - flatTrace.setResult(result); + flatTrace.setAction(actionBuilder.orElseGet(() -> Action.Builder.of(action)).build()); + + flatTrace.setResult(resultBuilder.orElseGet(() -> Result.Builder.of(result)).build()); flatTrace.setSubtraces(subtraces); flatTrace.setTraceAddress(traceAddress); flatTrace.setType(type); return flatTrace; } + + public Action getAction() { + return action; + } + + public Optional getResultBuilder() { + return resultBuilder; + } } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java index 607acf7954..d98d283392 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java @@ -52,6 +52,13 @@ public Builder output(final String output) { return this; } + public static Builder of(final Result result) { + final Builder builder = new Builder(); + builder.output = result.output; + builder.gasUsed = result.gasUsed; + return builder; + } + public Result build() { Result result = new Result(); result.setGasUsed(gasUsed); From 044805ad8db6a83cc06d45a88a2ec31fe1057447 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Wed, 28 Aug 2019 11:58:28 +0200 Subject: [PATCH 24/56] fix unit tests --- .../jsonrpc/trace/trace_replayBlockTransactions_0x1.json | 2 +- .../jsonrpc/trace/trace_replayBlockTransactions_pending.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json index cca4e59d86..ff444aaf97 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json @@ -12,7 +12,7 @@ }, "response": { "jsonrpc": "2.0", - "result": [{"trace":[]}], + "result": [{"stateDiff":null,"vmTrace":null,"trace":[]}], "id": 415 }, "statusCode": 200 diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json index f449262d83..779da39c53 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json @@ -5,13 +5,13 @@ "method": "trace_replayBlockTransactions", "params": [ "pending", - ["trace","vmTrace","stateDiff"] + ["trace"] ] }, "response": { "jsonrpc": "2.0", "id": 415, - "result": [{}] + "result": [{"transactionHash":"0x4af0ef28fbfcbdee7cc5925797c1b9030b3848c2f63f92737c3fe76b45582af5","output":"0xf000000000000000000000000000000000000000000000000000000000000002","stateDiff":null,"vmTrace":null,"trace":[{"action":{"callType":"call","from":"0xfe3b557e8fb62b89f4916b721be55ceb828dbd73","gas":"0xee00513e","input":"0x000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001","to":"0x0040000000000000000000000000000000000000","value":"0x0"},"result":{"gasUsed":"0x6","output":"0xf000000000000000000000000000000000000000000000000000000000000002"},"subtraces":1,"traceAddress":[],"type":"call"},{"action":{"callType":"call","from":"0x0040000000000000000000000000000000000000","gas":"0xffaa71","input":"0x0000000000000000000000000040000000000000000000000000000000000000","to":"0x0040000000000000000000000000000000000000","value":"0x0"},"result":{"gasUsed":"0x6","output":"0xf000000000000000000000000000000000000000000000000000000000000002"},"subtraces":1,"traceAddress":[0],"type":"call"},{"action":{"callType":"call","from":"0x0040000000000000000000000000000000000000","gas":"0xfba8e4","input":"0x0000000000000000000000000030000000000000000000000000000000000000","to":"0x0040000000000000000000000000000000000000","value":"0x0"},"result":{"gasUsed":"0x6","output":"0xf000000000000000000000000000000000000000000000000000000000000002"},"subtraces":1,"traceAddress":[0,1],"type":"call"},{"action":{"callType":"call","from":"0x0040000000000000000000000000000000000000","gas":"0xf7b763","input":"0xf000000000000000000000000000000000000000000000000000000000000001","to":"0x0030000000000000000000000000000000000000","value":"0x0"},"result":{"gasUsed":"0x1b","output":"0xf000000000000000000000000000000000000000000000000000000000000002"},"subtraces":0,"traceAddress":[0,1,2],"type":"call"}]}] }, "statusCode": 200 } \ No newline at end of file From 6300a184324eeaa2e62baea0a2151fb1fccfbc8c Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Wed, 28 Aug 2019 15:45:42 +0200 Subject: [PATCH 25/56] Update FlatTrace.java add final modifier --- .../jsonrpc/internal/results/tracing/FlatTrace.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index cc4a26b70c..05296b1b8c 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -70,12 +70,11 @@ public static class Context { private Builder builder; private boolean returned; - public Context(Builder builder) { - this.builder = builder; - this.returned = false; + public Context(final Builder builder) { + this(builder, false); } - public Context(Builder builder, boolean returned) { + Context(final Builder builder, final boolean returned) { this.builder = builder; this.returned = returned; } From da9196259412e9071d23cb05ed3a9e56a42e5daa Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Wed, 28 Aug 2019 16:03:28 +0200 Subject: [PATCH 26/56] pretty format JSON file --- ...trace_replayBlockTransactions_pending.json | 92 ++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json index 779da39c53..6738c1901c 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json @@ -5,13 +5,101 @@ "method": "trace_replayBlockTransactions", "params": [ "pending", - ["trace"] + [ + "trace" + ] ] }, "response": { "jsonrpc": "2.0", "id": 415, - "result": [{"transactionHash":"0x4af0ef28fbfcbdee7cc5925797c1b9030b3848c2f63f92737c3fe76b45582af5","output":"0xf000000000000000000000000000000000000000000000000000000000000002","stateDiff":null,"vmTrace":null,"trace":[{"action":{"callType":"call","from":"0xfe3b557e8fb62b89f4916b721be55ceb828dbd73","gas":"0xee00513e","input":"0x000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001","to":"0x0040000000000000000000000000000000000000","value":"0x0"},"result":{"gasUsed":"0x6","output":"0xf000000000000000000000000000000000000000000000000000000000000002"},"subtraces":1,"traceAddress":[],"type":"call"},{"action":{"callType":"call","from":"0x0040000000000000000000000000000000000000","gas":"0xffaa71","input":"0x0000000000000000000000000040000000000000000000000000000000000000","to":"0x0040000000000000000000000000000000000000","value":"0x0"},"result":{"gasUsed":"0x6","output":"0xf000000000000000000000000000000000000000000000000000000000000002"},"subtraces":1,"traceAddress":[0],"type":"call"},{"action":{"callType":"call","from":"0x0040000000000000000000000000000000000000","gas":"0xfba8e4","input":"0x0000000000000000000000000030000000000000000000000000000000000000","to":"0x0040000000000000000000000000000000000000","value":"0x0"},"result":{"gasUsed":"0x6","output":"0xf000000000000000000000000000000000000000000000000000000000000002"},"subtraces":1,"traceAddress":[0,1],"type":"call"},{"action":{"callType":"call","from":"0x0040000000000000000000000000000000000000","gas":"0xf7b763","input":"0xf000000000000000000000000000000000000000000000000000000000000001","to":"0x0030000000000000000000000000000000000000","value":"0x0"},"result":{"gasUsed":"0x1b","output":"0xf000000000000000000000000000000000000000000000000000000000000002"},"subtraces":0,"traceAddress":[0,1,2],"type":"call"}]}] + "result": [ + { + "transactionHash": "0x4af0ef28fbfcbdee7cc5925797c1b9030b3848c2f63f92737c3fe76b45582af5", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002", + "stateDiff": null, + "vmTrace": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xee00513e", + "input": "0x000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x6", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xffaa71", + "input": "0x0000000000000000000000000040000000000000000000000000000000000000", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x6", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [ + 0 + ], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xfba8e4", + "input": "0x0000000000000000000000000030000000000000000000000000000000000000", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x6", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [ + 0, + 1 + ], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xf7b763", + "input": "0xf000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0030000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x1b", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 0, + "traceAddress": [ + 0, + 1, + 2 + ], + "type": "call" + } + ] + } + ] }, "statusCode": 200 } \ No newline at end of file From 86510a26e16c6a9f35b16b2b2e8280329736de60 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Wed, 28 Aug 2019 17:00:29 +0200 Subject: [PATCH 27/56] handle smart contract deployments --- .../methods/TraceReplayBlockTransactions.java | 37 ++++++++++++++---- .../internal/results/tracing/Action.java | 24 +++++++++++- .../internal/results/tracing/FlatTrace.java | 2 +- .../internal/results/tracing/Result.java | 39 +++++++++++++++++++ 4 files changed, 92 insertions(+), 10 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index ffc624bbab..474dbda199 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -41,6 +41,7 @@ import java.util.Arrays; import java.util.Deque; import java.util.List; +import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.IntStream; @@ -144,27 +145,47 @@ private void formatWithTraceOption( final AtomicInteger traceCounter, final ObjectMapper mapper, final ArrayNode tracesNode) { + final FlatTrace.Builder firstFlatTraceBuilder = FlatTrace.builder().resultBuilder(Result.builder()); String lastContractAddress = trace.getTransaction().getTo().orElse(Address.ZERO).getHexString(); final Action.Builder firstFlatTraceActionBuilder = Action.builder() .from(trace.getTransaction().getSender().getHexString()) - .to(trace.getTransaction().getTo().orElse(Address.ZERO).toString()) - .input( - trace - .getTransaction() - .getData() - .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) - .getHexString()) .gas( trace .getTransaction() .getUpfrontGasCost() .minus(Wei.of(trace.getResult().getGasRemaining())) .toShortHexString()) - .callType("call") .value(trace.getTransaction().getValue().toShortHexString()); + + final Optional smartContractCode = + trace.getTransaction().getInit().isPresent() + ? Optional.of(trace.getResult().getOutput().toString()) + : Optional.empty(); + smartContractCode.ifPresent( + code -> firstFlatTraceBuilder.getResultBuilder().orElseThrow().code(code)); + // set init field if transaction is a smart contract deployment + trace + .getTransaction() + .getInit() + .ifPresent(init -> firstFlatTraceActionBuilder.init(init.getHexString())); + // set to, input and callType fields if not a smart contract + trace + .getTransaction() + .getTo() + .ifPresent( + to -> + firstFlatTraceActionBuilder + .to(to.toString()) + .callType("call") + .input( + trace + .getTransaction() + .getData() + .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) + .getHexString())); firstFlatTraceBuilder.actionBuilder(firstFlatTraceActionBuilder); final Deque tracesContexts = new ArrayDeque<>(); tracesContexts.addLast(new FlatTrace.Context(firstFlatTraceBuilder)); diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index e7bd89dd9f..6a95142379 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -12,6 +12,11 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(NON_NULL) public class Action { private String callType; @@ -19,6 +24,7 @@ public class Action { private String gas; private String input; private String to; + private String init; private String value; public String getCallType() { @@ -69,16 +75,25 @@ public void setValue(final String value) { this.value = value; } + public String getInit() { + return init; + } + + public void setInit(final String init) { + this.init = init; + } + public static Builder builder() { return new Builder(); } public static final class Builder { - private String callType = "call"; + private String callType; private String from; private String gas; private String input; private String to; + private String init; private String value; private Builder() {} @@ -90,6 +105,7 @@ public static Builder of(final Action action) { builder.gas = action.gas; builder.input = action.input; builder.to = action.to; + builder.init = action.init; builder.value = action.value; return builder; } @@ -119,6 +135,11 @@ public Builder to(final String to) { return this; } + public Builder init(final String init) { + this.init = init; + return this; + } + public Builder value(final String value) { this.value = value; return this; @@ -131,6 +152,7 @@ public Action build() { action.setGas(gas); action.setInput(input); action.setTo(to); + action.setInit(init); action.setValue(value); return action; } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index 05296b1b8c..200974409d 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -148,7 +148,7 @@ public Builder incSubTraces(final int n) { } public FlatTrace build() { - FlatTrace flatTrace = new FlatTrace(); + final FlatTrace flatTrace = new FlatTrace(); flatTrace.setAction(action); flatTrace.setAction(actionBuilder.orElseGet(() -> Action.Builder.of(action)).build()); diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java index d98d283392..af988daf3c 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java @@ -12,9 +12,16 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(NON_NULL) public class Result { private String gasUsed; private String output; + private String code; + private String address; public String getGasUsed() { return gasUsed; @@ -32,6 +39,22 @@ public void setOutput(final String output) { this.output = output; } + public String getCode() { + return code; + } + + public void setCode(final String code) { + this.code = code; + } + + public String getAddress() { + return address; + } + + public void setAddress(final String address) { + this.address = address; + } + public static Builder builder() { return new Builder(); } @@ -39,6 +62,8 @@ public static Builder builder() { public static final class Builder { private String gasUsed; private String output; + private String code; + private String address; private Builder() {} @@ -52,10 +77,22 @@ public Builder output(final String output) { return this; } + public Builder code(final String code) { + this.code = code; + return this; + } + + public Builder address(final String address) { + this.address = address; + return this; + } + public static Builder of(final Result result) { final Builder builder = new Builder(); builder.output = result.output; builder.gasUsed = result.gasUsed; + builder.code = result.code; + builder.address = result.address; return builder; } @@ -63,6 +100,8 @@ public Result build() { Result result = new Result(); result.setGasUsed(gasUsed); result.setOutput(output); + result.setCode(code); + result.setAddress(address); return result; } } From 082b2374733f4274217e79d5f1bef3c5dffa8a67 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Thu, 29 Aug 2019 10:29:16 +0200 Subject: [PATCH 28/56] handle smart contract deployment - set `code` field when contract creation transaction - set `address` field when contract creation transaction --- .../methods/TraceReplayBlockTransactions.java | 52 +++++++++++++------ 1 file changed, 37 insertions(+), 15 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 474dbda199..2f5b03980f 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -164,8 +164,15 @@ private void formatWithTraceOption( trace.getTransaction().getInit().isPresent() ? Optional.of(trace.getResult().getOutput().toString()) : Optional.empty(); - smartContractCode.ifPresent( - code -> firstFlatTraceBuilder.getResultBuilder().orElseThrow().code(code)); + final Optional smartContractAddress = + smartContractCode.isPresent() + ? Optional.of( + Address.contractAddress( + trace.getTransaction().getSender(), trace.getTransaction().getNonce()) + .getHexString()) + : Optional.empty(); + // set code field in result node + smartContractCode.ifPresent(firstFlatTraceBuilder.getResultBuilder().orElseThrow()::code); // set init field if transaction is a smart contract deployment trace .getTransaction() @@ -187,9 +194,12 @@ private void formatWithTraceOption( .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) .getHexString())); firstFlatTraceBuilder.actionBuilder(firstFlatTraceActionBuilder); + // declare a queue of trace contexts final Deque tracesContexts = new ArrayDeque<>(); + // add the first trace context to the queue of trace contexts tracesContexts.addLast(new FlatTrace.Context(firstFlatTraceBuilder)); - FlatTrace.Builder previousTraceBuilder = firstFlatTraceBuilder; + // declare the first trace context as the previous trace context + // FlatTrace.Context previousTraceContext = tracesContexts.peekLast(); final List currentTraceAddressVector = new ArrayList<>(); currentTraceAddressVector.add(traceCounter.get()); final AtomicInteger subTracesCounter = new AtomicInteger(0); @@ -213,14 +223,22 @@ private void formatWithTraceOption( .gas(traceFrame.getGasRemaining().toHexString()) .callType("call") .value(trace.getTransaction().getValue().toShortHexString()); + final long gasCost = cumulativeGasCost; + // retrieve the previous trace context + Optional.ofNullable(tracesContexts.peekLast()) + .ifPresent( + previousContext -> { + // increment sub traces counter of previous trace + previousContext.getBuilder().incSubTraces(); + // set gas cost of previous trace + previousContext + .getBuilder() + .getResultBuilder() + .orElse(Result.builder()) + .gasUsed(Gas.of(gasCost).toHexString()); + }); tracesContexts.addLast( new FlatTrace.Context(subTraceBuilder.action(subTraceActionBuilder.build()))); - previousTraceBuilder.incSubTraces(); - previousTraceBuilder - .getResultBuilder() - .orElse(Result.builder()) - .gasUsed(Gas.of(cumulativeGasCost).toHexString()); - previousTraceBuilder = subTraceBuilder; // compute trace addresses IntStream.of(subTracesCounter.incrementAndGet()).forEach(currentTraceAddressVector::add); cumulativeGasCost = 0; @@ -233,13 +251,17 @@ private void formatWithTraceOption( while (continueToPollContexts && (ctx = tracesContexts.pollLast()) != null) { polledContexts.addFirst(ctx); if (!ctx.isReturned()) { + final FlatTrace.Builder flatTraceBuilder = ctx.getBuilder(); + final Result.Builder resultBuilder = + flatTraceBuilder.getResultBuilder().orElse(Result.builder()); final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); - ctx.getBuilder() - .getResultBuilder() - .orElse(Result.builder()) - .gasUsed(Gas.of(cumulativeGasCost).toHexString()) - .output(memory[0].toString()); - previousTraceBuilder = ctx.getBuilder(); + resultBuilder.gasUsed(Gas.of(cumulativeGasCost).toHexString()); + smartContractAddress.ifPresentOrElse( + address -> { + resultBuilder.address(address); + flatTraceBuilder.type("create"); + }, + () -> resultBuilder.output(memory[0].toString())); ctx.markAsReturned(); continueToPollContexts = false; } From 4ca0c362b5b7bbc59150826f369b0274c0482663 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Thu, 29 Aug 2019 18:16:08 +0200 Subject: [PATCH 29/56] introduce FlatTraceGenerator --- .../methods/TraceReplayBlockTransactions.java | 172 ++--------------- .../internal/results/tracing/FlatTrace.java | 2 +- .../results/tracing/FlatTraceGenerator.java | 173 ++++++++++++++++++ .../internal/results/tracing/Trace.java | 15 ++ .../results/tracing/TraceFormatter.java | 24 +++ 5 files changed, 228 insertions(+), 158 deletions(-) create mode 100644 ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java create mode 100644 ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java create mode 100644 ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceFormatter.java diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 2f5b03980f..fcf0c3be3d 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -12,12 +12,8 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.methods; -import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Block; import tech.pegasys.pantheon.ethereum.core.BlockHeader; -import tech.pegasys.pantheon.ethereum.core.Gas; -import tech.pegasys.pantheon.ethereum.core.Wei; -import tech.pegasys.pantheon.ethereum.debug.TraceFrame; import tech.pegasys.pantheon.ethereum.debug.TraceOptions; import tech.pegasys.pantheon.ethereum.jsonrpc.RpcMethod; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.JsonRpcRequest; @@ -29,22 +25,13 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.BlockTracer; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; -import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.Action; -import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.FlatTrace; -import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.Result; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.FlatTraceGenerator; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.TraceFormatter; import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer; -import tech.pegasys.pantheon.util.bytes.Bytes32; -import tech.pegasys.pantheon.util.bytes.BytesValue; -import java.util.ArrayDeque; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Deque; import java.util.List; -import java.util.Optional; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; -import java.util.stream.IntStream; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -131,158 +118,29 @@ private JsonNode formatTraces( resultNode.put("vmTrace", (String) null); if (traceTypes.contains(TraceTypeParameter.TraceType.TRACE)) { - final ArrayNode tracesNode = resultNode.putArray("trace"); - traces.forEach((trace) -> formatWithTraceOption(trace, traceCounter, mapper, tracesNode)); + formatTraces( + resultNode.putArray("trace"), + traces, + FlatTraceGenerator::generateFromTransactionTrace, + traceCounter); } resultArrayNode.add(resultNode); return resultArrayNode; } - @SuppressWarnings("unused") - private void formatWithTraceOption( - final TransactionTrace trace, - final AtomicInteger traceCounter, - final ObjectMapper mapper, - final ArrayNode tracesNode) { - - final FlatTrace.Builder firstFlatTraceBuilder = - FlatTrace.builder().resultBuilder(Result.builder()); - String lastContractAddress = trace.getTransaction().getTo().orElse(Address.ZERO).getHexString(); - final Action.Builder firstFlatTraceActionBuilder = - Action.builder() - .from(trace.getTransaction().getSender().getHexString()) - .gas( - trace - .getTransaction() - .getUpfrontGasCost() - .minus(Wei.of(trace.getResult().getGasRemaining())) - .toShortHexString()) - .value(trace.getTransaction().getValue().toShortHexString()); - - final Optional smartContractCode = - trace.getTransaction().getInit().isPresent() - ? Optional.of(trace.getResult().getOutput().toString()) - : Optional.empty(); - final Optional smartContractAddress = - smartContractCode.isPresent() - ? Optional.of( - Address.contractAddress( - trace.getTransaction().getSender(), trace.getTransaction().getNonce()) - .getHexString()) - : Optional.empty(); - // set code field in result node - smartContractCode.ifPresent(firstFlatTraceBuilder.getResultBuilder().orElseThrow()::code); - // set init field if transaction is a smart contract deployment - trace - .getTransaction() - .getInit() - .ifPresent(init -> firstFlatTraceActionBuilder.init(init.getHexString())); - // set to, input and callType fields if not a smart contract - trace - .getTransaction() - .getTo() - .ifPresent( - to -> - firstFlatTraceActionBuilder - .to(to.toString()) - .callType("call") - .input( - trace - .getTransaction() - .getData() - .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) - .getHexString())); - firstFlatTraceBuilder.actionBuilder(firstFlatTraceActionBuilder); - // declare a queue of trace contexts - final Deque tracesContexts = new ArrayDeque<>(); - // add the first trace context to the queue of trace contexts - tracesContexts.addLast(new FlatTrace.Context(firstFlatTraceBuilder)); - // declare the first trace context as the previous trace context - // FlatTrace.Context previousTraceContext = tracesContexts.peekLast(); - final List currentTraceAddressVector = new ArrayList<>(); - currentTraceAddressVector.add(traceCounter.get()); - final AtomicInteger subTracesCounter = new AtomicInteger(0); - long cumulativeGasCost = 0; - for (TraceFrame traceFrame : trace.getTraceFrames()) { - cumulativeGasCost += traceFrame.getGasCost().orElse(Gas.ZERO).toLong(); - if ("CALL".equals(traceFrame.getOpcode())) { - final Bytes32[] stack = traceFrame.getStack().orElseThrow(); - final Address contractCallAddress = toAddress(stack[stack.length - 2]); - final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); - final Bytes32 contractCallInput = memory[0]; - final FlatTrace.Builder subTraceBuilder = - FlatTrace.builder() - .traceAddress(currentTraceAddressVector.toArray(new Integer[0])) - .resultBuilder(Result.builder()); - final Action.Builder subTraceActionBuilder = - Action.builder() - .from(lastContractAddress) - .to(contractCallAddress.toString()) - .input(contractCallInput.getHexString()) - .gas(traceFrame.getGasRemaining().toHexString()) - .callType("call") - .value(trace.getTransaction().getValue().toShortHexString()); - final long gasCost = cumulativeGasCost; - // retrieve the previous trace context - Optional.ofNullable(tracesContexts.peekLast()) - .ifPresent( - previousContext -> { - // increment sub traces counter of previous trace - previousContext.getBuilder().incSubTraces(); - // set gas cost of previous trace - previousContext - .getBuilder() - .getResultBuilder() - .orElse(Result.builder()) - .gasUsed(Gas.of(gasCost).toHexString()); - }); - tracesContexts.addLast( - new FlatTrace.Context(subTraceBuilder.action(subTraceActionBuilder.build()))); - // compute trace addresses - IntStream.of(subTracesCounter.incrementAndGet()).forEach(currentTraceAddressVector::add); - cumulativeGasCost = 0; - } - if ("RETURN".equals(traceFrame.getOpcode())) { - final Deque polledContexts = new ArrayDeque<>(); - FlatTrace.Context ctx; - boolean continueToPollContexts = true; - // find last non returned trace - while (continueToPollContexts && (ctx = tracesContexts.pollLast()) != null) { - polledContexts.addFirst(ctx); - if (!ctx.isReturned()) { - final FlatTrace.Builder flatTraceBuilder = ctx.getBuilder(); - final Result.Builder resultBuilder = - flatTraceBuilder.getResultBuilder().orElse(Result.builder()); - final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); - resultBuilder.gasUsed(Gas.of(cumulativeGasCost).toHexString()); - smartContractAddress.ifPresentOrElse( - address -> { - resultBuilder.address(address); - flatTraceBuilder.type("create"); - }, - () -> resultBuilder.output(memory[0].toString())); - ctx.markAsReturned(); - continueToPollContexts = false; - } - } - // reinsert polled contexts add the end of the queue - polledContexts.forEach(tracesContexts::addLast); - cumulativeGasCost = 0; - } - } - tracesContexts.forEach(context -> tracesNode.addPOJO(context.getBuilder().build())); - traceCounter.incrementAndGet(); + private void formatTraces( + final ArrayNode node, + final List traces, + final TraceFormatter formatter, + final AtomicInteger traceCounter) { + traces.forEach( + (transactionTrace) -> + formatter.format(transactionTrace, traceCounter).forEachOrdered(node::addPOJO)); } private Object emptyResult() { final ObjectMapper mapper = new ObjectMapper(); return mapper.createArrayNode(); } - - private static Address toAddress(final Bytes32 value) { - return Address.wrap( - BytesValue.of( - Arrays.copyOfRange(value.extractArray(), Bytes32.SIZE - Address.SIZE, Bytes32.SIZE))); - } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index 200974409d..11f51b8495 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -14,7 +14,7 @@ import java.util.Optional; -public class FlatTrace { +public class FlatTrace implements Trace { private Action action; private Result result; private int subtraces; diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java new file mode 100644 index 0000000000..50c880a9d3 --- /dev/null +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -0,0 +1,173 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; + +import tech.pegasys.pantheon.ethereum.core.Address; +import tech.pegasys.pantheon.ethereum.core.Gas; +import tech.pegasys.pantheon.ethereum.core.Wei; +import tech.pegasys.pantheon.ethereum.debug.TraceFrame; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; +import tech.pegasys.pantheon.util.bytes.Bytes32; +import tech.pegasys.pantheon.util.bytes.BytesValue; + +import java.util.ArrayDeque; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Deque; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public class FlatTraceGenerator { + + public static Stream generateFromTransactionTrace( + final TransactionTrace trace, final AtomicInteger traceCounter) { + final FlatTrace.Builder firstFlatTraceBuilder = + FlatTrace.builder().resultBuilder(Result.builder()); + String lastContractAddress = trace.getTransaction().getTo().orElse(Address.ZERO).getHexString(); + final Action.Builder firstFlatTraceActionBuilder = + Action.builder() + .from(trace.getTransaction().getSender().getHexString()) + .gas( + trace + .getTransaction() + .getUpfrontGasCost() + .minus(Wei.of(trace.getResult().getGasRemaining())) + .toShortHexString()) + .value(trace.getTransaction().getValue().toShortHexString()); + + final Optional smartContractCode = + trace.getTransaction().getInit().isPresent() + ? Optional.of(trace.getResult().getOutput().toString()) + : Optional.empty(); + final Optional smartContractAddress = + smartContractCode.isPresent() + ? Optional.of( + Address.contractAddress( + trace.getTransaction().getSender(), trace.getTransaction().getNonce()) + .getHexString()) + : Optional.empty(); + // set code field in result node + smartContractCode.ifPresent(firstFlatTraceBuilder.getResultBuilder().orElseThrow()::code); + // set init field if transaction is a smart contract deployment + trace + .getTransaction() + .getInit() + .ifPresent(init -> firstFlatTraceActionBuilder.init(init.getHexString())); + // set to, input and callType fields if not a smart contract + trace + .getTransaction() + .getTo() + .ifPresent( + to -> + firstFlatTraceActionBuilder + .to(to.toString()) + .callType("call") + .input( + trace + .getTransaction() + .getData() + .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) + .getHexString())); + firstFlatTraceBuilder.actionBuilder(firstFlatTraceActionBuilder); + // declare a queue of trace contexts + final Deque tracesContexts = new ArrayDeque<>(); + // add the first trace context to the queue of trace contexts + tracesContexts.addLast(new FlatTrace.Context(firstFlatTraceBuilder)); + // declare the first trace context as the previous trace context + // FlatTrace.Context previousTraceContext = tracesContexts.peekLast(); + final List currentTraceAddressVector = new ArrayList<>(); + currentTraceAddressVector.add(traceCounter.get()); + final AtomicInteger subTracesCounter = new AtomicInteger(0); + long cumulativeGasCost = 0; + for (TraceFrame traceFrame : trace.getTraceFrames()) { + cumulativeGasCost += traceFrame.getGasCost().orElse(Gas.ZERO).toLong(); + if ("CALL".equals(traceFrame.getOpcode())) { + final Bytes32[] stack = traceFrame.getStack().orElseThrow(); + final Address contractCallAddress = toAddress(stack[stack.length - 2]); + final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); + final Bytes32 contractCallInput = memory[0]; + final FlatTrace.Builder subTraceBuilder = + FlatTrace.builder() + .traceAddress(currentTraceAddressVector.toArray(new Integer[0])) + .resultBuilder(Result.builder()); + final Action.Builder subTraceActionBuilder = + Action.builder() + .from(lastContractAddress) + .to(contractCallAddress.toString()) + .input(contractCallInput.getHexString()) + .gas(traceFrame.getGasRemaining().toHexString()) + .callType("call") + .value(trace.getTransaction().getValue().toShortHexString()); + final long gasCost = cumulativeGasCost; + // retrieve the previous trace context + Optional.ofNullable(tracesContexts.peekLast()) + .ifPresent( + previousContext -> { + // increment sub traces counter of previous trace + previousContext.getBuilder().incSubTraces(); + // set gas cost of previous trace + previousContext + .getBuilder() + .getResultBuilder() + .orElse(Result.builder()) + .gasUsed(Gas.of(gasCost).toHexString()); + }); + tracesContexts.addLast( + new FlatTrace.Context(subTraceBuilder.action(subTraceActionBuilder.build()))); + // compute trace addresses + IntStream.of(subTracesCounter.incrementAndGet()).forEach(currentTraceAddressVector::add); + cumulativeGasCost = 0; + } + if ("RETURN".equals(traceFrame.getOpcode())) { + final Deque polledContexts = new ArrayDeque<>(); + FlatTrace.Context ctx; + boolean continueToPollContexts = true; + // find last non returned trace + while (continueToPollContexts && (ctx = tracesContexts.pollLast()) != null) { + polledContexts.addFirst(ctx); + if (!ctx.isReturned()) { + final FlatTrace.Builder flatTraceBuilder = ctx.getBuilder(); + final Result.Builder resultBuilder = + flatTraceBuilder.getResultBuilder().orElse(Result.builder()); + final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); + resultBuilder.gasUsed(Gas.of(cumulativeGasCost).toHexString()); + smartContractAddress.ifPresentOrElse( + address -> { + resultBuilder.address(address); + flatTraceBuilder.type("create"); + }, + () -> resultBuilder.output(memory[0].toString())); + ctx.markAsReturned(); + continueToPollContexts = false; + } + } + // reinsert polled contexts add the end of the queue + polledContexts.forEach(tracesContexts::addLast); + cumulativeGasCost = 0; + } + } + final List flatTraces = new ArrayList<>(); + tracesContexts.forEach(context -> flatTraces.add(context.getBuilder().build())); + traceCounter.incrementAndGet(); + return flatTraces.stream(); + } + + private static Address toAddress(final Bytes32 value) { + return Address.wrap( + BytesValue.of( + Arrays.copyOfRange(value.extractArray(), Bytes32.SIZE - Address.SIZE, Bytes32.SIZE))); + } +} diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java new file mode 100644 index 0000000000..fe6a004ed2 --- /dev/null +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java @@ -0,0 +1,15 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; + +public interface Trace {} diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceFormatter.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceFormatter.java new file mode 100644 index 0000000000..31118ff968 --- /dev/null +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceFormatter.java @@ -0,0 +1,24 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; + +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; + +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Stream; + +@FunctionalInterface +public interface TraceFormatter { + + Stream format(TransactionTrace transactionTrace, AtomicInteger traceCounter); +} From 1f9b60bbcffd42ce90d3c8145acffb248693d36a Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Thu, 29 Aug 2019 19:19:54 +0200 Subject: [PATCH 30/56] refactoring --- .../methods/TraceReplayBlockTransactions.java | 12 +- .../internal/results/tracing/Action.java | 32 +++ .../internal/results/tracing/FlatTrace.java | 13 ++ .../results/tracing/FlatTraceGenerator.java | 212 ++++++++++-------- 4 files changed, 173 insertions(+), 96 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index fcf0c3be3d..9b2dec6ecb 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -26,6 +26,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.FlatTraceGenerator; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.Trace; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.TraceFormatter; import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer; @@ -119,7 +120,7 @@ private JsonNode formatTraces( if (traceTypes.contains(TraceTypeParameter.TraceType.TRACE)) { formatTraces( - resultNode.putArray("trace"), + resultNode.putArray("trace")::addPOJO, traces, FlatTraceGenerator::generateFromTransactionTrace, traceCounter); @@ -130,13 +131,18 @@ private JsonNode formatTraces( } private void formatTraces( - final ArrayNode node, + final TraceResultWriter writer, final List traces, final TraceFormatter formatter, final AtomicInteger traceCounter) { traces.forEach( (transactionTrace) -> - formatter.format(transactionTrace, traceCounter).forEachOrdered(node::addPOJO)); + formatter.format(transactionTrace, traceCounter).forEachOrdered(writer::writeResult)); + } + + @FunctionalInterface + public interface TraceResultWriter { + void writeResult(Trace trace); } private Object emptyResult() { diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index 6a95142379..f86ade389e 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -14,6 +14,12 @@ import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; +import tech.pegasys.pantheon.ethereum.core.Address; +import tech.pegasys.pantheon.ethereum.core.Transaction; +import tech.pegasys.pantheon.ethereum.core.Wei; +import tech.pegasys.pantheon.ethereum.debug.TraceFrame; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; + import com.fasterxml.jackson.annotation.JsonInclude; @JsonInclude(NON_NULL) @@ -87,6 +93,20 @@ public static Builder builder() { return new Builder(); } + public static Builder createCallAction( + final Transaction transaction, + final String lastContractAddress, + final Address contractCallAddress, + TraceFrame traceFrame) { + return builder() + .from(lastContractAddress) + .to(contractCallAddress.toString()) + .input(traceFrame.getMemory().orElseThrow()[0].getHexString()) + .gas(traceFrame.getGasRemaining().toHexString()) + .callType("call") + .value(transaction.getValue().toShortHexString()); + } + public static final class Builder { private String callType; private String from; @@ -110,6 +130,18 @@ public static Builder of(final Action action) { return builder; } + public static Builder from(final TransactionTrace trace) { + return new Builder() + .from(trace.getTransaction().getSender().getHexString()) + .gas( + trace + .getTransaction() + .getUpfrontGasCost() + .minus(Wei.of(trace.getResult().getGasRemaining())) + .toShortHexString()) + .value(trace.getTransaction().getValue().toShortHexString()); + } + public Builder callType(final String callType) { this.callType = callType; return this; diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index 11f51b8495..ae655aeb15 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -12,6 +12,8 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; + import java.util.Optional; public class FlatTrace implements Trace { @@ -21,6 +23,12 @@ public class FlatTrace implements Trace { private Integer[] traceAddress = new Integer[0]; private String type; + public static Builder freshBuilder(final TransactionTrace transactionTrace) { + return FlatTrace.builder() + .resultBuilder(Result.builder()) + .actionBuilder(Action.Builder.from(transactionTrace)); + } + public Action getAction() { return action; } @@ -94,6 +102,7 @@ public void markAsReturned() { public static final class Builder { private Action action; + private Optional actionBuilder = Optional.empty(); private Result result; private Optional resultBuilder = Optional.empty(); @@ -166,5 +175,9 @@ public Action getAction() { public Optional getResultBuilder() { return resultBuilder; } + + public Optional getActionBuilder() { + return actionBuilder; + } } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index 50c880a9d3..cbea6953d1 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -14,7 +14,7 @@ import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Gas; -import tech.pegasys.pantheon.ethereum.core.Wei; +import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.debug.TraceFrame; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; import tech.pegasys.pantheon.util.bytes.Bytes32; @@ -27,136 +27,91 @@ import java.util.List; import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; +import java.util.concurrent.atomic.AtomicLong; import java.util.stream.IntStream; import java.util.stream.Stream; public class FlatTraceGenerator { + /** + * Generates a stream of {@link Trace} from the passed {@link TransactionTrace} data. + * + * @param transactionTrace the {@link TransactionTrace} to use + * @param traceCounter the current trace counter value + * @return a stream of generated traces {@link Trace} + */ public static Stream generateFromTransactionTrace( - final TransactionTrace trace, final AtomicInteger traceCounter) { - final FlatTrace.Builder firstFlatTraceBuilder = - FlatTrace.builder().resultBuilder(Result.builder()); - String lastContractAddress = trace.getTransaction().getTo().orElse(Address.ZERO).getHexString(); - final Action.Builder firstFlatTraceActionBuilder = - Action.builder() - .from(trace.getTransaction().getSender().getHexString()) - .gas( - trace - .getTransaction() - .getUpfrontGasCost() - .minus(Wei.of(trace.getResult().getGasRemaining())) - .toShortHexString()) - .value(trace.getTransaction().getValue().toShortHexString()); + final TransactionTrace transactionTrace, final AtomicInteger traceCounter) { + final FlatTrace.Builder firstFlatTraceBuilder = FlatTrace.freshBuilder(transactionTrace); + final String lastContractAddress = + transactionTrace.getTransaction().getTo().orElse(Address.ZERO).getHexString(); final Optional smartContractCode = - trace.getTransaction().getInit().isPresent() - ? Optional.of(trace.getResult().getOutput().toString()) + transactionTrace.getTransaction().getInit().isPresent() + ? Optional.of(transactionTrace.getResult().getOutput().toString()) : Optional.empty(); final Optional smartContractAddress = smartContractCode.isPresent() ? Optional.of( Address.contractAddress( - trace.getTransaction().getSender(), trace.getTransaction().getNonce()) + transactionTrace.getTransaction().getSender(), + transactionTrace.getTransaction().getNonce()) .getHexString()) : Optional.empty(); // set code field in result node smartContractCode.ifPresent(firstFlatTraceBuilder.getResultBuilder().orElseThrow()::code); // set init field if transaction is a smart contract deployment - trace + transactionTrace .getTransaction() .getInit() - .ifPresent(init -> firstFlatTraceActionBuilder.init(init.getHexString())); + .ifPresent( + init -> + firstFlatTraceBuilder.getActionBuilder().orElseThrow().init(init.getHexString())); // set to, input and callType fields if not a smart contract - trace + transactionTrace .getTransaction() .getTo() .ifPresent( to -> - firstFlatTraceActionBuilder + firstFlatTraceBuilder + .getActionBuilder() + .orElseThrow() .to(to.toString()) .callType("call") .input( - trace + transactionTrace .getTransaction() .getData() - .orElse(trace.getTransaction().getInit().orElse(BytesValue.EMPTY)) + .orElse( + transactionTrace + .getTransaction() + .getInit() + .orElse(BytesValue.EMPTY)) .getHexString())); - firstFlatTraceBuilder.actionBuilder(firstFlatTraceActionBuilder); - // declare a queue of trace contexts + // declare a queue of transactionTrace contexts final Deque tracesContexts = new ArrayDeque<>(); - // add the first trace context to the queue of trace contexts + // add the first transactionTrace context to the queue of transactionTrace contexts tracesContexts.addLast(new FlatTrace.Context(firstFlatTraceBuilder)); - // declare the first trace context as the previous trace context + // declare the first transactionTrace context as the previous transactionTrace context // FlatTrace.Context previousTraceContext = tracesContexts.peekLast(); - final List currentTraceAddressVector = new ArrayList<>(); - currentTraceAddressVector.add(traceCounter.get()); + final List addressVector = new ArrayList<>(); + addressVector.add(traceCounter.get()); final AtomicInteger subTracesCounter = new AtomicInteger(0); - long cumulativeGasCost = 0; - for (TraceFrame traceFrame : trace.getTraceFrames()) { - cumulativeGasCost += traceFrame.getGasCost().orElse(Gas.ZERO).toLong(); + final AtomicLong cumulativeGasCost = new AtomicLong(0); + for (TraceFrame traceFrame : transactionTrace.getTraceFrames()) { + cumulativeGasCost.addAndGet(traceFrame.getGasCost().orElse(Gas.ZERO).toLong()); if ("CALL".equals(traceFrame.getOpcode())) { - final Bytes32[] stack = traceFrame.getStack().orElseThrow(); - final Address contractCallAddress = toAddress(stack[stack.length - 2]); - final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); - final Bytes32 contractCallInput = memory[0]; - final FlatTrace.Builder subTraceBuilder = - FlatTrace.builder() - .traceAddress(currentTraceAddressVector.toArray(new Integer[0])) - .resultBuilder(Result.builder()); - final Action.Builder subTraceActionBuilder = - Action.builder() - .from(lastContractAddress) - .to(contractCallAddress.toString()) - .input(contractCallInput.getHexString()) - .gas(traceFrame.getGasRemaining().toHexString()) - .callType("call") - .value(trace.getTransaction().getValue().toShortHexString()); - final long gasCost = cumulativeGasCost; - // retrieve the previous trace context - Optional.ofNullable(tracesContexts.peekLast()) - .ifPresent( - previousContext -> { - // increment sub traces counter of previous trace - previousContext.getBuilder().incSubTraces(); - // set gas cost of previous trace - previousContext - .getBuilder() - .getResultBuilder() - .orElse(Result.builder()) - .gasUsed(Gas.of(gasCost).toHexString()); - }); - tracesContexts.addLast( - new FlatTrace.Context(subTraceBuilder.action(subTraceActionBuilder.build()))); - // compute trace addresses - IntStream.of(subTracesCounter.incrementAndGet()).forEach(currentTraceAddressVector::add); - cumulativeGasCost = 0; + handleCall( + transactionTrace.getTransaction(), + traceFrame, + lastContractAddress, + cumulativeGasCost, + addressVector, + tracesContexts, + subTracesCounter); } if ("RETURN".equals(traceFrame.getOpcode())) { - final Deque polledContexts = new ArrayDeque<>(); - FlatTrace.Context ctx; - boolean continueToPollContexts = true; - // find last non returned trace - while (continueToPollContexts && (ctx = tracesContexts.pollLast()) != null) { - polledContexts.addFirst(ctx); - if (!ctx.isReturned()) { - final FlatTrace.Builder flatTraceBuilder = ctx.getBuilder(); - final Result.Builder resultBuilder = - flatTraceBuilder.getResultBuilder().orElse(Result.builder()); - final Bytes32[] memory = traceFrame.getMemory().orElseThrow(); - resultBuilder.gasUsed(Gas.of(cumulativeGasCost).toHexString()); - smartContractAddress.ifPresentOrElse( - address -> { - resultBuilder.address(address); - flatTraceBuilder.type("create"); - }, - () -> resultBuilder.output(memory[0].toString())); - ctx.markAsReturned(); - continueToPollContexts = false; - } - } - // reinsert polled contexts add the end of the queue - polledContexts.forEach(tracesContexts::addLast); - cumulativeGasCost = 0; + handleReturn(traceFrame, smartContractAddress, cumulativeGasCost, tracesContexts); } } final List flatTraces = new ArrayList<>(); @@ -165,6 +120,77 @@ public static Stream generateFromTransactionTrace( return flatTraces.stream(); } + private static void handleCall( + final Transaction transaction, + final TraceFrame traceFrame, + final String lastContractAddress, + final AtomicLong cumulativeGasCost, + final List addressVector, + final Deque tracesContexts, + final AtomicInteger subTracesCounter) { + final Bytes32[] stack = traceFrame.getStack().orElseThrow(); + final Address contractCallAddress = toAddress(stack[stack.length - 2]); + final FlatTrace.Builder subTraceBuilder = + FlatTrace.builder() + .traceAddress(addressVector.toArray(new Integer[0])) + .resultBuilder(Result.builder()); + final Action.Builder subTraceActionBuilder = + Action.createCallAction(transaction, lastContractAddress, contractCallAddress, traceFrame); + + final long gasCost = cumulativeGasCost.longValue(); + // retrieve the previous transactionTrace context + Optional.ofNullable(tracesContexts.peekLast()) + .ifPresent( + previousContext -> { + // increment sub traces counter of previous transactionTrace + previousContext.getBuilder().incSubTraces(); + // set gas cost of previous transactionTrace + previousContext + .getBuilder() + .getResultBuilder() + .orElse(Result.builder()) + .gasUsed(Gas.of(gasCost).toHexString()); + }); + tracesContexts.addLast( + new FlatTrace.Context(subTraceBuilder.action(subTraceActionBuilder.build()))); + // compute transactionTrace addresses + IntStream.of(subTracesCounter.incrementAndGet()).forEach(addressVector::add); + cumulativeGasCost.set(0); + } + + private static void handleReturn( + final TraceFrame traceFrame, + final Optional smartContractAddress, + final AtomicLong cumulativeGasCost, + final Deque tracesContexts) { + final Deque polledContexts = new ArrayDeque<>(); + FlatTrace.Context ctx; + boolean continueToPollContexts = true; + // find last non returned transactionTrace + while (continueToPollContexts && (ctx = tracesContexts.pollLast()) != null) { + polledContexts.addFirst(ctx); + if (!ctx.isReturned()) { + final FlatTrace.Builder flatTraceBuilder = ctx.getBuilder(); + final Result.Builder resultBuilder = + flatTraceBuilder.getResultBuilder().orElse(Result.builder()); + resultBuilder.gasUsed(Gas.of(cumulativeGasCost.longValue()).toHexString()); + // set address and type to create if smart contract deployment + smartContractAddress.ifPresentOrElse( + address -> { + resultBuilder.address(address); + flatTraceBuilder.type("create"); + }, + // set output otherwise + () -> resultBuilder.output(traceFrame.getMemory().orElseThrow()[0].toString())); + ctx.markAsReturned(); + continueToPollContexts = false; + } + } + // reinsert polled contexts add the end of the queue + polledContexts.forEach(tracesContexts::addLast); + cumulativeGasCost.set(0); + } + private static Address toAddress(final Bytes32 value) { return Address.wrap( BytesValue.of( From fe1f8914f977684e89ceba9c05ad013180f97c64 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Fri, 30 Aug 2019 08:58:44 +0200 Subject: [PATCH 31/56] spotless apply --- .../ethereum/jsonrpc/internal/results/tracing/Action.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index f86ade389e..1c5ed780eb 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -97,7 +97,7 @@ public static Builder createCallAction( final Transaction transaction, final String lastContractAddress, final Address contractCallAddress, - TraceFrame traceFrame) { + final TraceFrame traceFrame) { return builder() .from(lastContractAddress) .to(contractCallAddress.toString()) From cbddee0c8793fdce2f73dccd9bc04f2cce313b53 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Fri, 30 Aug 2019 16:32:32 +0200 Subject: [PATCH 32/56] update tests to compare Json node tree independently of the order - added generated test cases - use jackson `ObjectMapper` to compare the actual result to the expected one - `assertThat(mapper.readTree(actualResult)).isEqualTo(mapper.readTree(expectedResult));` --- .../methods/TraceReplayBlockTransactions.java | 9 +- .../internal/results/tracing/Action.java | 7 +- .../internal/results/tracing/Result.java | 5 +- .../internal/results/tracing/Trace.java | 7 +- .../AbstractJsonRpcHttpBySpecTest.java | 3 +- .../trace_replayBlockTransactions_0x1.json | 2 +- .../trace_replayBlockTransactions_0x2.json | 45 ++++++++ .../trace_replayBlockTransactions_0x3.json | 44 ++++++++ .../trace_replayBlockTransactions_0x4.json | 45 ++++++++ .../trace_replayBlockTransactions_0x5.json | 45 ++++++++ .../trace_replayBlockTransactions_0x6.json | 58 ++++++++++ .../trace_replayBlockTransactions_0x7.json | 45 ++++++++ .../trace_replayBlockTransactions_0x8.json | 64 +++++++++++ .../trace_replayBlockTransactions_0x9.json | 105 ++++++++++++++++++ 14 files changed, 466 insertions(+), 18 deletions(-) create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x3.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 9b2dec6ecb..fd1a767683 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -131,18 +131,13 @@ private JsonNode formatTraces( } private void formatTraces( - final TraceResultWriter writer, + final Trace.ResultWriter writer, final List traces, final TraceFormatter formatter, final AtomicInteger traceCounter) { traces.forEach( (transactionTrace) -> - formatter.format(transactionTrace, traceCounter).forEachOrdered(writer::writeResult)); - } - - @FunctionalInterface - public interface TraceResultWriter { - void writeResult(Trace trace); + formatter.format(transactionTrace, traceCounter).forEachOrdered(writer::write)); } private Object emptyResult() { diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index 1c5ed780eb..f3ea6de74e 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -133,12 +133,7 @@ public static Builder of(final Action action) { public static Builder from(final TransactionTrace trace) { return new Builder() .from(trace.getTransaction().getSender().getHexString()) - .gas( - trace - .getTransaction() - .getUpfrontGasCost() - .minus(Wei.of(trace.getResult().getGasRemaining())) - .toShortHexString()) + .gas(Wei.of(trace.getResult().getGasRemaining()).toStrictShortHexString()) .value(trace.getTransaction().getValue().toShortHexString()); } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java index af988daf3c..c9f3c1a1fa 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java @@ -60,8 +60,8 @@ public static Builder builder() { } public static final class Builder { - private String gasUsed; - private String output; + private String gasUsed = "0x0"; + private String output = "0x"; private String code; private String address; @@ -79,6 +79,7 @@ public Builder output(final String output) { public Builder code(final String code) { this.code = code; + this.output = null; return this; } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java index fe6a004ed2..45c26659f1 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java @@ -12,4 +12,9 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; -public interface Trace {} +public interface Trace { + @FunctionalInterface + interface ResultWriter { + void write(Trace trace); + } +} diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java index 9e8055f0d1..0d412c0b23 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java @@ -134,7 +134,8 @@ private void jsonRPCCall(final URL specFile) throws IOException { assertThat(responseBody.has("result")).isTrue(); final String expectedResult = expectedResponse.get("result").toString(); final String actualResult = responseBody.get("result").toString(); - assertThat(actualResult).isEqualToIgnoringWhitespace(expectedResult); + final ObjectMapper mapper = new ObjectMapper(); + assertThat(mapper.readTree(actualResult)).isEqualTo(mapper.readTree(expectedResult)); } // Check error diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json index ff444aaf97..ad9eb5fd51 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json @@ -12,7 +12,7 @@ }, "response": { "jsonrpc": "2.0", - "result": [{"stateDiff":null,"vmTrace":null,"trace":[]}], + "result": [], "id": 415 }, "statusCode": 200 diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json new file mode 100644 index 0000000000..702ffd6e24 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json @@ -0,0 +1,45 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x2", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0x", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0x627306090abab3a6e1400e9345bc60c78a8bef57", + "gas": "0xffadea", + "input": "0x", + "to": "0x0000000000000000000000000000000000000999", + "value": "0x1" + }, + "result": { + "gasUsed": "0x0", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ], + "transactionHash": "0x28fa8042c7b5835f4f91fc20937f3e70dcf3585c1afe31202bb6075185f9abfe", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x3.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x3.json new file mode 100644 index 0000000000..5c57ee6fcb --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x3.json @@ -0,0 +1,44 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x3", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0x600035ff", + "stateDiff": null, + "trace": [ + { + "action": { + "from": "0x627306090abab3a6e1400e9345bc60c78a8bef57", + "gas": "0xff2d6a", + "init": "0x6004600c60003960046000f3600035ff", + "value": "0x0" + }, + "result": { + "address": "0xf12b5dd4ead5f743c6baa640b0216200e89b60da", + "code": "0x600035ff", + "gasUsed": "0x338" + }, + "subtraces": 0, + "traceAddress": [], + "type": "create" + } + ], + "transactionHash": "0x8d5477f0aae852c3e9487b0f8e7b9ecf9ccdf23d7934d4b4b7eff40c271031e5", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json new file mode 100644 index 0000000000..6724406fa9 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json @@ -0,0 +1,45 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x4", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0x", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffaaea", + "input": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002", + "to": "0x0010000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x9c58", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ], + "transactionHash": "0x4de634fe767d1f6d0512ca0c9c0a054d3a2596f7cdd7c1eea5f93046a740b3c7", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json new file mode 100644 index 0000000000..89967f6f4b --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json @@ -0,0 +1,45 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x5", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0x", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffab6a", + "input": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000", + "to": "0x0010000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x2728", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ], + "transactionHash": "0xdb2cd5e93dedae66371fc4a95452c746e11f7d2097464707597b8807c889ef5b", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json new file mode 100644 index 0000000000..487b455ad1 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json @@ -0,0 +1,58 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x6", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0x", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffad1a", + "input": "0x0000000000000000000000000000000000000999", + "to": "0x0020000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x7536", + "output": "0x" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "address": "0x0020000000000000000000000000000000000000", + "balance": "0x300", + "refundAddress": "0x0000000000000999000000000000000000000000" + }, + "result": null, + "subtraces": 0, + "traceAddress": [ + 0 + ], + "type": "suicide" + } + ], + "transactionHash": "0x91eeabc671e2dd2b1c8ddebb46ba59e8cb3e7d189f80bcc868a9787728c6e59e", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json new file mode 100644 index 0000000000..e62f98fd22 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json @@ -0,0 +1,45 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x7", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0xf000000000000000000000000000000000000000000000000000000000000002", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffacea", + "input": "0xf000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0030000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x1b", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ], + "transactionHash": "0x47f4d445ea1812cb1ddd3464ab23d2bfc6ed408a8a9db1c497f94e8e06e85286", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json new file mode 100644 index 0000000000..9d78cf2fd3 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json @@ -0,0 +1,64 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x8", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0xf000000000000000000000000000000000000000000000000000000000000002", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffac2a", + "input": "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x30a", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xfbaa9c", + "input": "0xf000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0030000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x1b", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 0, + "traceAddress": [ + 0 + ], + "type": "call" + } + ], + "transactionHash": "0xa29f9d6a4f183f4c22c4857544a9a6b69c48d7bb8a97652be06e50bb69470666", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json new file mode 100644 index 0000000000..36aadcfdcb --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json @@ -0,0 +1,105 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x9", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0xf000000000000000000000000000000000000000000000000000000000000002", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffaaaa", + "input": "0x000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x8fa", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xfba917", + "input": "0x00000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x5ff", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [ + 0 + ], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xf7b790", + "input": "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x30a", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [ + 0, + 0 + ], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xf3d5d5", + "input": "0xf000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0030000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x1b", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 0, + "traceAddress": [ + 0, + 0, + 0 + ], + "type": "call" + } + ], + "transactionHash": "0x4af0ef28fbfcbdee7cc5925797c1b9030b3848c2f63f92737c3fe76b45582af5", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} From c93685dba9c9b93307f545366a4ec3ecf626fe86 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 3 Sep 2019 10:01:16 +0200 Subject: [PATCH 33/56] fix unit tests - return empty result if block is empty - handle case where there is no `RETURN`, `STOP` is then considered as a return to close the trace and perform gas computation. - increment gas remaining by gas used --- .../methods/TraceReplayBlockTransactions.java | 3 +++ .../jsonrpc/internal/results/tracing/Action.java | 6 ++++++ .../results/tracing/FlatTraceGenerator.java | 14 ++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index fd1a767683..2dc214b6bb 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -90,6 +90,9 @@ protected Object resultByBlockNumber(final JsonRpcRequest request, final long bl } private Object traceBlock(final Block block, final TraceTypeParameter traceTypeParameter) { + if (block == null || block.getBody().getTransactions().isEmpty()) { + return emptyResult(); + } // TODO: generate options based on traceTypeParameter final TraceOptions traceOptions = TraceOptions.DEFAULT; diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index f3ea6de74e..313713abce 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -15,6 +15,7 @@ import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; import tech.pegasys.pantheon.ethereum.core.Address; +import tech.pegasys.pantheon.ethereum.core.Gas; import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.debug.TraceFrame; @@ -137,6 +138,11 @@ public static Builder from(final TransactionTrace trace) { .value(trace.getTransaction().getValue().toShortHexString()); } + public Builder incrementGas(long value) { + this.gas = Gas.fromHexString(gas).plus(Gas.of(value)).toHexString(); + return this; + } + public Builder callType(final String callType) { this.callType = callType; return this; diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index cbea6953d1..43da0b5e0c 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -42,6 +42,7 @@ public class FlatTraceGenerator { */ public static Stream generateFromTransactionTrace( final TransactionTrace transactionTrace, final AtomicInteger traceCounter) { + transactionTrace.getTraceFrames().forEach(System.out::println); final FlatTrace.Builder firstFlatTraceBuilder = FlatTrace.freshBuilder(transactionTrace); final String lastContractAddress = transactionTrace.getTransaction().getTo().orElse(Address.ZERO).getHexString(); @@ -110,7 +111,7 @@ public static Stream generateFromTransactionTrace( tracesContexts, subTracesCounter); } - if ("RETURN".equals(traceFrame.getOpcode())) { + if ("RETURN".equals(traceFrame.getOpcode()) || "STOP".equals(traceFrame.getOpcode())) { handleReturn(traceFrame, smartContractAddress, cumulativeGasCost, tracesContexts); } } @@ -181,13 +182,22 @@ private static void handleReturn( flatTraceBuilder.type("create"); }, // set output otherwise - () -> resultBuilder.output(traceFrame.getMemory().orElseThrow()[0].toString())); + () -> + resultBuilder.output( + traceFrame.getMemory().isPresent() && traceFrame.getMemory().get().length > 0 + ? traceFrame.getMemory().get()[0].toString() + : "0x")); ctx.markAsReturned(); continueToPollContexts = false; } } // reinsert polled contexts add the end of the queue polledContexts.forEach(tracesContexts::addLast); + tracesContexts + .getFirst() + .getBuilder() + .getActionBuilder() + .ifPresent(actionBuilder -> actionBuilder.incrementGas(cumulativeGasCost.longValue())); cumulativeGasCost.set(0); } From 10680b019053c1680bfbcabf2a41cdf1ef104cdc Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 3 Sep 2019 10:28:47 +0200 Subject: [PATCH 34/56] spotless apply --- .../ethereum/jsonrpc/internal/results/tracing/Action.java | 2 +- .../jsonrpc/internal/results/tracing/FlatTraceGenerator.java | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index 313713abce..daefe43667 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -138,7 +138,7 @@ public static Builder from(final TransactionTrace trace) { .value(trace.getTransaction().getValue().toShortHexString()); } - public Builder incrementGas(long value) { + public Builder incrementGas(final long value) { this.gas = Gas.fromHexString(gas).plus(Gas.of(value)).toHexString(); return this; } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index 43da0b5e0c..beaa2f1f6c 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -42,7 +42,6 @@ public class FlatTraceGenerator { */ public static Stream generateFromTransactionTrace( final TransactionTrace transactionTrace, final AtomicInteger traceCounter) { - transactionTrace.getTraceFrames().forEach(System.out::println); final FlatTrace.Builder firstFlatTraceBuilder = FlatTrace.freshBuilder(transactionTrace); final String lastContractAddress = transactionTrace.getTransaction().getTo().orElse(Address.ZERO).getHexString(); From e73671632eda79c87602bf5170fc6e454a02cfdc Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 3 Sep 2019 10:56:55 +0200 Subject: [PATCH 35/56] introduce SELFDESTRUCT --- .../internal/results/tracing/Action.java | 92 +++++++++++++++---- .../internal/results/tracing/FlatTrace.java | 7 +- .../results/tracing/FlatTraceGenerator.java | 51 +++++++++- .../internal/results/tracing/Result.java | 10 +- 4 files changed, 135 insertions(+), 25 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index daefe43667..d876ad5f93 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -12,8 +12,7 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; - +import com.fasterxml.jackson.annotation.JsonInclude; import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Gas; import tech.pegasys.pantheon.ethereum.core.Transaction; @@ -21,7 +20,7 @@ import tech.pegasys.pantheon.ethereum.debug.TraceFrame; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; -import com.fasterxml.jackson.annotation.JsonInclude; +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; @JsonInclude(NON_NULL) public class Action { @@ -33,6 +32,35 @@ public class Action { private String to; private String init; private String value; + private String address; + private String balance; + private String refundAddress; + + public static Builder builder() { + return new Builder(); + } + + public static Builder createCallAction( + final Transaction transaction, + final String lastContractAddress, + final Address contractCallAddress, + final TraceFrame traceFrame) { + return builder() + .from(lastContractAddress) + .to(contractCallAddress.toString()) + .input(traceFrame.getMemory().orElseThrow()[0].getHexString()) + .gas(traceFrame.getGasRemaining().toHexString()) + .callType("call") + .value(transaction.getValue().toShortHexString()); + } + + public static Builder createSelfDestructAction( + final Transaction transaction, + final String lastContractAddress, + final Address contractCallAddress, + final TraceFrame traceFrame) { + return builder().address(lastContractAddress).refundAddress(contractCallAddress.toString()); + } public String getCallType() { return callType; @@ -90,22 +118,28 @@ public void setInit(final String init) { this.init = init; } - public static Builder builder() { - return new Builder(); + public String getAddress() { + return address; } - public static Builder createCallAction( - final Transaction transaction, - final String lastContractAddress, - final Address contractCallAddress, - final TraceFrame traceFrame) { - return builder() - .from(lastContractAddress) - .to(contractCallAddress.toString()) - .input(traceFrame.getMemory().orElseThrow()[0].getHexString()) - .gas(traceFrame.getGasRemaining().toHexString()) - .callType("call") - .value(transaction.getValue().toShortHexString()); + public void setAddress(final String address) { + this.address = address; + } + + public String getBalance() { + return balance; + } + + public void setBalance(final String balance) { + this.balance = balance; + } + + public String getRefundAddress() { + return refundAddress; + } + + public void setRefundAddress(final String refundAddress) { + this.refundAddress = refundAddress; } public static final class Builder { @@ -116,6 +150,9 @@ public static final class Builder { private String to; private String init; private String value; + private String address; + private String balance; + private String refundAddress; private Builder() {} @@ -128,6 +165,9 @@ public static Builder of(final Action action) { builder.to = action.to; builder.init = action.init; builder.value = action.value; + builder.address = action.address; + builder.refundAddress = action.refundAddress; + builder.balance = action.balance; return builder; } @@ -178,6 +218,21 @@ public Builder value(final String value) { return this; } + public Builder address(final String address) { + this.address = address; + return this; + } + + public Builder balance(final String balance) { + this.balance = balance; + return this; + } + + public Builder refundAddress(final String refundAddress) { + this.refundAddress = refundAddress; + return this; + } + public Action build() { final Action action = new Action(); action.setCallType(callType); @@ -187,6 +242,9 @@ public Action build() { action.setTo(to); action.setInit(init); action.setValue(value); + action.setAddress(address); + action.setRefundAddress(refundAddress); + action.setBalance(balance); return action; } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index ae655aeb15..9a5e189e1d 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -160,8 +160,11 @@ public FlatTrace build() { final FlatTrace flatTrace = new FlatTrace(); flatTrace.setAction(action); flatTrace.setAction(actionBuilder.orElseGet(() -> Action.Builder.of(action)).build()); - - flatTrace.setResult(resultBuilder.orElseGet(() -> Result.Builder.of(result)).build()); + if (resultBuilder != null) { + flatTrace.setResult(resultBuilder.orElseGet(() -> Result.Builder.of(result)).build()); + }else{ + flatTrace.setResult(null); + } flatTrace.setSubtraces(subtraces); flatTrace.setTraceAddress(traceAddress); flatTrace.setType(type); diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index beaa2f1f6c..c14c3a50e0 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -109,9 +109,17 @@ public static Stream generateFromTransactionTrace( addressVector, tracesContexts, subTracesCounter); - } - if ("RETURN".equals(traceFrame.getOpcode()) || "STOP".equals(traceFrame.getOpcode())) { + } else if ("RETURN".equals(traceFrame.getOpcode()) || "STOP".equals(traceFrame.getOpcode())) { handleReturn(traceFrame, smartContractAddress, cumulativeGasCost, tracesContexts); + } else if ("SELFDESTRUCT".equals(traceFrame.getOpcode())) { + handleSelfDestruct( + transactionTrace.getTransaction(), + traceFrame, + lastContractAddress, + cumulativeGasCost, + addressVector, + tracesContexts, + subTracesCounter); } } final List flatTraces = new ArrayList<>(); @@ -200,6 +208,45 @@ private static void handleReturn( cumulativeGasCost.set(0); } + private static void handleSelfDestruct( + final Transaction transaction, + final TraceFrame traceFrame, + final String lastContractAddress, + final AtomicLong cumulativeGasCost, + final List addressVector, + final Deque tracesContexts, + final AtomicInteger subTracesCounter) { + final Bytes32[] stack = traceFrame.getStack().orElseThrow(); + final Address refundAddress = toAddress(stack[0]); + final FlatTrace.Builder subTraceBuilder = + FlatTrace.builder() + .type("suicide") + .traceAddress(addressVector.toArray(new Integer[0])); + final Action.Builder subTraceActionBuilder = + Action.createSelfDestructAction( + transaction, lastContractAddress, refundAddress, traceFrame); + + final long gasCost = cumulativeGasCost.longValue(); + // retrieve the previous transactionTrace context + Optional.ofNullable(tracesContexts.peekLast()) + .ifPresent( + previousContext -> { + // increment sub traces counter of previous transactionTrace + previousContext.getBuilder().incSubTraces(); + // set gas cost of previous transactionTrace + previousContext + .getBuilder() + .getResultBuilder() + .orElse(Result.builder()) + .gasUsed(Gas.of(gasCost).toHexString()); + }); + tracesContexts.addLast( + new FlatTrace.Context(subTraceBuilder.action(subTraceActionBuilder.build()))); + // compute transactionTrace addresses + IntStream.of(subTracesCounter.incrementAndGet()).forEach(addressVector::add); + cumulativeGasCost.set(0); + } + private static Address toAddress(final Bytes32 value) { return Address.wrap( BytesValue.of( diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java index c9f3c1a1fa..0e8e47a469 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java @@ -90,10 +90,12 @@ public Builder address(final String address) { public static Builder of(final Result result) { final Builder builder = new Builder(); - builder.output = result.output; - builder.gasUsed = result.gasUsed; - builder.code = result.code; - builder.address = result.address; + if (result != null) { + builder.output = result.output; + builder.gasUsed = result.gasUsed; + builder.code = result.code; + builder.address = result.address; + } return builder; } From 4841e66794362beb41cc44310c377352b829ac5b Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 3 Sep 2019 13:31:32 +0200 Subject: [PATCH 36/56] set result to null when suicide type --- .../ethereum/jsonrpc/internal/results/tracing/Action.java | 5 +++-- .../jsonrpc/internal/results/tracing/FlatTrace.java | 7 ++----- .../internal/results/tracing/FlatTraceGenerator.java | 4 +--- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index d876ad5f93..1cb6d1d55f 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -12,7 +12,8 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; -import com.fasterxml.jackson.annotation.JsonInclude; +import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; + import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Gas; import tech.pegasys.pantheon.ethereum.core.Transaction; @@ -20,7 +21,7 @@ import tech.pegasys.pantheon.ethereum.debug.TraceFrame; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; -import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; +import com.fasterxml.jackson.annotation.JsonInclude; @JsonInclude(NON_NULL) public class Action { diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index 9a5e189e1d..33819d21cf 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -160,11 +160,8 @@ public FlatTrace build() { final FlatTrace flatTrace = new FlatTrace(); flatTrace.setAction(action); flatTrace.setAction(actionBuilder.orElseGet(() -> Action.Builder.of(action)).build()); - if (resultBuilder != null) { - flatTrace.setResult(resultBuilder.orElseGet(() -> Result.Builder.of(result)).build()); - }else{ - flatTrace.setResult(null); - } + resultBuilder.ifPresentOrElse( + builder -> flatTrace.setResult(builder.build()), () -> flatTrace.setResult(null)); flatTrace.setSubtraces(subtraces); flatTrace.setTraceAddress(traceAddress); flatTrace.setType(type); diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index c14c3a50e0..667f9bd6f4 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -219,9 +219,7 @@ private static void handleSelfDestruct( final Bytes32[] stack = traceFrame.getStack().orElseThrow(); final Address refundAddress = toAddress(stack[0]); final FlatTrace.Builder subTraceBuilder = - FlatTrace.builder() - .type("suicide") - .traceAddress(addressVector.toArray(new Integer[0])); + FlatTrace.builder().type("suicide").traceAddress(addressVector.toArray(new Integer[0])); final Action.Builder subTraceActionBuilder = Action.createSelfDestructAction( transaction, lastContractAddress, refundAddress, traceFrame); From 6dd19fb2395c73be0831ca2eb02e459dfbf23d03 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 3 Sep 2019 13:41:45 +0200 Subject: [PATCH 37/56] remove result field, use builder only --- .../jsonrpc/internal/results/tracing/FlatTrace.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index 33819d21cf..870535ff68 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -104,7 +104,6 @@ public static final class Builder { private Action action; private Optional actionBuilder = Optional.empty(); - private Result result; private Optional resultBuilder = Optional.empty(); private int subtraces; private Integer[] traceAddress = new Integer[0]; @@ -117,11 +116,6 @@ public Builder action(final Action action) { return this; } - public Builder result(final Result result) { - this.result = result; - return this; - } - public Builder resultBuilder(final Result.Builder resultBuilder) { this.resultBuilder = Optional.ofNullable(resultBuilder); return this; From 025eb42a8fc0078157a0efe46e9ef438814f2acf Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Wed, 4 Sep 2019 10:03:35 +0200 Subject: [PATCH 38/56] re-enable tracing tests --- .../ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java | 7 ------- .../jsonrpc/trace/trace_replayBlockTransactions_0x0.json | 1 - .../jsonrpc/trace/trace_replayBlockTransactions_0x1.json | 3 +-- .../trace/trace_replayBlockTransactions_earliest.json | 3 +-- .../trace_replayBlockTransactions_invalidBlockParam.json | 3 +-- .../trace_replayBlockTransactions_invalidTraceOptions.json | 3 +-- .../trace/trace_replayBlockTransactions_pending.json | 3 +-- 7 files changed, 5 insertions(+), 18 deletions(-) diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java index 46f753b26c..0d412c0b23 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java @@ -102,13 +102,6 @@ private void jsonRPCCall(final URL specFile) throws IOException { final String json = Resources.toString(specFile, Charsets.UTF_8); final ObjectNode specNode = (ObjectNode) objectMapper.readTree(json); - // TODO remove when https://github.com/PegaSysEng/pantheon/pull/1886 is merged - // temporary ignore flaky tests - if (specNode.has("ignored") && specNode.get("ignored").asBoolean()) { - System.err.println("Ignored test."); - return; - } - final String rawRequestBody = specNode.get("request").toString(); final RequestBody requestBody = RequestBody.create(JSON, rawRequestBody); final Request request = new Request.Builder().post(requestBody).url(baseUrl).build(); diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json index 5b0582cf90..e0831e7a4b 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json @@ -1,5 +1,4 @@ { - "ignored": true, "request": { "jsonrpc": "2.0", "method": "trace_replayBlockTransactions", diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json index 0759a367b4..143756b273 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json @@ -1,6 +1,5 @@ { - "ignored": true, - "request": { +"request": { "jsonrpc": "2.0", "method": "trace_replayBlockTransactions", "params": [ diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json index d70c784c8c..a137025d71 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json @@ -1,6 +1,5 @@ { - "ignored": true, - "request": { +"request": { "id": 415, "jsonrpc": "2.0", "method": "trace_replayBlockTransactions", diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json index 5f24d06014..0281b72d66 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json @@ -1,6 +1,5 @@ { - "ignored": true, - "request": { +"request": { "id": 415, "jsonrpc": "2.0", "method": "trace_replayBlockTransactions", diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json index 8a8d2df750..34c64277d9 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json @@ -1,6 +1,5 @@ { - "ignored": true, - "request": { +"request": { "id": 415, "jsonrpc": "2.0", "method": "trace_replayBlockTransactions", diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json index d53d8213d6..f2a2dee6d7 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json @@ -1,6 +1,5 @@ { - "ignored": true, - "request": { +"request": { "id": 415, "jsonrpc": "2.0", "method": "trace_replayBlockTransactions", From 5babade04428eba6bc871bd80aedc662543fa4b6 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Wed, 4 Sep 2019 16:18:50 +0200 Subject: [PATCH 39/56] implement gas used computation - implement a strategy with 2 options - if first frame gas remaining is higher than gas remaining after transaction was processed then the gas used will be the net difference - otherwise a frame by frame cumulative gas cost will be used --- .../internal/results/tracing/Action.java | 7 +--- .../results/tracing/FlatTraceGenerator.java | 38 ++++++++++++++----- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index 1cb6d1d55f..eacf7ff8d0 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -175,15 +175,10 @@ public static Builder of(final Action action) { public static Builder from(final TransactionTrace trace) { return new Builder() .from(trace.getTransaction().getSender().getHexString()) - .gas(Wei.of(trace.getResult().getGasRemaining()).toStrictShortHexString()) + .gas(trace.getTraceFrames().get(0).getGasRemaining().toHexString()) .value(trace.getTransaction().getValue().toShortHexString()); } - public Builder incrementGas(final long value) { - this.gas = Gas.fromHexString(gas).plus(Gas.of(value)).toHexString(); - return this; - } - public Builder callType(final String callType) { this.callType = callType; return this; diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index 667f9bd6f4..5802bec190 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -31,8 +31,13 @@ import java.util.stream.IntStream; import java.util.stream.Stream; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + public class FlatTraceGenerator { + public static final Logger LOG = LogManager.getLogger(); + /** * Generates a stream of {@link Trace} from the passed {@link TransactionTrace} data. * @@ -98,8 +103,11 @@ public static Stream generateFromTransactionTrace( addressVector.add(traceCounter.get()); final AtomicInteger subTracesCounter = new AtomicInteger(0); final AtomicLong cumulativeGasCost = new AtomicLong(0); + LOG.info("Result gas remaining: {}", transactionTrace.getResult().getGasRemaining()); for (TraceFrame traceFrame : transactionTrace.getTraceFrames()) { cumulativeGasCost.addAndGet(traceFrame.getGasCost().orElse(Gas.ZERO).toLong()); + LOG.info("cumulativeGasCost: {}", cumulativeGasCost); + LOG.info("{} - {}", traceFrame.getOpcode(), traceFrame); if ("CALL".equals(traceFrame.getOpcode())) { handleCall( transactionTrace.getTransaction(), @@ -110,7 +118,8 @@ public static Stream generateFromTransactionTrace( tracesContexts, subTracesCounter); } else if ("RETURN".equals(traceFrame.getOpcode()) || "STOP".equals(traceFrame.getOpcode())) { - handleReturn(traceFrame, smartContractAddress, cumulativeGasCost, tracesContexts); + handleReturn( + transactionTrace, traceFrame, smartContractAddress, tracesContexts, cumulativeGasCost); } else if ("SELFDESTRUCT".equals(traceFrame.getOpcode())) { handleSelfDestruct( transactionTrace.getTransaction(), @@ -167,10 +176,11 @@ private static void handleCall( } private static void handleReturn( + final TransactionTrace transactionTrace, final TraceFrame traceFrame, final Optional smartContractAddress, - final AtomicLong cumulativeGasCost, - final Deque tracesContexts) { + final Deque tracesContexts, + final AtomicLong cumulativeGasCost) { final Deque polledContexts = new ArrayDeque<>(); FlatTrace.Context ctx; boolean continueToPollContexts = true; @@ -178,10 +188,11 @@ private static void handleReturn( while (continueToPollContexts && (ctx = tracesContexts.pollLast()) != null) { polledContexts.addFirst(ctx); if (!ctx.isReturned()) { + final long gasUsed = computeGasUsed(transactionTrace, cumulativeGasCost); final FlatTrace.Builder flatTraceBuilder = ctx.getBuilder(); final Result.Builder resultBuilder = flatTraceBuilder.getResultBuilder().orElse(Result.builder()); - resultBuilder.gasUsed(Gas.of(cumulativeGasCost.longValue()).toHexString()); + resultBuilder.gasUsed(Gas.of(gasUsed).toHexString()); // set address and type to create if smart contract deployment smartContractAddress.ifPresentOrElse( address -> { @@ -200,12 +211,6 @@ private static void handleReturn( } // reinsert polled contexts add the end of the queue polledContexts.forEach(tracesContexts::addLast); - tracesContexts - .getFirst() - .getBuilder() - .getActionBuilder() - .ifPresent(actionBuilder -> actionBuilder.incrementGas(cumulativeGasCost.longValue())); - cumulativeGasCost.set(0); } private static void handleSelfDestruct( @@ -245,6 +250,19 @@ private static void handleSelfDestruct( cumulativeGasCost.set(0); } + private static long computeGasUsed( + final TransactionTrace transactionTrace, final AtomicLong cumulativeGasCost) { + final long firstFrameGasRemaining = + transactionTrace.getTraceFrames().get(0).getGasRemaining().toLong(); + final long gasRemainingAfterTransactionWasProcessed = + transactionTrace.getResult().getGasRemaining(); + if (firstFrameGasRemaining > gasRemainingAfterTransactionWasProcessed) { + return firstFrameGasRemaining - gasRemainingAfterTransactionWasProcessed; + } else { + return cumulativeGasCost.longValue(); + } + } + private static Address toAddress(final Bytes32 value) { return Address.wrap( BytesValue.of( From 96f2e7d5e848fc303624e6f647567358a1b3b0d5 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Wed, 4 Sep 2019 17:16:53 +0200 Subject: [PATCH 40/56] get self destruct refund balance from message frame --- .../pantheon/ethereum/debug/TraceFrame.java | 36 ++++++++++++++++++- .../ethereum/vm/DebugOperationTracer.java | 8 +++-- .../pantheon/ethereum/vm/MessageFrame.java | 23 ++++++++++++ .../vm/operations/SelfDestructOperation.java | 4 +++ .../internal/results/tracing/Action.java | 11 +++--- .../results/tracing/FlatTraceGenerator.java | 16 +++++---- 6 files changed, 83 insertions(+), 15 deletions(-) diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/debug/TraceFrame.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/debug/TraceFrame.java index 9f0f821529..e74866850b 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/debug/TraceFrame.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/debug/TraceFrame.java @@ -12,7 +12,9 @@ */ package tech.pegasys.pantheon.ethereum.debug; +import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Gas; +import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.vm.ExceptionalHaltReason; import tech.pegasys.pantheon.util.bytes.Bytes32; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -36,6 +38,7 @@ public class TraceFrame { private final Optional memory; private final Optional> storage; private final Optional revertReason; + private final Optional> maybeRefunds; public TraceFrame( final int pc, @@ -47,7 +50,8 @@ public TraceFrame( final Optional stack, final Optional memory, final Optional> storage, - final Optional revertReason) { + final Optional revertReason, + final Optional> maybeRefunds) { this.pc = pc; this.opcode = opcode; this.gasRemaining = gasRemaining; @@ -58,6 +62,32 @@ public TraceFrame( this.memory = memory; this.storage = storage; this.revertReason = revertReason; + this.maybeRefunds = maybeRefunds; + } + + public TraceFrame( + final int pc, + final String opcode, + final Gas gasRemaining, + final Optional gasCost, + final int depth, + final EnumSet exceptionalHaltReasons, + final Optional stack, + final Optional memory, + final Optional> storage, + final Optional revertReason) { + this( + pc, + opcode, + gasRemaining, + gasCost, + depth, + exceptionalHaltReasons, + stack, + memory, + storage, + revertReason, + Optional.empty()); } public TraceFrame( @@ -123,6 +153,10 @@ public Optional getRevertReason() { return revertReason; } + public Optional> getMaybeRefunds() { + return maybeRefunds; + } + @Override public String toString() { return MoreObjects.toStringHelper(this) diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/DebugOperationTracer.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/DebugOperationTracer.java index 20c81baac6..36dd8dfb41 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/DebugOperationTracer.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/DebugOperationTracer.java @@ -14,7 +14,9 @@ import static tech.pegasys.pantheon.util.uint.UInt256.U_32; +import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Gas; +import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.debug.TraceFrame; import tech.pegasys.pantheon.ethereum.debug.TraceOptions; import tech.pegasys.pantheon.ethereum.vm.ehalt.ExceptionalHaltException; @@ -56,7 +58,8 @@ public void traceExecution( executeOperation.execute(); } finally { final Optional> storage = captureStorage(frame); - + final Optional> maybeRefunds = + frame.getRefunds().isEmpty() ? Optional.empty() : Optional.of(frame.getRefunds()); traceFrames.add( new TraceFrame( pc, @@ -68,7 +71,8 @@ public void traceExecution( stack, memory, storage, - frame.getRevertReason())); + frame.getRevertReason(), + maybeRefunds)); } } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/MessageFrame.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/MessageFrame.java index 4573f67054..0bc56a0dfe 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/MessageFrame.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/MessageFrame.java @@ -32,7 +32,9 @@ import java.util.Deque; import java.util.EnumSet; +import java.util.HashMap; import java.util.HashSet; +import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.function.Consumer; @@ -202,6 +204,7 @@ public enum Type { private final LogSeries logs; private Gas gasRefund; private final Set
selfDestructs; + private final Map refunds; // Execution Environment fields. private final Address recipient; @@ -271,6 +274,7 @@ private MessageFrame( this.logs = LogSeries.empty(); this.gasRefund = Gas.ZERO; this.selfDestructs = new HashSet<>(); + this.refunds = new HashMap<>(); this.recipient = recipient; this.originator = originator; this.contract = contract; @@ -654,6 +658,25 @@ public Set
getSelfDestructs() { return selfDestructs; } + /** + * Add refund to the refunds map if not already present. + * + * @param beneficiary the beneficiary of the refund. + * @param amount the amount of the refund. + */ + public void addRefund(final Address beneficiary, final Wei amount) { + refunds.put(beneficiary, amount); + } + + /** + * Returns the refunds map. + * + * @return the refunds map + */ + public Map getRefunds() { + return refunds; + } + /** * Returns the current blockchain. * diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/operations/SelfDestructOperation.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/operations/SelfDestructOperation.java index 41b35c37d9..ff058e0e02 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/operations/SelfDestructOperation.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/vm/operations/SelfDestructOperation.java @@ -54,6 +54,10 @@ public void execute(final MessageFrame frame) { frame.getWorldState().getOrCreate(Words.toAddress(frame.popStackItem())); recipient.incrementBalance(account.getBalance()); + + // add refund in message frame + frame.addRefund(recipient.getAddress(), account.getBalance()); + account.setBalance(Wei.ZERO); frame.setState(MessageFrame.State.CODE_SUCCESS); diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index eacf7ff8d0..da028ea385 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -15,7 +15,6 @@ import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; import tech.pegasys.pantheon.ethereum.core.Address; -import tech.pegasys.pantheon.ethereum.core.Gas; import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.debug.TraceFrame; @@ -56,11 +55,11 @@ public static Builder createCallAction( } public static Builder createSelfDestructAction( - final Transaction transaction, - final String lastContractAddress, - final Address contractCallAddress, - final TraceFrame traceFrame) { - return builder().address(lastContractAddress).refundAddress(contractCallAddress.toString()); + final String lastContractAddress, final Address contractCallAddress, final Wei balance) { + return builder() + .address(lastContractAddress) + .refundAddress(contractCallAddress.toString()) + .balance(balance.toShortHexString()); } public String getCallType() { diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index 5802bec190..4c7711c196 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -15,6 +15,7 @@ import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Gas; import tech.pegasys.pantheon.ethereum.core.Transaction; +import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.debug.TraceFrame; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; import tech.pegasys.pantheon.util.bytes.Bytes32; @@ -28,9 +29,11 @@ import java.util.Optional; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.IntStream; import java.util.stream.Stream; +import com.google.common.util.concurrent.Atomics; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -103,10 +106,8 @@ public static Stream generateFromTransactionTrace( addressVector.add(traceCounter.get()); final AtomicInteger subTracesCounter = new AtomicInteger(0); final AtomicLong cumulativeGasCost = new AtomicLong(0); - LOG.info("Result gas remaining: {}", transactionTrace.getResult().getGasRemaining()); for (TraceFrame traceFrame : transactionTrace.getTraceFrames()) { cumulativeGasCost.addAndGet(traceFrame.getGasCost().orElse(Gas.ZERO).toLong()); - LOG.info("cumulativeGasCost: {}", cumulativeGasCost); LOG.info("{} - {}", traceFrame.getOpcode(), traceFrame); if ("CALL".equals(traceFrame.getOpcode())) { handleCall( @@ -122,7 +123,6 @@ public static Stream generateFromTransactionTrace( transactionTrace, traceFrame, smartContractAddress, tracesContexts, cumulativeGasCost); } else if ("SELFDESTRUCT".equals(traceFrame.getOpcode())) { handleSelfDestruct( - transactionTrace.getTransaction(), traceFrame, lastContractAddress, cumulativeGasCost, @@ -214,7 +214,6 @@ private static void handleReturn( } private static void handleSelfDestruct( - final Transaction transaction, final TraceFrame traceFrame, final String lastContractAddress, final AtomicLong cumulativeGasCost, @@ -225,9 +224,14 @@ private static void handleSelfDestruct( final Address refundAddress = toAddress(stack[0]); final FlatTrace.Builder subTraceBuilder = FlatTrace.builder().type("suicide").traceAddress(addressVector.toArray(new Integer[0])); + + final AtomicReference weiBalance = Atomics.newReference(Wei.ZERO); + traceFrame + .getMaybeRefunds() + .ifPresent(refunds -> weiBalance.set(refunds.getOrDefault(refundAddress, Wei.ZERO))); + final Action.Builder subTraceActionBuilder = - Action.createSelfDestructAction( - transaction, lastContractAddress, refundAddress, traceFrame); + Action.createSelfDestructAction(lastContractAddress, refundAddress, weiBalance.get()); final long gasCost = cumulativeGasCost.longValue(); // retrieve the previous transactionTrace context From 978dcc73162a781e643da68a94454a7ec546b456 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Thu, 5 Sep 2019 16:14:11 +0200 Subject: [PATCH 41/56] give access to `ProtocolSchedule` to get `GasCalculator` --- .../ethereum/mainnet/ProtocolSpec.java | 17 ++++++++++++++- .../ethereum/mainnet/ProtocolSpecBuilder.java | 3 ++- .../jsonrpc/JsonRpcMethodsFactory.java | 3 ++- .../methods/TraceReplayBlockTransactions.java | 21 +++++++++++++++---- .../results/tracing/FlatTraceGenerator.java | 9 ++++++-- .../results/tracing/TraceFormatter.java | 4 +++- .../jsonrpc/TraceJsonRpcHttpBySpecTest.java | 6 +++++- .../methods/EthGetTransactionReceiptTest.java | 6 ++++-- .../NoRewardProtocolScheduleWrapper.java | 3 ++- 9 files changed, 58 insertions(+), 14 deletions(-) diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSpec.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSpec.java index 0b418c4bb1..a74833453c 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSpec.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSpec.java @@ -19,6 +19,7 @@ import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.mainnet.MainnetBlockProcessor.TransactionReceiptFactory; import tech.pegasys.pantheon.ethereum.vm.EVM; +import tech.pegasys.pantheon.ethereum.vm.GasCalculator; /** A protocol specification. */ public class ProtocolSpec { @@ -26,6 +27,8 @@ public class ProtocolSpec { private final String name; private final EVM evm; + private final GasCalculator gasCalculator; + private final TransactionValidator transactionValidator; private final TransactionProcessor transactionProcessor; @@ -76,6 +79,7 @@ public class ProtocolSpec { * @param miningBeneficiaryCalculator determines to whom mining proceeds are paid * @param precompileContractRegistry all the pre-compiled contracts added * @param skipZeroBlockRewards should rewards be skipped if it is zero + * @param gasCalculator the gas calculator to use. */ public ProtocolSpec( final String name, @@ -94,7 +98,8 @@ public ProtocolSpec( final Wei blockReward, final MiningBeneficiaryCalculator miningBeneficiaryCalculator, final PrecompileContractRegistry precompileContractRegistry, - final boolean skipZeroBlockRewards) { + final boolean skipZeroBlockRewards, + final GasCalculator gasCalculator) { this.name = name; this.evm = evm; this.transactionValidator = transactionValidator; @@ -112,6 +117,7 @@ public ProtocolSpec( this.miningBeneficiaryCalculator = miningBeneficiaryCalculator; this.precompileContractRegistry = precompileContractRegistry; this.skipZeroBlockRewards = skipZeroBlockRewards; + this.gasCalculator = gasCalculator; } /** @@ -259,6 +265,15 @@ public PrecompileContractRegistry getPrecompileContractRegistry() { return precompileContractRegistry; } + /** + * Returns the gasCalculator used in this specification. + * + * @return the gas calculator + */ + public GasCalculator getGasCalculator() { + return gasCalculator; + } + public void setTransactionFilter(final TransactionFilter transactionFilter) { transactionValidator.setTransactionFilter(transactionFilter); } diff --git a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSpecBuilder.java b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSpecBuilder.java index 40480883c1..24e5e75b23 100644 --- a/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSpecBuilder.java +++ b/ethereum/core/src/main/java/tech/pegasys/pantheon/ethereum/mainnet/ProtocolSpecBuilder.java @@ -331,7 +331,8 @@ public ProtocolSpec build(final ProtocolSchedule protocolSchedule) { blockReward, miningBeneficiaryCalculator, precompileContractRegistry, - skipZeroBlockRewards); + skipZeroBlockRewards, + gasCalculator); } public interface TransactionProcessorBuilder { diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java index e286b989d7..c50650256e 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/JsonRpcMethodsFactory.java @@ -345,7 +345,8 @@ blockchainQueries, new TransactionTracer(blockReplay), parameter), protocolSchedule, blockchainQueries.getBlockchain(), blockchainQueries.getWorldStateArchive())), - blockchainQueries)); + blockchainQueries, + protocolSchedule)); } final boolean eea = rpcApis.contains(RpcApis.EEA); diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 2dc214b6bb..1d09b624ef 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -28,6 +28,7 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.FlatTraceGenerator; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.Trace; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.TraceFormatter; +import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer; import java.util.List; @@ -45,13 +46,16 @@ public class TraceReplayBlockTransactions extends AbstractBlockParameterMethod { private static final Logger LOG = LogManager.getLogger(); private final BlockTracer blockTracer; + private final ProtocolSchedule protocolSchedule; public TraceReplayBlockTransactions( final JsonRpcParameter parameters, final BlockTracer blockTracer, - final BlockchainQueries queries) { + final BlockchainQueries queries, + final ProtocolSchedule protocolSchedule) { super(queries, parameters); this.blockTracer = blockTracer; + this.protocolSchedule = protocolSchedule; } @Override @@ -99,12 +103,14 @@ private Object traceBlock(final Block block, final TraceTypeParameter traceTypeP return blockTracer .trace(block, new DebugOperationTracer(traceOptions)) .map(BlockTrace::getTransactionTraces) - .map((traces) -> formatTraces(traces, traceTypeParameter)) + .map((traces) -> formatTraces(block.getHeader().getNumber(), traces, traceTypeParameter)) .orElse(null); } private JsonNode formatTraces( - final List traces, final TraceTypeParameter traceTypeParameter) { + final long blockNumber, + final List traces, + final TraceTypeParameter traceTypeParameter) { final Set traceTypes = traceTypeParameter.getTraceTypes(); final ObjectMapper mapper = new ObjectMapper(); final ArrayNode resultArrayNode = mapper.createArrayNode(); @@ -123,6 +129,7 @@ private JsonNode formatTraces( if (traceTypes.contains(TraceTypeParameter.TraceType.TRACE)) { formatTraces( + blockNumber, resultNode.putArray("trace")::addPOJO, traces, FlatTraceGenerator::generateFromTransactionTrace, @@ -134,13 +141,19 @@ private JsonNode formatTraces( } private void formatTraces( + final long blockNumber, final Trace.ResultWriter writer, final List traces, final TraceFormatter formatter, final AtomicInteger traceCounter) { traces.forEach( (transactionTrace) -> - formatter.format(transactionTrace, traceCounter).forEachOrdered(writer::write)); + formatter + .format( + transactionTrace, + traceCounter, + protocolSchedule.getByBlockNumber(blockNumber).getGasCalculator()) + .forEachOrdered(writer::write)); } private Object emptyResult() { diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index 4c7711c196..feadc1d409 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -18,6 +18,7 @@ import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.debug.TraceFrame; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; +import tech.pegasys.pantheon.ethereum.vm.GasCalculator; import tech.pegasys.pantheon.util.bytes.Bytes32; import tech.pegasys.pantheon.util.bytes.BytesValue; @@ -49,7 +50,9 @@ public class FlatTraceGenerator { * @return a stream of generated traces {@link Trace} */ public static Stream generateFromTransactionTrace( - final TransactionTrace transactionTrace, final AtomicInteger traceCounter) { + final TransactionTrace transactionTrace, + final AtomicInteger traceCounter, + final GasCalculator gasCalculator) { final FlatTrace.Builder firstFlatTraceBuilder = FlatTrace.freshBuilder(transactionTrace); final String lastContractAddress = transactionTrace.getTransaction().getTo().orElse(Address.ZERO).getHexString(); @@ -101,11 +104,13 @@ public static Stream generateFromTransactionTrace( // add the first transactionTrace context to the queue of transactionTrace contexts tracesContexts.addLast(new FlatTrace.Context(firstFlatTraceBuilder)); // declare the first transactionTrace context as the previous transactionTrace context - // FlatTrace.Context previousTraceContext = tracesContexts.peekLast(); final List addressVector = new ArrayList<>(); addressVector.add(traceCounter.get()); final AtomicInteger subTracesCounter = new AtomicInteger(0); final AtomicLong cumulativeGasCost = new AtomicLong(0); + LOG.info( + "Transaction intrinsic gas cost: {}", + gasCalculator.transactionIntrinsicGasCost(transactionTrace.getTransaction())); for (TraceFrame traceFrame : transactionTrace.getTraceFrames()) { cumulativeGasCost.addAndGet(traceFrame.getGasCost().orElse(Gas.ZERO).toLong()); LOG.info("{} - {}", traceFrame.getOpcode(), traceFrame); diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceFormatter.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceFormatter.java index 31118ff968..0b01e75d57 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceFormatter.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceFormatter.java @@ -13,6 +13,7 @@ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; +import tech.pegasys.pantheon.ethereum.vm.GasCalculator; import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; @@ -20,5 +21,6 @@ @FunctionalInterface public interface TraceFormatter { - Stream format(TransactionTrace transactionTrace, AtomicInteger traceCounter); + Stream format( + TransactionTrace transactionTrace, AtomicInteger traceCounter, GasCalculator gasCalculator); } diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java index 3f077c55d1..6b952f4930 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java @@ -63,7 +63,11 @@ protected Map getRpcMethods( blockchainSetupUtil.getWorldArchive()); final BlockTracer blockTracer = new BlockTracer(blockReplay); final TraceReplayBlockTransactions traceReplayBlockTransactions = - new TraceReplayBlockTransactions(new JsonRpcParameter(), blockTracer, blockchainQueries); + new TraceReplayBlockTransactions( + new JsonRpcParameter(), + blockTracer, + blockchainQueries, + blockchainSetupUtil.getProtocolSchedule()); methods.put(traceReplayBlockTransactions.getName(), traceReplayBlockTransactions); return methods; diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java index 3a8826e6e0..d3ee2c3873 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/EthGetTransactionReceiptTest.java @@ -91,7 +91,8 @@ public class EthGetTransactionReceiptTest { null, BlockHeader::getCoinbase, null, - false); + false, + null); private final ProtocolSpec statusTransactionTypeSpec = new ProtocolSpec<>( "status", @@ -110,7 +111,8 @@ public class EthGetTransactionReceiptTest { null, BlockHeader::getCoinbase, null, - false); + false, + null); private final JsonRpcParameter parameters = new JsonRpcParameter(); diff --git a/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java b/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java index cc5d6d40bd..e77f406bc9 100644 --- a/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java +++ b/ethereum/retesteth/src/main/java/tech/pegasys/pantheon/ethereum/retesteth/NoRewardProtocolScheduleWrapper.java @@ -68,7 +68,8 @@ public ProtocolSpec getByBlockNumber(final long number) { Wei.ZERO, // block reward original.getMiningBeneficiaryCalculator(), original.getPrecompileContractRegistry(), - original.isSkipZeroBlockRewards()); + original.isSkipZeroBlockRewards(), + original.getGasCalculator()); } @Override From 34880a22e7d229e2a2be2bb7a80619a0c2465309 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Thu, 5 Sep 2019 17:13:30 +0200 Subject: [PATCH 42/56] fix gas used computation for subtrace (1 level deep) --- .../internal/results/tracing/Action.java | 10 ++- .../internal/results/tracing/FlatTrace.java | 10 +++ .../results/tracing/FlatTraceGenerator.java | 70 +++++++++++++------ 3 files changed, 67 insertions(+), 23 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index da028ea385..99ed4c2df7 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -15,6 +15,7 @@ import static com.fasterxml.jackson.annotation.JsonInclude.Include.NON_NULL; import tech.pegasys.pantheon.ethereum.core.Address; +import tech.pegasys.pantheon.ethereum.core.Gas; import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.debug.TraceFrame; @@ -44,12 +45,13 @@ public static Builder createCallAction( final Transaction transaction, final String lastContractAddress, final Address contractCallAddress, - final TraceFrame traceFrame) { + final TraceFrame traceFrame, + final Gas gasRemaining) { return builder() .from(lastContractAddress) .to(contractCallAddress.toString()) .input(traceFrame.getMemory().orElseThrow()[0].getHexString()) - .gas(traceFrame.getGasRemaining().toHexString()) + .gas(gasRemaining.toHexString()) .callType("call") .value(transaction.getValue().toShortHexString()); } @@ -228,6 +230,10 @@ public Builder refundAddress(final String refundAddress) { return this; } + public String getGas() { + return gas; + } + public Action build() { final Action action = new Action(); action.setCallType(callType); diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index 870535ff68..d363c80bc9 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -77,6 +77,7 @@ public static class Context { private Builder builder; private boolean returned; + private boolean isSubtrace = false; public Context(final Builder builder) { this(builder, false); @@ -95,6 +96,15 @@ public boolean isReturned() { return returned; } + public boolean isSubtrace() { + return isSubtrace; + } + + public Context subTrace() { + this.isSubtrace = true; + return this; + } + public void markAsReturned() { this.returned = true; } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index feadc1d409..ba93adec88 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -14,7 +14,6 @@ import tech.pegasys.pantheon.ethereum.core.Address; import tech.pegasys.pantheon.ethereum.core.Gas; -import tech.pegasys.pantheon.ethereum.core.Transaction; import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.debug.TraceFrame; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; @@ -108,24 +107,33 @@ public static Stream generateFromTransactionTrace( addressVector.add(traceCounter.get()); final AtomicInteger subTracesCounter = new AtomicInteger(0); final AtomicLong cumulativeGasCost = new AtomicLong(0); - LOG.info( - "Transaction intrinsic gas cost: {}", - gasCalculator.transactionIntrinsicGasCost(transactionTrace.getTransaction())); + final Gas transactionIntrinsicGasCost = + gasCalculator.transactionIntrinsicGasCost(transactionTrace.getTransaction()); + LOG.debug( + "Transaction intrinsic gas cost: {} - {}", + transactionIntrinsicGasCost.toLong(), + transactionIntrinsicGasCost.toHexString()); + int traceFrameIndex = 0; for (TraceFrame traceFrame : transactionTrace.getTraceFrames()) { cumulativeGasCost.addAndGet(traceFrame.getGasCost().orElse(Gas.ZERO).toLong()); - LOG.info("{} - {}", traceFrame.getOpcode(), traceFrame); + LOG.info( + "{} - {} - {} - {}", + traceFrame.getOpcode(), + traceFrame.getGasCost().orElse(Gas.ZERO).toLong(), + traceFrame.getGasRemaining().toLong(), + traceFrame.getGasRemaining().toHexString()); if ("CALL".equals(traceFrame.getOpcode())) { handleCall( - transactionTrace.getTransaction(), + transactionTrace, traceFrame, lastContractAddress, cumulativeGasCost, addressVector, tracesContexts, - subTracesCounter); + subTracesCounter, + traceFrameIndex); } else if ("RETURN".equals(traceFrame.getOpcode()) || "STOP".equals(traceFrame.getOpcode())) { - handleReturn( - transactionTrace, traceFrame, smartContractAddress, tracesContexts, cumulativeGasCost); + handleReturn(transactionTrace, traceFrame, smartContractAddress, tracesContexts); } else if ("SELFDESTRUCT".equals(traceFrame.getOpcode())) { handleSelfDestruct( traceFrame, @@ -135,6 +143,7 @@ public static Stream generateFromTransactionTrace( tracesContexts, subTracesCounter); } + traceFrameIndex++; } final List flatTraces = new ArrayList<>(); tracesContexts.forEach(context -> flatTraces.add(context.getBuilder().build())); @@ -143,21 +152,30 @@ public static Stream generateFromTransactionTrace( } private static void handleCall( - final Transaction transaction, + final TransactionTrace transactionTrace, final TraceFrame traceFrame, final String lastContractAddress, final AtomicLong cumulativeGasCost, final List addressVector, final Deque tracesContexts, - final AtomicInteger subTracesCounter) { + final AtomicInteger subTracesCounter, + final int traceFrameIndex) { final Bytes32[] stack = traceFrame.getStack().orElseThrow(); final Address contractCallAddress = toAddress(stack[stack.length - 2]); final FlatTrace.Builder subTraceBuilder = FlatTrace.builder() .traceAddress(addressVector.toArray(new Integer[0])) .resultBuilder(Result.builder()); + // get the next trace frame to set the gas field (gas remaining) of the sub trace + final TraceFrame traceFrameAfterCall = + transactionTrace.getTraceFrames().get(traceFrameIndex + 1); final Action.Builder subTraceActionBuilder = - Action.createCallAction(transaction, lastContractAddress, contractCallAddress, traceFrame); + Action.createCallAction( + transactionTrace.getTransaction(), + lastContractAddress, + contractCallAddress, + traceFrame, + traceFrameAfterCall.getGasRemaining()); final long gasCost = cumulativeGasCost.longValue(); // retrieve the previous transactionTrace context @@ -174,7 +192,7 @@ private static void handleCall( .gasUsed(Gas.of(gasCost).toHexString()); }); tracesContexts.addLast( - new FlatTrace.Context(subTraceBuilder.action(subTraceActionBuilder.build()))); + new FlatTrace.Context(subTraceBuilder.actionBuilder(subTraceActionBuilder)).subTrace()); // compute transactionTrace addresses IntStream.of(subTracesCounter.incrementAndGet()).forEach(addressVector::add); cumulativeGasCost.set(0); @@ -184,8 +202,7 @@ private static void handleReturn( final TransactionTrace transactionTrace, final TraceFrame traceFrame, final Optional smartContractAddress, - final Deque tracesContexts, - final AtomicLong cumulativeGasCost) { + final Deque tracesContexts) { final Deque polledContexts = new ArrayDeque<>(); FlatTrace.Context ctx; boolean continueToPollContexts = true; @@ -193,11 +210,22 @@ private static void handleReturn( while (continueToPollContexts && (ctx = tracesContexts.pollLast()) != null) { polledContexts.addFirst(ctx); if (!ctx.isReturned()) { - final long gasUsed = computeGasUsed(transactionTrace, cumulativeGasCost); final FlatTrace.Builder flatTraceBuilder = ctx.getBuilder(); + final Gas gasRemainingAtStartOfTrace = + Gas.fromHexString( + flatTraceBuilder.getActionBuilder().orElse(Action.builder()).getGas()); + final Gas gasUsed = gasRemainingAtStartOfTrace.minus(traceFrame.getGasRemaining()); final Result.Builder resultBuilder = flatTraceBuilder.getResultBuilder().orElse(Result.builder()); - resultBuilder.gasUsed(Gas.of(gasUsed).toHexString()); + final Gas finalGasUsed; + if (ctx.isSubtrace()) { + finalGasUsed = gasUsed; + } else { + finalGasUsed = computeGasUsed(transactionTrace, gasUsed); + } + + // set gas used for the trace + resultBuilder.gasUsed(finalGasUsed.toHexString()); // set address and type to create if smart contract deployment smartContractAddress.ifPresentOrElse( address -> { @@ -259,16 +287,16 @@ private static void handleSelfDestruct( cumulativeGasCost.set(0); } - private static long computeGasUsed( - final TransactionTrace transactionTrace, final AtomicLong cumulativeGasCost) { + private static Gas computeGasUsed( + final TransactionTrace transactionTrace, final Gas fallbackValue) { final long firstFrameGasRemaining = transactionTrace.getTraceFrames().get(0).getGasRemaining().toLong(); final long gasRemainingAfterTransactionWasProcessed = transactionTrace.getResult().getGasRemaining(); if (firstFrameGasRemaining > gasRemainingAfterTransactionWasProcessed) { - return firstFrameGasRemaining - gasRemainingAfterTransactionWasProcessed; + return Gas.of(firstFrameGasRemaining - gasRemainingAfterTransactionWasProcessed); } else { - return cumulativeGasCost.longValue(); + return fallbackValue; } } From ac1a5985eac4bba26f3051dafbbcb70b00c59733 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Thu, 5 Sep 2019 17:38:20 +0200 Subject: [PATCH 43/56] fix input, use all memory and not only first element --- .../internal/results/tracing/Action.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index 99ed4c2df7..89c62d9850 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -20,6 +20,12 @@ import tech.pegasys.pantheon.ethereum.core.Wei; import tech.pegasys.pantheon.ethereum.debug.TraceFrame; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; +import tech.pegasys.pantheon.util.bytes.Bytes32; +import tech.pegasys.pantheon.util.bytes.BytesValue; + +import java.util.Arrays; +import java.util.Optional; +import java.util.stream.Collectors; import com.fasterxml.jackson.annotation.JsonInclude; @@ -50,7 +56,7 @@ public static Builder createCallAction( return builder() .from(lastContractAddress) .to(contractCallAddress.toString()) - .input(traceFrame.getMemory().orElseThrow()[0].getHexString()) + .input(dumpMemory(traceFrame.getMemory())) .gas(gasRemaining.toHexString()) .callType("call") .value(transaction.getValue().toShortHexString()); @@ -64,6 +70,18 @@ public static Builder createSelfDestructAction( .balance(balance.toShortHexString()); } + private static String dumpMemory(final Optional memory) { + return memory + .map( + element -> + "0x" + .concat( + Arrays.stream(element) + .map(BytesValue::toUnprefixedString) + .collect(Collectors.joining()))) + .orElse(""); + } + public String getCallType() { return callType; } From a250cde6d0613eba75bb12add4947e2504230222 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Fri, 6 Sep 2019 09:53:05 +0200 Subject: [PATCH 44/56] fix trace addresses --- .../internal/results/tracing/FlatTrace.java | 12 +++--- .../results/tracing/FlatTraceGenerator.java | 41 +++++++------------ .../AbstractJsonRpcHttpBySpecTest.java | 2 + ...trace_replayBlockTransactions_pending.json | 40 +++++++++--------- 4 files changed, 43 insertions(+), 52 deletions(-) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index d363c80bc9..da3e91ba0d 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -14,13 +14,15 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; public class FlatTrace implements Trace { private Action action; private Result result; private int subtraces; - private Integer[] traceAddress = new Integer[0]; + private List traceAddress = new ArrayList<>(); private String type; public static Builder freshBuilder(final TransactionTrace transactionTrace) { @@ -53,11 +55,11 @@ public void setSubtraces(final int subtraces) { this.subtraces = subtraces; } - public Integer[] getTraceAddress() { + public List getTraceAddress() { return traceAddress; } - public void setTraceAddress(final Integer[] traceAddress) { + public void setTraceAddress(final List traceAddress) { this.traceAddress = traceAddress; } @@ -116,7 +118,7 @@ public static final class Builder { private Optional actionBuilder = Optional.empty(); private Optional resultBuilder = Optional.empty(); private int subtraces; - private Integer[] traceAddress = new Integer[0]; + private List traceAddress = new ArrayList<>(); private String type = "call"; private Builder() {} @@ -141,7 +143,7 @@ public Builder subtraces(final int subtraces) { return this; } - public Builder traceAddress(final Integer[] traceAddress) { + public Builder traceAddress(final List traceAddress) { this.traceAddress = traceAddress; return this; } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index ba93adec88..6ea50784e6 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -30,9 +30,9 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; -import java.util.stream.IntStream; import java.util.stream.Stream; +import com.google.common.collect.Lists; import com.google.common.util.concurrent.Atomics; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -104,8 +104,6 @@ public static Stream generateFromTransactionTrace( tracesContexts.addLast(new FlatTrace.Context(firstFlatTraceBuilder)); // declare the first transactionTrace context as the previous transactionTrace context final List addressVector = new ArrayList<>(); - addressVector.add(traceCounter.get()); - final AtomicInteger subTracesCounter = new AtomicInteger(0); final AtomicLong cumulativeGasCost = new AtomicLong(0); final Gas transactionIntrinsicGasCost = gasCalculator.transactionIntrinsicGasCost(transactionTrace.getTransaction()); @@ -116,12 +114,6 @@ public static Stream generateFromTransactionTrace( int traceFrameIndex = 0; for (TraceFrame traceFrame : transactionTrace.getTraceFrames()) { cumulativeGasCost.addAndGet(traceFrame.getGasCost().orElse(Gas.ZERO).toLong()); - LOG.info( - "{} - {} - {} - {}", - traceFrame.getOpcode(), - traceFrame.getGasCost().orElse(Gas.ZERO).toLong(), - traceFrame.getGasRemaining().toLong(), - traceFrame.getGasRemaining().toHexString()); if ("CALL".equals(traceFrame.getOpcode())) { handleCall( transactionTrace, @@ -130,18 +122,12 @@ public static Stream generateFromTransactionTrace( cumulativeGasCost, addressVector, tracesContexts, - subTracesCounter, traceFrameIndex); } else if ("RETURN".equals(traceFrame.getOpcode()) || "STOP".equals(traceFrame.getOpcode())) { handleReturn(transactionTrace, traceFrame, smartContractAddress, tracesContexts); } else if ("SELFDESTRUCT".equals(traceFrame.getOpcode())) { handleSelfDestruct( - traceFrame, - lastContractAddress, - cumulativeGasCost, - addressVector, - tracesContexts, - subTracesCounter); + traceFrame, lastContractAddress, cumulativeGasCost, addressVector, tracesContexts); } traceFrameIndex++; } @@ -158,14 +144,17 @@ private static void handleCall( final AtomicLong cumulativeGasCost, final List addressVector, final Deque tracesContexts, - final AtomicInteger subTracesCounter, final int traceFrameIndex) { final Bytes32[] stack = traceFrame.getStack().orElseThrow(); final Address contractCallAddress = toAddress(stack[stack.length - 2]); + if (addressVector.size() <= traceFrame.getDepth()) { + addressVector.add(0); + } else { + addressVector.set(traceFrame.getDepth(), addressVector.get(traceFrame.getDepth()) + 1); + } + final List traceAddress = Lists.newCopyOnWriteArrayList(addressVector); final FlatTrace.Builder subTraceBuilder = - FlatTrace.builder() - .traceAddress(addressVector.toArray(new Integer[0])) - .resultBuilder(Result.builder()); + FlatTrace.builder().traceAddress(traceAddress).resultBuilder(Result.builder()); // get the next trace frame to set the gas field (gas remaining) of the sub trace final TraceFrame traceFrameAfterCall = transactionTrace.getTraceFrames().get(traceFrameIndex + 1); @@ -193,8 +182,6 @@ private static void handleCall( }); tracesContexts.addLast( new FlatTrace.Context(subTraceBuilder.actionBuilder(subTraceActionBuilder)).subTrace()); - // compute transactionTrace addresses - IntStream.of(subTracesCounter.incrementAndGet()).forEach(addressVector::add); cumulativeGasCost.set(0); } @@ -251,12 +238,14 @@ private static void handleSelfDestruct( final String lastContractAddress, final AtomicLong cumulativeGasCost, final List addressVector, - final Deque tracesContexts, - final AtomicInteger subTracesCounter) { + final Deque tracesContexts) { final Bytes32[] stack = traceFrame.getStack().orElseThrow(); final Address refundAddress = toAddress(stack[0]); + if (addressVector.size() <= traceFrame.getDepth()) { + addressVector.add(0); + } final FlatTrace.Builder subTraceBuilder = - FlatTrace.builder().type("suicide").traceAddress(addressVector.toArray(new Integer[0])); + FlatTrace.builder().type("suicide").traceAddress(addressVector); final AtomicReference weiBalance = Atomics.newReference(Wei.ZERO); traceFrame @@ -282,8 +271,6 @@ private static void handleSelfDestruct( }); tracesContexts.addLast( new FlatTrace.Context(subTraceBuilder.action(subTraceActionBuilder.build()))); - // compute transactionTrace addresses - IntStream.of(subTracesCounter.incrementAndGet()).forEach(addressVector::add); cumulativeGasCost.set(0); } diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java index 0d412c0b23..c540d67be1 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java @@ -135,6 +135,8 @@ private void jsonRPCCall(final URL specFile) throws IOException { final String expectedResult = expectedResponse.get("result").toString(); final String actualResult = responseBody.get("result").toString(); final ObjectMapper mapper = new ObjectMapper(); + System.err.println(mapper.readTree(actualResult).toString()); + System.err.println(mapper.readTree(expectedResult).toString()); assertThat(mapper.readTree(actualResult)).isEqualTo(mapper.readTree(expectedResult)); } diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json index f2a2dee6d7..340c78c561 100644 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json @@ -1,6 +1,5 @@ { -"request": { - "id": 415, + "request": { "jsonrpc": "2.0", "method": "trace_replayBlockTransactions", "params": [ @@ -8,29 +7,27 @@ [ "trace" ] - ] + ], + "id": 415 }, "response": { "jsonrpc": "2.0", - "id": 415, "result": [ { - "transactionHash": "0x4af0ef28fbfcbdee7cc5925797c1b9030b3848c2f63f92737c3fe76b45582af5", "output": "0xf000000000000000000000000000000000000000000000000000000000000002", "stateDiff": null, - "vmTrace": null, "trace": [ { "action": { "callType": "call", "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", - "gas": "0xee00513e", + "gas": "0xffaaaa", "input": "0x000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", "to": "0x0040000000000000000000000000000000000000", "value": "0x0" }, "result": { - "gasUsed": "0x6", + "gasUsed": "0x8fa", "output": "0xf000000000000000000000000000000000000000000000000000000000000002" }, "subtraces": 1, @@ -41,13 +38,13 @@ "action": { "callType": "call", "from": "0x0040000000000000000000000000000000000000", - "gas": "0xffaa71", - "input": "0x0000000000000000000000000040000000000000000000000000000000000000", + "gas": "0xfba917", + "input": "0x00000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", "to": "0x0040000000000000000000000000000000000000", "value": "0x0" }, "result": { - "gasUsed": "0x6", + "gasUsed": "0x5ff", "output": "0xf000000000000000000000000000000000000000000000000000000000000002" }, "subtraces": 1, @@ -60,19 +57,19 @@ "action": { "callType": "call", "from": "0x0040000000000000000000000000000000000000", - "gas": "0xfba8e4", - "input": "0x0000000000000000000000000030000000000000000000000000000000000000", + "gas": "0xf7b790", + "input": "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", "to": "0x0040000000000000000000000000000000000000", "value": "0x0" }, "result": { - "gasUsed": "0x6", + "gasUsed": "0x30a", "output": "0xf000000000000000000000000000000000000000000000000000000000000002" }, "subtraces": 1, "traceAddress": [ 0, - 1 + 0 ], "type": "call" }, @@ -80,7 +77,7 @@ "action": { "callType": "call", "from": "0x0040000000000000000000000000000000000000", - "gas": "0xf7b763", + "gas": "0xf3d5d5", "input": "0xf000000000000000000000000000000000000000000000000000000000000001", "to": "0x0030000000000000000000000000000000000000", "value": "0x0" @@ -92,14 +89,17 @@ "subtraces": 0, "traceAddress": [ 0, - 1, - 2 + 0, + 0 ], "type": "call" } - ] + ], + "transactionHash": "0x4af0ef28fbfcbdee7cc5925797c1b9030b3848c2f63f92737c3fe76b45582af5", + "vmTrace": null } - ] + ], + "id": 415 }, "statusCode": 200 } From d472e9725bd3aab8c600d54eb3226d90dfc380b8 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Fri, 6 Sep 2019 10:35:43 +0200 Subject: [PATCH 45/56] debug log --- .../ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java index c540d67be1..2440c8df4d 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java @@ -135,8 +135,8 @@ private void jsonRPCCall(final URL specFile) throws IOException { final String expectedResult = expectedResponse.get("result").toString(); final String actualResult = responseBody.get("result").toString(); final ObjectMapper mapper = new ObjectMapper(); - System.err.println(mapper.readTree(actualResult).toString()); - System.err.println(mapper.readTree(expectedResult).toString()); + System.err.println("---" + mapper.readTree(actualResult).toString() + "---"); + System.err.println("+++" + mapper.readTree(expectedResult).toString() + "+++"); assertThat(mapper.readTree(actualResult)).isEqualTo(mapper.readTree(expectedResult)); } From 88ee6aa84c199e1f386e1ba314c507d17c89226d Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Fri, 6 Sep 2019 17:33:12 +0200 Subject: [PATCH 46/56] remove some tests files --- .../trace_replayBlockTransactions_0x0.json | 19 ---- .../trace_replayBlockTransactions_0x1.json | 19 ---- .../trace_replayBlockTransactions_0x2.json | 45 -------- .../trace_replayBlockTransactions_0x4.json | 45 -------- .../trace_replayBlockTransactions_0x5.json | 45 -------- .../trace_replayBlockTransactions_0x6.json | 58 ---------- .../trace_replayBlockTransactions_0x7.json | 45 -------- .../trace_replayBlockTransactions_0x8.json | 64 ----------- .../trace_replayBlockTransactions_0x9.json | 105 ------------------ ...race_replayBlockTransactions_earliest.json | 17 --- ...ayBlockTransactions_invalidBlockParam.json | 20 ---- ...BlockTransactions_invalidTraceOptions.json | 20 ---- ...trace_replayBlockTransactions_pending.json | 105 ------------------ 13 files changed, 607 deletions(-) delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json delete mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json deleted file mode 100644 index e0831e7a4b..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "request": { - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "0x0", - [ - "trace" - ] - ], - "id": 415 - }, - "response": { - "jsonrpc": "2.0", - "result": [], - "id": 415 - }, - "statusCode": 200 -} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json deleted file mode 100644 index 143756b273..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json +++ /dev/null @@ -1,19 +0,0 @@ -{ -"request": { - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "0x1", - [ - "trace" - ] - ], - "id": 415 - }, - "response": { - "jsonrpc": "2.0", - "result": [], - "id": 415 - }, - "statusCode": 200 -} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json deleted file mode 100644 index 702ffd6e24..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "request": { - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "0x2", - [ - "trace" - ] - ], - "id": 415 - }, - "response": { - "jsonrpc": "2.0", - "result": [ - { - "output": "0x", - "stateDiff": null, - "trace": [ - { - "action": { - "callType": "call", - "from": "0x627306090abab3a6e1400e9345bc60c78a8bef57", - "gas": "0xffadea", - "input": "0x", - "to": "0x0000000000000000000000000000000000000999", - "value": "0x1" - }, - "result": { - "gasUsed": "0x0", - "output": "0x" - }, - "subtraces": 0, - "traceAddress": [], - "type": "call" - } - ], - "transactionHash": "0x28fa8042c7b5835f4f91fc20937f3e70dcf3585c1afe31202bb6075185f9abfe", - "vmTrace": null - } - ], - "id": 415 - }, - "statusCode": 200 -} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json deleted file mode 100644 index 6724406fa9..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "request": { - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "0x4", - [ - "trace" - ] - ], - "id": 415 - }, - "response": { - "jsonrpc": "2.0", - "result": [ - { - "output": "0x", - "stateDiff": null, - "trace": [ - { - "action": { - "callType": "call", - "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", - "gas": "0xffaaea", - "input": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002", - "to": "0x0010000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x9c58", - "output": "0x" - }, - "subtraces": 0, - "traceAddress": [], - "type": "call" - } - ], - "transactionHash": "0x4de634fe767d1f6d0512ca0c9c0a054d3a2596f7cdd7c1eea5f93046a740b3c7", - "vmTrace": null - } - ], - "id": 415 - }, - "statusCode": 200 -} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json deleted file mode 100644 index 89967f6f4b..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "request": { - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "0x5", - [ - "trace" - ] - ], - "id": 415 - }, - "response": { - "jsonrpc": "2.0", - "result": [ - { - "output": "0x", - "stateDiff": null, - "trace": [ - { - "action": { - "callType": "call", - "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", - "gas": "0xffab6a", - "input": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000", - "to": "0x0010000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x2728", - "output": "0x" - }, - "subtraces": 0, - "traceAddress": [], - "type": "call" - } - ], - "transactionHash": "0xdb2cd5e93dedae66371fc4a95452c746e11f7d2097464707597b8807c889ef5b", - "vmTrace": null - } - ], - "id": 415 - }, - "statusCode": 200 -} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json deleted file mode 100644 index 487b455ad1..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json +++ /dev/null @@ -1,58 +0,0 @@ -{ - "request": { - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "0x6", - [ - "trace" - ] - ], - "id": 415 - }, - "response": { - "jsonrpc": "2.0", - "result": [ - { - "output": "0x", - "stateDiff": null, - "trace": [ - { - "action": { - "callType": "call", - "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", - "gas": "0xffad1a", - "input": "0x0000000000000000000000000000000000000999", - "to": "0x0020000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x7536", - "output": "0x" - }, - "subtraces": 1, - "traceAddress": [], - "type": "call" - }, - { - "action": { - "address": "0x0020000000000000000000000000000000000000", - "balance": "0x300", - "refundAddress": "0x0000000000000999000000000000000000000000" - }, - "result": null, - "subtraces": 0, - "traceAddress": [ - 0 - ], - "type": "suicide" - } - ], - "transactionHash": "0x91eeabc671e2dd2b1c8ddebb46ba59e8cb3e7d189f80bcc868a9787728c6e59e", - "vmTrace": null - } - ], - "id": 415 - }, - "statusCode": 200 -} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json deleted file mode 100644 index e62f98fd22..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "request": { - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "0x7", - [ - "trace" - ] - ], - "id": 415 - }, - "response": { - "jsonrpc": "2.0", - "result": [ - { - "output": "0xf000000000000000000000000000000000000000000000000000000000000002", - "stateDiff": null, - "trace": [ - { - "action": { - "callType": "call", - "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", - "gas": "0xffacea", - "input": "0xf000000000000000000000000000000000000000000000000000000000000001", - "to": "0x0030000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x1b", - "output": "0xf000000000000000000000000000000000000000000000000000000000000002" - }, - "subtraces": 0, - "traceAddress": [], - "type": "call" - } - ], - "transactionHash": "0x47f4d445ea1812cb1ddd3464ab23d2bfc6ed408a8a9db1c497f94e8e06e85286", - "vmTrace": null - } - ], - "id": 415 - }, - "statusCode": 200 -} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json deleted file mode 100644 index 9d78cf2fd3..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "request": { - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "0x8", - [ - "trace" - ] - ], - "id": 415 - }, - "response": { - "jsonrpc": "2.0", - "result": [ - { - "output": "0xf000000000000000000000000000000000000000000000000000000000000002", - "stateDiff": null, - "trace": [ - { - "action": { - "callType": "call", - "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", - "gas": "0xffac2a", - "input": "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", - "to": "0x0040000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x30a", - "output": "0xf000000000000000000000000000000000000000000000000000000000000002" - }, - "subtraces": 1, - "traceAddress": [], - "type": "call" - }, - { - "action": { - "callType": "call", - "from": "0x0040000000000000000000000000000000000000", - "gas": "0xfbaa9c", - "input": "0xf000000000000000000000000000000000000000000000000000000000000001", - "to": "0x0030000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x1b", - "output": "0xf000000000000000000000000000000000000000000000000000000000000002" - }, - "subtraces": 0, - "traceAddress": [ - 0 - ], - "type": "call" - } - ], - "transactionHash": "0xa29f9d6a4f183f4c22c4857544a9a6b69c48d7bb8a97652be06e50bb69470666", - "vmTrace": null - } - ], - "id": 415 - }, - "statusCode": 200 -} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json deleted file mode 100644 index 36aadcfdcb..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "request": { - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "0x9", - [ - "trace" - ] - ], - "id": 415 - }, - "response": { - "jsonrpc": "2.0", - "result": [ - { - "output": "0xf000000000000000000000000000000000000000000000000000000000000002", - "stateDiff": null, - "trace": [ - { - "action": { - "callType": "call", - "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", - "gas": "0xffaaaa", - "input": "0x000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", - "to": "0x0040000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x8fa", - "output": "0xf000000000000000000000000000000000000000000000000000000000000002" - }, - "subtraces": 1, - "traceAddress": [], - "type": "call" - }, - { - "action": { - "callType": "call", - "from": "0x0040000000000000000000000000000000000000", - "gas": "0xfba917", - "input": "0x00000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", - "to": "0x0040000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x5ff", - "output": "0xf000000000000000000000000000000000000000000000000000000000000002" - }, - "subtraces": 1, - "traceAddress": [ - 0 - ], - "type": "call" - }, - { - "action": { - "callType": "call", - "from": "0x0040000000000000000000000000000000000000", - "gas": "0xf7b790", - "input": "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", - "to": "0x0040000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x30a", - "output": "0xf000000000000000000000000000000000000000000000000000000000000002" - }, - "subtraces": 1, - "traceAddress": [ - 0, - 0 - ], - "type": "call" - }, - { - "action": { - "callType": "call", - "from": "0x0040000000000000000000000000000000000000", - "gas": "0xf3d5d5", - "input": "0xf000000000000000000000000000000000000000000000000000000000000001", - "to": "0x0030000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x1b", - "output": "0xf000000000000000000000000000000000000000000000000000000000000002" - }, - "subtraces": 0, - "traceAddress": [ - 0, - 0, - 0 - ], - "type": "call" - } - ], - "transactionHash": "0x4af0ef28fbfcbdee7cc5925797c1b9030b3848c2f63f92737c3fe76b45582af5", - "vmTrace": null - } - ], - "id": 415 - }, - "statusCode": 200 -} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json deleted file mode 100644 index a137025d71..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json +++ /dev/null @@ -1,17 +0,0 @@ -{ -"request": { - "id": 415, - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "earliest", - ["trace"] - ] - }, - "response": { - "jsonrpc": "2.0", - "id": 415, - "result": [] - }, - "statusCode": 200 -} \ No newline at end of file diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json deleted file mode 100644 index 0281b72d66..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json +++ /dev/null @@ -1,20 +0,0 @@ -{ -"request": { - "id": 415, - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", - ["trace"] - ] - }, - "response": { - "jsonrpc": "2.0", - "id": 415, - "error": { - "code": -32602, - "message": "Invalid params" - } - }, - "statusCode": 400 -} \ No newline at end of file diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json deleted file mode 100644 index 34c64277d9..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json +++ /dev/null @@ -1,20 +0,0 @@ -{ -"request": { - "id": 415, - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "0x01", - ["bla"] - ] - }, - "response": { - "jsonrpc": "2.0", - "id": 415, - "error": { - "code": -32602, - "message": "Invalid params" - } - }, - "statusCode": 400 -} \ No newline at end of file diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json deleted file mode 100644 index 340c78c561..0000000000 --- a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json +++ /dev/null @@ -1,105 +0,0 @@ -{ - "request": { - "jsonrpc": "2.0", - "method": "trace_replayBlockTransactions", - "params": [ - "pending", - [ - "trace" - ] - ], - "id": 415 - }, - "response": { - "jsonrpc": "2.0", - "result": [ - { - "output": "0xf000000000000000000000000000000000000000000000000000000000000002", - "stateDiff": null, - "trace": [ - { - "action": { - "callType": "call", - "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", - "gas": "0xffaaaa", - "input": "0x000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", - "to": "0x0040000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x8fa", - "output": "0xf000000000000000000000000000000000000000000000000000000000000002" - }, - "subtraces": 1, - "traceAddress": [], - "type": "call" - }, - { - "action": { - "callType": "call", - "from": "0x0040000000000000000000000000000000000000", - "gas": "0xfba917", - "input": "0x00000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", - "to": "0x0040000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x5ff", - "output": "0xf000000000000000000000000000000000000000000000000000000000000002" - }, - "subtraces": 1, - "traceAddress": [ - 0 - ], - "type": "call" - }, - { - "action": { - "callType": "call", - "from": "0x0040000000000000000000000000000000000000", - "gas": "0xf7b790", - "input": "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", - "to": "0x0040000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x30a", - "output": "0xf000000000000000000000000000000000000000000000000000000000000002" - }, - "subtraces": 1, - "traceAddress": [ - 0, - 0 - ], - "type": "call" - }, - { - "action": { - "callType": "call", - "from": "0x0040000000000000000000000000000000000000", - "gas": "0xf3d5d5", - "input": "0xf000000000000000000000000000000000000000000000000000000000000001", - "to": "0x0030000000000000000000000000000000000000", - "value": "0x0" - }, - "result": { - "gasUsed": "0x1b", - "output": "0xf000000000000000000000000000000000000000000000000000000000000002" - }, - "subtraces": 0, - "traceAddress": [ - 0, - 0, - 0 - ], - "type": "call" - } - ], - "transactionHash": "0x4af0ef28fbfcbdee7cc5925797c1b9030b3848c2f63f92737c3fe76b45582af5", - "vmTrace": null - } - ], - "id": 415 - }, - "statusCode": 200 -} From 2857e222a15bbaf8b3663262c64dafb8d53a7891 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Fri, 6 Sep 2019 17:54:45 +0200 Subject: [PATCH 47/56] Revert "remove some tests files" This reverts commit 88ee6aa84c199e1f386e1ba314c507d17c89226d. --- .../trace_replayBlockTransactions_0x0.json | 19 ++++ .../trace_replayBlockTransactions_0x1.json | 19 ++++ .../trace_replayBlockTransactions_0x2.json | 45 ++++++++ .../trace_replayBlockTransactions_0x4.json | 45 ++++++++ .../trace_replayBlockTransactions_0x5.json | 45 ++++++++ .../trace_replayBlockTransactions_0x6.json | 58 ++++++++++ .../trace_replayBlockTransactions_0x7.json | 45 ++++++++ .../trace_replayBlockTransactions_0x8.json | 64 +++++++++++ .../trace_replayBlockTransactions_0x9.json | 105 ++++++++++++++++++ ...race_replayBlockTransactions_earliest.json | 17 +++ ...ayBlockTransactions_invalidBlockParam.json | 20 ++++ ...BlockTransactions_invalidTraceOptions.json | 20 ++++ ...trace_replayBlockTransactions_pending.json | 105 ++++++++++++++++++ 13 files changed, 607 insertions(+) create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json create mode 100644 ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json new file mode 100644 index 0000000000..e0831e7a4b --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x0.json @@ -0,0 +1,19 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x0", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json new file mode 100644 index 0000000000..143756b273 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x1.json @@ -0,0 +1,19 @@ +{ +"request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x1", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json new file mode 100644 index 0000000000..702ffd6e24 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x2.json @@ -0,0 +1,45 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x2", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0x", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0x627306090abab3a6e1400e9345bc60c78a8bef57", + "gas": "0xffadea", + "input": "0x", + "to": "0x0000000000000000000000000000000000000999", + "value": "0x1" + }, + "result": { + "gasUsed": "0x0", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ], + "transactionHash": "0x28fa8042c7b5835f4f91fc20937f3e70dcf3585c1afe31202bb6075185f9abfe", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json new file mode 100644 index 0000000000..6724406fa9 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x4.json @@ -0,0 +1,45 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x4", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0x", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffaaea", + "input": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002", + "to": "0x0010000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x9c58", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ], + "transactionHash": "0x4de634fe767d1f6d0512ca0c9c0a054d3a2596f7cdd7c1eea5f93046a740b3c7", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json new file mode 100644 index 0000000000..89967f6f4b --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x5.json @@ -0,0 +1,45 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x5", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0x", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffab6a", + "input": "0x0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000", + "to": "0x0010000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x2728", + "output": "0x" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ], + "transactionHash": "0xdb2cd5e93dedae66371fc4a95452c746e11f7d2097464707597b8807c889ef5b", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json new file mode 100644 index 0000000000..487b455ad1 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x6.json @@ -0,0 +1,58 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x6", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0x", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffad1a", + "input": "0x0000000000000000000000000000000000000999", + "to": "0x0020000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x7536", + "output": "0x" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "address": "0x0020000000000000000000000000000000000000", + "balance": "0x300", + "refundAddress": "0x0000000000000999000000000000000000000000" + }, + "result": null, + "subtraces": 0, + "traceAddress": [ + 0 + ], + "type": "suicide" + } + ], + "transactionHash": "0x91eeabc671e2dd2b1c8ddebb46ba59e8cb3e7d189f80bcc868a9787728c6e59e", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json new file mode 100644 index 0000000000..e62f98fd22 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x7.json @@ -0,0 +1,45 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x7", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0xf000000000000000000000000000000000000000000000000000000000000002", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffacea", + "input": "0xf000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0030000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x1b", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 0, + "traceAddress": [], + "type": "call" + } + ], + "transactionHash": "0x47f4d445ea1812cb1ddd3464ab23d2bfc6ed408a8a9db1c497f94e8e06e85286", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json new file mode 100644 index 0000000000..9d78cf2fd3 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x8.json @@ -0,0 +1,64 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x8", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0xf000000000000000000000000000000000000000000000000000000000000002", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffac2a", + "input": "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x30a", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xfbaa9c", + "input": "0xf000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0030000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x1b", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 0, + "traceAddress": [ + 0 + ], + "type": "call" + } + ], + "transactionHash": "0xa29f9d6a4f183f4c22c4857544a9a6b69c48d7bb8a97652be06e50bb69470666", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json new file mode 100644 index 0000000000..36aadcfdcb --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_0x9.json @@ -0,0 +1,105 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x9", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0xf000000000000000000000000000000000000000000000000000000000000002", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffaaaa", + "input": "0x000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x8fa", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xfba917", + "input": "0x00000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x5ff", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [ + 0 + ], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xf7b790", + "input": "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x30a", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [ + 0, + 0 + ], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xf3d5d5", + "input": "0xf000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0030000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x1b", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 0, + "traceAddress": [ + 0, + 0, + 0 + ], + "type": "call" + } + ], + "transactionHash": "0x4af0ef28fbfcbdee7cc5925797c1b9030b3848c2f63f92737c3fe76b45582af5", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json new file mode 100644 index 0000000000..a137025d71 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_earliest.json @@ -0,0 +1,17 @@ +{ +"request": { + "id": 415, + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "earliest", + ["trace"] + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 415, + "result": [] + }, + "statusCode": 200 +} \ No newline at end of file diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json new file mode 100644 index 0000000000..0281b72d66 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidBlockParam.json @@ -0,0 +1,20 @@ +{ +"request": { + "id": 415, + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", + ["trace"] + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 415, + "error": { + "code": -32602, + "message": "Invalid params" + } + }, + "statusCode": 400 +} \ No newline at end of file diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json new file mode 100644 index 0000000000..34c64277d9 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_invalidTraceOptions.json @@ -0,0 +1,20 @@ +{ +"request": { + "id": 415, + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "0x01", + ["bla"] + ] + }, + "response": { + "jsonrpc": "2.0", + "id": 415, + "error": { + "code": -32602, + "message": "Invalid params" + } + }, + "statusCode": 400 +} \ No newline at end of file diff --git a/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json new file mode 100644 index 0000000000..340c78c561 --- /dev/null +++ b/ethereum/jsonrpc/src/test/resources/tech/pegasys/pantheon/ethereum/jsonrpc/trace/trace_replayBlockTransactions_pending.json @@ -0,0 +1,105 @@ +{ + "request": { + "jsonrpc": "2.0", + "method": "trace_replayBlockTransactions", + "params": [ + "pending", + [ + "trace" + ] + ], + "id": 415 + }, + "response": { + "jsonrpc": "2.0", + "result": [ + { + "output": "0xf000000000000000000000000000000000000000000000000000000000000002", + "stateDiff": null, + "trace": [ + { + "action": { + "callType": "call", + "from": "0xfe3b557e8fb62b89f4916b721be55ceb828dbd73", + "gas": "0xffaaaa", + "input": "0x000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x8fa", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xfba917", + "input": "0x00000000000000000000000000400000000000000000000000000000000000000000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x5ff", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [ + 0 + ], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xf7b790", + "input": "0x0000000000000000000000000030000000000000000000000000000000000000f000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0040000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x30a", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 1, + "traceAddress": [ + 0, + 0 + ], + "type": "call" + }, + { + "action": { + "callType": "call", + "from": "0x0040000000000000000000000000000000000000", + "gas": "0xf3d5d5", + "input": "0xf000000000000000000000000000000000000000000000000000000000000001", + "to": "0x0030000000000000000000000000000000000000", + "value": "0x0" + }, + "result": { + "gasUsed": "0x1b", + "output": "0xf000000000000000000000000000000000000000000000000000000000000002" + }, + "subtraces": 0, + "traceAddress": [ + 0, + 0, + 0 + ], + "type": "call" + } + ], + "transactionHash": "0x4af0ef28fbfcbdee7cc5925797c1b9030b3848c2f63f92737c3fe76b45582af5", + "vmTrace": null + } + ], + "id": 415 + }, + "statusCode": 200 +} From 8f1ae065180c7760ebfee4aa760aca957311d43f Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Mon, 9 Sep 2019 09:26:04 +0200 Subject: [PATCH 48/56] debug jenkins --- .../jsonrpc/AbstractJsonRpcHttpBySpecTest.java | 10 ++++++++-- .../ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java | 11 +++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java index 2440c8df4d..975f1cdc48 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java @@ -42,10 +42,12 @@ public abstract class AbstractJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpServiceTest { private static ObjectMapper objectMapper = new ObjectMapper(); + private final String specName; private final URL specURL; public AbstractJsonRpcHttpBySpecTest(final String specName, final URL specURL) { this.specURL = specURL; + this.specName = specName; } @Test @@ -102,7 +104,10 @@ private void jsonRPCCall(final URL specFile) throws IOException { final String json = Resources.toString(specFile, Charsets.UTF_8); final ObjectNode specNode = (ObjectNode) objectMapper.readTree(json); + System.out.println("********************************************"); + System.out.printf("Test: %s%n", specName); final String rawRequestBody = specNode.get("request").toString(); + System.out.printf("Raw request body: %s%n", rawRequestBody); final RequestBody requestBody = RequestBody.create(JSON, rawRequestBody); final Request request = new Request.Builder().post(requestBody).url(baseUrl).build(); @@ -135,8 +140,8 @@ private void jsonRPCCall(final URL specFile) throws IOException { final String expectedResult = expectedResponse.get("result").toString(); final String actualResult = responseBody.get("result").toString(); final ObjectMapper mapper = new ObjectMapper(); - System.err.println("---" + mapper.readTree(actualResult).toString() + "---"); - System.err.println("+++" + mapper.readTree(expectedResult).toString() + "+++"); + System.err.printf("---%s---%n", mapper.readTree(actualResult).toString()); + System.err.printf("+++%s+++%n", mapper.readTree(expectedResult).toString()); assertThat(mapper.readTree(actualResult)).isEqualTo(mapper.readTree(expectedResult)); } @@ -148,5 +153,6 @@ private void jsonRPCCall(final URL specFile) throws IOException { assertThat(actualError).isEqualToIgnoringWhitespace(expectedError); } } + System.out.println("********************************************"); } } diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java index 6b952f4930..a88b340f9b 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java @@ -23,6 +23,8 @@ import java.net.URL; import java.util.Map; +import com.google.common.base.Charsets; +import com.google.common.io.Resources; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @@ -42,6 +44,15 @@ public void setup() throws Exception { @Override protected BlockchainSetupUtil getBlockchainSetupUtil() { + try { + System.out.printf( + "GENESIS: %s%n", + Resources.toString( + TraceJsonRpcHttpBySpecTest.class.getResource("trace/chain-data/genesis.json"), + Charsets.UTF_8)); + } catch (Exception e) { + System.err.println(e.getMessage()); + } return createBlockchainSetupUtil( "trace/chain-data/genesis.json", "trace/chain-data/blocks.bin"); } From c3d41e11153d7184afdf0be1b3f9437dafd6131b Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Mon, 9 Sep 2019 09:46:37 +0200 Subject: [PATCH 49/56] out instead of err --- .../ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java | 4 ++-- .../ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java | 9 --------- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java index 975f1cdc48..67799c034b 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java @@ -140,8 +140,8 @@ private void jsonRPCCall(final URL specFile) throws IOException { final String expectedResult = expectedResponse.get("result").toString(); final String actualResult = responseBody.get("result").toString(); final ObjectMapper mapper = new ObjectMapper(); - System.err.printf("---%s---%n", mapper.readTree(actualResult).toString()); - System.err.printf("+++%s+++%n", mapper.readTree(expectedResult).toString()); + System.out.printf("---%s---%n", mapper.readTree(actualResult).toString()); + System.out.printf("+++%s+++%n", mapper.readTree(expectedResult).toString()); assertThat(mapper.readTree(actualResult)).isEqualTo(mapper.readTree(expectedResult)); } diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java index a88b340f9b..cd330a2177 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java @@ -44,15 +44,6 @@ public void setup() throws Exception { @Override protected BlockchainSetupUtil getBlockchainSetupUtil() { - try { - System.out.printf( - "GENESIS: %s%n", - Resources.toString( - TraceJsonRpcHttpBySpecTest.class.getResource("trace/chain-data/genesis.json"), - Charsets.UTF_8)); - } catch (Exception e) { - System.err.println(e.getMessage()); - } return createBlockchainSetupUtil( "trace/chain-data/genesis.json", "trace/chain-data/blocks.bin"); } From eb52fb6f0dd37727c3140158832bcb1f10b1db3d Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Mon, 9 Sep 2019 09:58:51 +0200 Subject: [PATCH 50/56] spotless apply --- .../pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java index cd330a2177..6b952f4930 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/TraceJsonRpcHttpBySpecTest.java @@ -23,8 +23,6 @@ import java.net.URL; import java.util.Map; -import com.google.common.base.Charsets; -import com.google.common.io.Resources; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; From dddf2d32aff5ff9d2172d5df1d057f126489dc4d Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Mon, 9 Sep 2019 15:29:23 +0200 Subject: [PATCH 51/56] add debug info --- .../AbstractJsonRpcHttpBySpecTest.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java index 67799c034b..5b9964822e 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java @@ -28,6 +28,7 @@ import java.util.stream.Stream; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Charsets; import com.google.common.io.Resources; @@ -106,6 +107,25 @@ private void jsonRPCCall(final URL specFile) throws IOException { System.out.println("********************************************"); System.out.printf("Test: %s%n", specName); + System.out.printf( + "Chain head hash: %s%n", + blockchainSetupUtil.getBlockchain().getChainHeadHash().getHexString()); + System.out.printf( + "Genesis: %s%n", blockchainSetupUtil.getBlockchain().getGenesisBlock().toString()); + final String blockString = ((ArrayNode) specNode.get("request").get("params")).get(0).asText(); + if (!blockString.equals("pending") + && !blockString.equals("earliest") + && !blockString.equals("latest") + && !(blockString.length() > 4)) { + System.out.printf( + "Bloc: %s%n", + blockchainSetupUtil + .getBlockchain() + .getBlockHashByNumber(Integer.parseInt(blockString.substring(2), 16)) + .orElseThrow() + .toString()); + } + final String rawRequestBody = specNode.get("request").toString(); System.out.printf("Raw request body: %s%n", rawRequestBody); final RequestBody requestBody = RequestBody.create(JSON, rawRequestBody); From f1d9ba7e620ce251d42d24747d893a31a56229b9 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Mon, 9 Sep 2019 16:55:26 +0200 Subject: [PATCH 52/56] remove static modifier for blockchainSetupUtil field --- .../AbstractJsonRpcHttpBySpecTest.java | 27 ------------------- .../AbstractJsonRpcHttpServiceTest.java | 8 +----- 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java index 5b9964822e..d4044bef33 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java @@ -28,7 +28,6 @@ import java.util.stream.Stream; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.base.Charsets; import com.google.common.io.Resources; @@ -104,30 +103,7 @@ private static Object[] fileToParams(final File file) { private void jsonRPCCall(final URL specFile) throws IOException { final String json = Resources.toString(specFile, Charsets.UTF_8); final ObjectNode specNode = (ObjectNode) objectMapper.readTree(json); - - System.out.println("********************************************"); - System.out.printf("Test: %s%n", specName); - System.out.printf( - "Chain head hash: %s%n", - blockchainSetupUtil.getBlockchain().getChainHeadHash().getHexString()); - System.out.printf( - "Genesis: %s%n", blockchainSetupUtil.getBlockchain().getGenesisBlock().toString()); - final String blockString = ((ArrayNode) specNode.get("request").get("params")).get(0).asText(); - if (!blockString.equals("pending") - && !blockString.equals("earliest") - && !blockString.equals("latest") - && !(blockString.length() > 4)) { - System.out.printf( - "Bloc: %s%n", - blockchainSetupUtil - .getBlockchain() - .getBlockHashByNumber(Integer.parseInt(blockString.substring(2), 16)) - .orElseThrow() - .toString()); - } - final String rawRequestBody = specNode.get("request").toString(); - System.out.printf("Raw request body: %s%n", rawRequestBody); final RequestBody requestBody = RequestBody.create(JSON, rawRequestBody); final Request request = new Request.Builder().post(requestBody).url(baseUrl).build(); @@ -160,8 +136,6 @@ private void jsonRPCCall(final URL specFile) throws IOException { final String expectedResult = expectedResponse.get("result").toString(); final String actualResult = responseBody.get("result").toString(); final ObjectMapper mapper = new ObjectMapper(); - System.out.printf("---%s---%n", mapper.readTree(actualResult).toString()); - System.out.printf("+++%s+++%n", mapper.readTree(expectedResult).toString()); assertThat(mapper.readTree(actualResult)).isEqualTo(mapper.readTree(expectedResult)); } @@ -173,6 +147,5 @@ private void jsonRPCCall(final URL specFile) throws IOException { assertThat(actualError).isEqualToIgnoringWhitespace(expectedError); } } - System.out.println("********************************************"); } } diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpServiceTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpServiceTest.java index 9a948416fc..6e3bc0a899 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpServiceTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpServiceTest.java @@ -63,8 +63,7 @@ public abstract class AbstractJsonRpcHttpServiceTest { @ClassRule public static final TemporaryFolder folder = new TemporaryFolder(); - protected static BlockchainSetupUtil blockchainSetupUtil; - private static boolean blockchainInitialized = false; + protected BlockchainSetupUtil blockchainSetupUtil; protected static String CLIENT_VERSION = "TestClientVersion/0.1.0"; protected static final BigInteger NETWORK_ID = BigInteger.valueOf(123); @@ -79,11 +78,6 @@ public abstract class AbstractJsonRpcHttpServiceTest { protected FilterManager filterManager; private void setupBlockchain() { - if (blockchainInitialized) { - return; - } - - blockchainInitialized = true; blockchainSetupUtil = getBlockchainSetupUtil(); blockchainSetupUtil.importAllBlocks(); } From efa3337b38cb23a467b053d1546d5f6cc93c3301 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Mon, 9 Sep 2019 17:04:56 +0200 Subject: [PATCH 53/56] remove unused field --- .../ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java index d4044bef33..d23a0236ae 100644 --- a/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java +++ b/ethereum/jsonrpc/src/test/java/tech/pegasys/pantheon/ethereum/jsonrpc/AbstractJsonRpcHttpBySpecTest.java @@ -42,12 +42,10 @@ public abstract class AbstractJsonRpcHttpBySpecTest extends AbstractJsonRpcHttpServiceTest { private static ObjectMapper objectMapper = new ObjectMapper(); - private final String specName; private final URL specURL; public AbstractJsonRpcHttpBySpecTest(final String specName, final URL specURL) { this.specURL = specURL; - this.specName = specName; } @Test From 74ff428c1993329e86db7c80d92d904f87dabaa8 Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Mon, 9 Sep 2019 17:19:40 +0200 Subject: [PATCH 54/56] add javadoc for gasCalculator parameter --- .../jsonrpc/internal/results/tracing/FlatTraceGenerator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index 6ea50784e6..7178c2b7a7 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -46,6 +46,7 @@ public class FlatTraceGenerator { * * @param transactionTrace the {@link TransactionTrace} to use * @param traceCounter the current trace counter value + * @param gasCalculator the {@link GasCalculator} to use * @return a stream of generated traces {@link Trace} */ public static Stream generateFromTransactionTrace( From 4888adee8d0847e25a73f81ba95e2ec4d1eda52d Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 10 Sep 2019 09:17:13 +0200 Subject: [PATCH 55/56] fix PR review comments --- .../methods/TraceReplayBlockTransactions.java | 4 +- .../internal/results/tracing/Action.java | 77 +++++---------- .../internal/results/tracing/FlatTrace.java | 82 +++++++--------- .../results/tracing/FlatTraceGenerator.java | 95 +++++++++---------- .../internal/results/tracing/Result.java | 34 +++---- .../internal/results/tracing/Trace.java | 7 +- .../internal/results/tracing/TraceWriter.java | 18 ++++ 7 files changed, 135 insertions(+), 182 deletions(-) create mode 100644 ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceWriter.java diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java index 1d09b624ef..34188be010 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/methods/TraceReplayBlockTransactions.java @@ -26,8 +26,8 @@ import tech.pegasys.pantheon.ethereum.jsonrpc.internal.processor.TransactionTrace; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.queries.BlockchainQueries; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.FlatTraceGenerator; -import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.Trace; import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.TraceFormatter; +import tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing.TraceWriter; import tech.pegasys.pantheon.ethereum.mainnet.ProtocolSchedule; import tech.pegasys.pantheon.ethereum.vm.DebugOperationTracer; @@ -142,7 +142,7 @@ private JsonNode formatTraces( private void formatTraces( final long blockNumber, - final Trace.ResultWriter writer, + final TraceWriter writer, final List traces, final TraceFormatter formatter, final AtomicInteger traceCounter) { diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java index 89c62d9850..6314a7519c 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Action.java @@ -43,6 +43,29 @@ public class Action { private String balance; private String refundAddress; + private Action( + final String callType, + final String from, + final String gas, + final String input, + final String to, + final String init, + final String value, + final String address, + final String balance, + final String refundAddress) { + this.callType = callType; + this.from = from; + this.gas = gas; + this.input = input; + this.to = to; + this.init = init; + this.value = value; + this.address = address; + this.balance = balance; + this.refundAddress = refundAddress; + } + public static Builder builder() { return new Builder(); } @@ -86,82 +109,42 @@ public String getCallType() { return callType; } - public void setCallType(final String callType) { - this.callType = callType; - } - public String getFrom() { return from; } - public void setFrom(final String from) { - this.from = from; - } - public String getGas() { return gas; } - public void setGas(final String gas) { - this.gas = gas; - } - public String getInput() { return input; } - public void setInput(final String input) { - this.input = input; - } - public String getTo() { return to; } - public void setTo(final String to) { - this.to = to; - } - public String getValue() { return value; } - public void setValue(final String value) { - this.value = value; - } - public String getInit() { return init; } - public void setInit(final String init) { - this.init = init; - } - public String getAddress() { return address; } - public void setAddress(final String address) { - this.address = address; - } - public String getBalance() { return balance; } - public void setBalance(final String balance) { - this.balance = balance; - } - public String getRefundAddress() { return refundAddress; } - public void setRefundAddress(final String refundAddress) { - this.refundAddress = refundAddress; - } - public static final class Builder { private String callType; private String from; @@ -253,18 +236,8 @@ public String getGas() { } public Action build() { - final Action action = new Action(); - action.setCallType(callType); - action.setFrom(from); - action.setGas(gas); - action.setInput(input); - action.setTo(to); - action.setInit(init); - action.setValue(value); - action.setAddress(address); - action.setRefundAddress(refundAddress); - action.setBalance(balance); - return action; + return new Action( + callType, from, gas, input, to, init, value, address, balance, refundAddress); } } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java index da3e91ba0d..f9cd7389aa 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTrace.java @@ -16,15 +16,41 @@ import java.util.ArrayList; import java.util.List; -import java.util.Optional; public class FlatTrace implements Trace { private Action action; private Result result; private int subtraces; - private List traceAddress = new ArrayList<>(); + private List traceAddress; private String type; + private FlatTrace( + final Action.Builder actionBuilder, + final Result.Builder resultBuilder, + final int subtraces, + final List traceAddress, + final String type) { + this( + actionBuilder != null ? actionBuilder.build() : null, + resultBuilder != null ? resultBuilder.build() : null, + subtraces, + traceAddress, + type); + } + + private FlatTrace( + final Action action, + final Result result, + final int subtraces, + final List traceAddress, + final String type) { + this.action = action; + this.result = result; + this.subtraces = subtraces; + this.traceAddress = traceAddress; + this.type = type; + } + public static Builder freshBuilder(final TransactionTrace transactionTrace) { return FlatTrace.builder() .resultBuilder(Result.builder()) @@ -35,42 +61,22 @@ public Action getAction() { return action; } - public void setAction(final Action action) { - this.action = action; - } - public Result getResult() { return result; } - public void setResult(final Result result) { - this.result = result; - } - public int getSubtraces() { return subtraces; } - public void setSubtraces(final int subtraces) { - this.subtraces = subtraces; - } - public List getTraceAddress() { return traceAddress; } - public void setTraceAddress(final List traceAddress) { - this.traceAddress = traceAddress; - } - public String getType() { return type; } - public void setType(final String type) { - this.type = type; - } - public static Builder builder() { return new Builder(); } @@ -113,28 +119,22 @@ public void markAsReturned() { } public static final class Builder { - private Action action; - private Optional actionBuilder = Optional.empty(); - private Optional resultBuilder = Optional.empty(); + private Action.Builder actionBuilder; + private Result.Builder resultBuilder; private int subtraces; private List traceAddress = new ArrayList<>(); private String type = "call"; private Builder() {} - public Builder action(final Action action) { - this.action = action; - return this; - } - public Builder resultBuilder(final Result.Builder resultBuilder) { - this.resultBuilder = Optional.ofNullable(resultBuilder); + this.resultBuilder = resultBuilder; return this; } public Builder actionBuilder(final Action.Builder actionBuilder) { - this.actionBuilder = Optional.ofNullable(actionBuilder); + this.actionBuilder = actionBuilder; return this; } @@ -163,26 +163,14 @@ public Builder incSubTraces(final int n) { } public FlatTrace build() { - final FlatTrace flatTrace = new FlatTrace(); - flatTrace.setAction(action); - flatTrace.setAction(actionBuilder.orElseGet(() -> Action.Builder.of(action)).build()); - resultBuilder.ifPresentOrElse( - builder -> flatTrace.setResult(builder.build()), () -> flatTrace.setResult(null)); - flatTrace.setSubtraces(subtraces); - flatTrace.setTraceAddress(traceAddress); - flatTrace.setType(type); - return flatTrace; - } - - public Action getAction() { - return action; + return new FlatTrace(actionBuilder, resultBuilder, subtraces, traceAddress, type); } - public Optional getResultBuilder() { + public Result.Builder getResultBuilder() { return resultBuilder; } - public Optional getActionBuilder() { + public Action.Builder getActionBuilder() { return actionBuilder; } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java index 7178c2b7a7..830d0346ed 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/FlatTraceGenerator.java @@ -70,14 +70,13 @@ public static Stream generateFromTransactionTrace( .getHexString()) : Optional.empty(); // set code field in result node - smartContractCode.ifPresent(firstFlatTraceBuilder.getResultBuilder().orElseThrow()::code); + smartContractCode.ifPresent(firstFlatTraceBuilder.getResultBuilder()::code); // set init field if transaction is a smart contract deployment transactionTrace .getTransaction() .getInit() - .ifPresent( - init -> - firstFlatTraceBuilder.getActionBuilder().orElseThrow().init(init.getHexString())); + .map(BytesValue::getHexString) + .ifPresent(firstFlatTraceBuilder.getActionBuilder()::init); // set to, input and callType fields if not a smart contract transactionTrace .getTransaction() @@ -86,7 +85,6 @@ public static Stream generateFromTransactionTrace( to -> firstFlatTraceBuilder .getActionBuilder() - .orElseThrow() .to(to.toString()) .callType("call") .input( @@ -178,7 +176,6 @@ private static void handleCall( previousContext .getBuilder() .getResultBuilder() - .orElse(Result.builder()) .gasUsed(Gas.of(gasCost).toHexString()); }); tracesContexts.addLast( @@ -193,42 +190,41 @@ private static void handleReturn( final Deque tracesContexts) { final Deque polledContexts = new ArrayDeque<>(); FlatTrace.Context ctx; - boolean continueToPollContexts = true; // find last non returned transactionTrace - while (continueToPollContexts && (ctx = tracesContexts.pollLast()) != null) { + while ((ctx = tracesContexts.pollLast()) != null) { polledContexts.addFirst(ctx); - if (!ctx.isReturned()) { - final FlatTrace.Builder flatTraceBuilder = ctx.getBuilder(); - final Gas gasRemainingAtStartOfTrace = - Gas.fromHexString( - flatTraceBuilder.getActionBuilder().orElse(Action.builder()).getGas()); - final Gas gasUsed = gasRemainingAtStartOfTrace.minus(traceFrame.getGasRemaining()); - final Result.Builder resultBuilder = - flatTraceBuilder.getResultBuilder().orElse(Result.builder()); - final Gas finalGasUsed; - if (ctx.isSubtrace()) { - finalGasUsed = gasUsed; - } else { - finalGasUsed = computeGasUsed(transactionTrace, gasUsed); - } - - // set gas used for the trace - resultBuilder.gasUsed(finalGasUsed.toHexString()); - // set address and type to create if smart contract deployment - smartContractAddress.ifPresentOrElse( - address -> { - resultBuilder.address(address); - flatTraceBuilder.type("create"); - }, - // set output otherwise - () -> - resultBuilder.output( - traceFrame.getMemory().isPresent() && traceFrame.getMemory().get().length > 0 - ? traceFrame.getMemory().get()[0].toString() - : "0x")); - ctx.markAsReturned(); - continueToPollContexts = false; + // continue until finding a non returned context + if (ctx.isReturned()) { + continue; } + final FlatTrace.Builder flatTraceBuilder = ctx.getBuilder(); + final Gas gasRemainingAtStartOfTrace = + Gas.fromHexString(flatTraceBuilder.getActionBuilder().getGas()); + final Gas gasUsed = gasRemainingAtStartOfTrace.minus(traceFrame.getGasRemaining()); + final Result.Builder resultBuilder = flatTraceBuilder.getResultBuilder(); + final Gas finalGasUsed; + if (ctx.isSubtrace()) { + finalGasUsed = gasUsed; + } else { + finalGasUsed = computeGasUsed(transactionTrace, gasUsed); + } + + // set gas used for the trace + resultBuilder.gasUsed(finalGasUsed.toHexString()); + // set address and type to create if smart contract deployment + smartContractAddress.ifPresentOrElse( + address -> { + resultBuilder.address(address); + flatTraceBuilder.type("create"); + }, + // set output otherwise + () -> + resultBuilder.output( + traceFrame.getMemory().isPresent() && traceFrame.getMemory().get().length > 0 + ? traceFrame.getMemory().get()[0].toString() + : "0x")); + ctx.markAsReturned(); + break; } // reinsert polled contexts add the end of the queue polledContexts.forEach(tracesContexts::addLast); @@ -258,20 +254,15 @@ private static void handleSelfDestruct( final long gasCost = cumulativeGasCost.longValue(); // retrieve the previous transactionTrace context - Optional.ofNullable(tracesContexts.peekLast()) - .ifPresent( - previousContext -> { - // increment sub traces counter of previous transactionTrace - previousContext.getBuilder().incSubTraces(); - // set gas cost of previous transactionTrace - previousContext - .getBuilder() - .getResultBuilder() - .orElse(Result.builder()) - .gasUsed(Gas.of(gasCost).toHexString()); - }); + if (!tracesContexts.isEmpty()) { + FlatTrace.Context previousContext = tracesContexts.peekLast(); + // increment sub traces counter of previous transactionTrace + previousContext.getBuilder().incSubTraces(); + // set gas cost of previous transactionTrace + previousContext.getBuilder().getResultBuilder().gasUsed(Gas.of(gasCost).toHexString()); + } tracesContexts.addLast( - new FlatTrace.Context(subTraceBuilder.action(subTraceActionBuilder.build()))); + new FlatTrace.Context(subTraceBuilder.actionBuilder(subTraceActionBuilder))); cumulativeGasCost.set(0); } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java index 0e8e47a469..d2780b1982 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Result.java @@ -21,40 +21,33 @@ public class Result { private String gasUsed; private String output; private String code; + + public Result( + final String gasUsed, final String output, final String code, final String address) { + this.gasUsed = gasUsed; + this.output = output; + this.code = code; + this.address = address; + } + private String address; public String getGasUsed() { return gasUsed; } - public void setGasUsed(final String gasUsed) { - this.gasUsed = gasUsed; - } - public String getOutput() { return output; } - public void setOutput(final String output) { - this.output = output; - } - public String getCode() { return code; } - public void setCode(final String code) { - this.code = code; - } - public String getAddress() { return address; } - public void setAddress(final String address) { - this.address = address; - } - public static Builder builder() { return new Builder(); } @@ -91,8 +84,8 @@ public Builder address(final String address) { public static Builder of(final Result result) { final Builder builder = new Builder(); if (result != null) { - builder.output = result.output; builder.gasUsed = result.gasUsed; + builder.output = result.output; builder.code = result.code; builder.address = result.address; } @@ -100,12 +93,7 @@ public static Builder of(final Result result) { } public Result build() { - Result result = new Result(); - result.setGasUsed(gasUsed); - result.setOutput(output); - result.setCode(code); - result.setAddress(address); - return result; + return new Result(gasUsed, output, code, address); } } } diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java index 45c26659f1..fe6a004ed2 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java @@ -12,9 +12,4 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; -public interface Trace { - @FunctionalInterface - interface ResultWriter { - void write(Trace trace); - } -} +public interface Trace {} diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceWriter.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceWriter.java new file mode 100644 index 0000000000..2abbb03819 --- /dev/null +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/TraceWriter.java @@ -0,0 +1,18 @@ +/* + * Copyright 2019 ConsenSys AG. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on + * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; + +@FunctionalInterface +public interface TraceWriter { + void write(Trace trace); +} From dfb404b13f1ae67119bb9d1350b76f580e19658f Mon Sep 17 00:00:00 2001 From: Abdelhamid Bakhta Date: Tue, 10 Sep 2019 17:12:11 +0200 Subject: [PATCH 56/56] add javadoc for Trace interface --- .../jsonrpc/internal/results/tracing/Trace.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java index fe6a004ed2..889117b444 100644 --- a/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java +++ b/ethereum/jsonrpc/src/main/java/tech/pegasys/pantheon/ethereum/jsonrpc/internal/results/tracing/Trace.java @@ -12,4 +12,15 @@ */ package tech.pegasys.pantheon.ethereum.jsonrpc.internal.results.tracing; +/** + * Trace is a marker interface representing different types of Parity style JSON responses for the + * trace_replayBlockTransactions RPC API. trace_replayBlockTransactions is part of the trace RPC API + * group. 3 implementations: + * + *
    + *
  • trace: {@link FlatTrace} + *
  • vmTrace: + *
  • stateDiff: + *
+ */ public interface Trace {}