You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tuweni.apache.org by to...@apache.org on 2020/02/07 04:33:05 UTC
[incubator-tuweni] branch master updated: Ethstats (#44)
This is an automated email from the ASF dual-hosted git repository.
toulmean pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-tuweni.git
The following commit(s) were added to refs/heads/master by this push:
new db62865 Ethstats (#44)
db62865 is described below
commit db6286567367484067647e8a4083053b33397334
Author: Antoine Toulme <at...@users.noreply.github.com>
AuthorDate: Thu Feb 6 20:32:57 2020 -0800
Ethstats (#44)
* Start work on ethstats client module
* add build
* wip
* Functional ethstats interface
* use getter syntax for eth object fields
* Fix JSON test
---
.../tuweni/eth/reference/BlockRLPTestSuite.java | 4 +-
.../tuweni/eth/reference/TransactionTestSuite.java | 10 +-
.../tuweni/eth/repository/BlockchainIndex.kt | 40 +--
.../tuweni/eth/repository/BlockchainRepository.kt | 14 +-
.../tuweni/eth/repository/BlockchainIndexTest.kt | 71 ++---
.../eth/repository/BlockchainRepositoryTest.kt | 58 ++--
eth/build.gradle | 1 +
eth/src/main/java/org/apache/tuweni/eth/Block.java | 4 +-
.../main/java/org/apache/tuweni/eth/BlockBody.java | 4 +-
.../java/org/apache/tuweni/eth/BlockHeader.java | 49 ++--
.../java/org/apache/tuweni/eth/EthJsonModule.java | 109 ++++++++
eth/src/main/java/org/apache/tuweni/eth/Log.java | 6 +-
.../org/apache/tuweni/eth/LogsBloomFilter.java | 4 +-
.../java/org/apache/tuweni/eth/Transaction.java | 20 +-
.../org/apache/tuweni/eth/TransactionReceipt.java | 10 +-
.../org/apache/tuweni/eth/EthJsonModuleTest.java} | 26 +-
.../org/apache/tuweni/eth/TransactionTest.java | 4 +-
{eth => ethstats}/build.gradle | 17 +-
.../org/apache/tuweni/ethstats/AuthMessage.java | 38 ++-
.../org/apache/tuweni/ethstats/BlockStats.java | 135 ++++++++++
.../apache/tuweni/ethstats/EthStatsReporter.java | 297 +++++++++++++++++++++
.../java/org/apache/tuweni/ethstats/NodeInfo.java | 91 +++++++
.../java/org/apache/tuweni/ethstats/NodeStats.java | 78 ++++++
.../java/org/apache/tuweni/ethstats/TxStats.java | 26 +-
.../tuweni/ethstats/EthStatsReporterTest.java | 129 +++++++++
.../org/apache/tuweni/les/LESSubProtocolHandler.kt | 10 +-
.../apache/tuweni/les/LESSubProtocolHandlerTest.kt | 4 +-
settings.gradle | 1 +
28 files changed, 1074 insertions(+), 186 deletions(-)
diff --git a/eth-reference-tests/src/test/java/org/apache/tuweni/eth/reference/BlockRLPTestSuite.java b/eth-reference-tests/src/test/java/org/apache/tuweni/eth/reference/BlockRLPTestSuite.java
index 5dad3d0..44748af 100644
--- a/eth-reference-tests/src/test/java/org/apache/tuweni/eth/reference/BlockRLPTestSuite.java
+++ b/eth-reference-tests/src/test/java/org/apache/tuweni/eth/reference/BlockRLPTestSuite.java
@@ -58,8 +58,8 @@ class BlockRLPTestSuite {
Block rlpBlock = Block.fromHexString(rlp);
assertEquals(block, rlpBlock);
assertEquals(Bytes.fromHexString(rlp), block.toBytes());
- assertEquals(Hash.fromHexString(hash), block.header().hash());
- assertEquals(Hash.fromHexString(hash), rlpBlock.header().hash());
+ assertEquals(Hash.fromHexString(hash), block.getHeader().getHash());
+ assertEquals(Hash.fromHexString(hash), rlpBlock.getHeader().getHash());
}
@MustBeClosed
diff --git a/eth-reference-tests/src/test/java/org/apache/tuweni/eth/reference/TransactionTestSuite.java b/eth-reference-tests/src/test/java/org/apache/tuweni/eth/reference/TransactionTestSuite.java
index 6f68edc..f013437 100644
--- a/eth-reference-tests/src/test/java/org/apache/tuweni/eth/reference/TransactionTestSuite.java
+++ b/eth-reference-tests/src/test/java/org/apache/tuweni/eth/reference/TransactionTestSuite.java
@@ -58,9 +58,9 @@ class TransactionTestSuite {
private void testValidTransaction(String rlp, String hash, String sender) {
Bytes rlpBytes = Bytes.fromHexString(rlp);
Transaction tx = Transaction.fromBytes(rlpBytes);
- assertEquals(Address.fromBytes(Bytes.fromHexString(sender)), tx.sender());
+ assertEquals(Address.fromBytes(Bytes.fromHexString(sender)), tx.getSender());
assertEquals(rlpBytes, tx.toBytes());
- assertEquals(Bytes.fromHexString(hash), tx.hash().toBytes());
+ assertEquals(Bytes.fromHexString(hash), tx.getHash().toBytes());
}
private void testInvalidTransaction(String rlp, String milestone) {
@@ -78,16 +78,16 @@ class TransactionTestSuite {
return;
}
- if (tx.sender() == null) {
+ if (tx.getSender() == null) {
return;
}
if ("Constantinople".equals(milestone) || "Byzantium".equals(milestone) || "EIP158".equals(milestone)) {
- if (tx.chainId() == null) {
+ if (tx.getChainId() == null) {
return;
}
} else {
- if (tx.chainId() != null) {
+ if (tx.getChainId() != null) {
return;
}
}
diff --git a/eth-repository/src/main/kotlin/org/apache/tuweni/eth/repository/BlockchainIndex.kt b/eth-repository/src/main/kotlin/org/apache/tuweni/eth/repository/BlockchainIndex.kt
index 93067d6..aaa1a87 100644
--- a/eth-repository/src/main/kotlin/org/apache/tuweni/eth/repository/BlockchainIndex.kt
+++ b/eth-repository/src/main/kotlin/org/apache/tuweni/eth/repository/BlockchainIndex.kt
@@ -322,10 +322,10 @@ class BlockchainIndex(private val indexWriter: IndexWriter) : BlockchainIndexWri
override fun indexBlockHeader(blockHeader: BlockHeader) {
val document = mutableListOf<IndexableField>()
- val id = toBytesRef(blockHeader.hash())
+ val id = toBytesRef(blockHeader.getHash())
document.add(StringField("_id", id, Field.Store.YES))
document.add(StringField("_type", "block", Field.Store.NO))
- blockHeader.parentHash()?.let { hash ->
+ blockHeader.getParentHash()?.let { hash ->
val hashRef = toBytesRef(hash)
document += StringField(
PARENT_HASH.fieldName,
@@ -334,26 +334,26 @@ class BlockchainIndex(private val indexWriter: IndexWriter) : BlockchainIndexWri
)
queryBlockDocs(TermQuery(Term("_id", hashRef)), listOf(TOTAL_DIFFICULTY)).firstOrNull()?.let {
it.getField(TOTAL_DIFFICULTY.fieldName)?.let {
- val totalDifficulty = blockHeader.difficulty().add(UInt256.fromBytes(Bytes.wrap(it.binaryValue().bytes)))
+ val totalDifficulty = blockHeader.getDifficulty().add(UInt256.fromBytes(Bytes.wrap(it.binaryValue().bytes)))
val diffBytes = toBytesRef(totalDifficulty.toBytes())
document += StringField(TOTAL_DIFFICULTY.fieldName, diffBytes, Field.Store.YES)
document += SortedDocValuesField(TOTAL_DIFFICULTY.fieldName, diffBytes)
}
}
} ?: run {
- val diffBytes = toBytesRef(blockHeader.difficulty().toBytes())
+ val diffBytes = toBytesRef(blockHeader.getDifficulty().toBytes())
document += StringField(TOTAL_DIFFICULTY.fieldName, diffBytes, Field.Store.YES)
document += SortedDocValuesField(TOTAL_DIFFICULTY.fieldName, diffBytes)
}
- document += StringField(OMMERS_HASH.fieldName, toBytesRef(blockHeader.ommersHash()), Field.Store.NO)
- document += StringField(COINBASE.fieldName, toBytesRef(blockHeader.coinbase()), Field.Store.NO)
- document += StringField(STATE_ROOT.fieldName, toBytesRef(blockHeader.stateRoot()), Field.Store.NO)
- document += StringField(DIFFICULTY.fieldName, toBytesRef(blockHeader.difficulty()), Field.Store.NO)
- document += StringField(NUMBER.fieldName, toBytesRef(blockHeader.number()), Field.Store.NO)
- document += StringField(GAS_LIMIT.fieldName, toBytesRef(blockHeader.gasLimit()), Field.Store.NO)
- document += StringField(GAS_USED.fieldName, toBytesRef(blockHeader.gasUsed()), Field.Store.NO)
- document += StringField(EXTRA_DATA.fieldName, toBytesRef(blockHeader.extraData()), Field.Store.NO)
- document += NumericDocValuesField(TIMESTAMP.fieldName, blockHeader.timestamp().toEpochMilli())
+ document += StringField(OMMERS_HASH.fieldName, toBytesRef(blockHeader.getOmmersHash()), Field.Store.NO)
+ document += StringField(COINBASE.fieldName, toBytesRef(blockHeader.getCoinbase()), Field.Store.NO)
+ document += StringField(STATE_ROOT.fieldName, toBytesRef(blockHeader.getStateRoot()), Field.Store.NO)
+ document += StringField(DIFFICULTY.fieldName, toBytesRef(blockHeader.getDifficulty()), Field.Store.NO)
+ document += StringField(NUMBER.fieldName, toBytesRef(blockHeader.getNumber()), Field.Store.NO)
+ document += StringField(GAS_LIMIT.fieldName, toBytesRef(blockHeader.getGasLimit()), Field.Store.NO)
+ document += StringField(GAS_USED.fieldName, toBytesRef(blockHeader.getGasUsed()), Field.Store.NO)
+ document += StringField(EXTRA_DATA.fieldName, toBytesRef(blockHeader.getExtraData()), Field.Store.NO)
+ document += NumericDocValuesField(TIMESTAMP.fieldName, blockHeader.getTimestamp().toEpochMilli())
try {
indexWriter.updateDocument(Term("_id", id), document)
@@ -372,20 +372,20 @@ class BlockchainIndex(private val indexWriter: IndexWriter) : BlockchainIndexWri
document += StringField(TransactionReceiptFields.TRANSACTION_HASH.fieldName, id, Field.Store.NO)
document += StringField(TransactionReceiptFields.BLOCK_HASH.fieldName, toBytesRef(blockHash.toBytes()),
Field.Store.NO)
- for (log in txReceipt.logs()) {
- document += StringField(TransactionReceiptFields.LOGGER.fieldName, toBytesRef(log.logger()), Field.Store.NO)
- for (logTopic in log.topics()) {
+ for (log in txReceipt.getLogs()) {
+ document += StringField(TransactionReceiptFields.LOGGER.fieldName, toBytesRef(log.getLogger()), Field.Store.NO)
+ for (logTopic in log.getTopics()) {
document += StringField(TransactionReceiptFields.LOG_TOPIC.fieldName, toBytesRef(logTopic), Field.Store.NO)
}
}
- txReceipt.stateRoot()?.let {
+ txReceipt.getStateRoot()?.let {
document += StringField(TransactionReceiptFields.STATE_ROOT.fieldName, toBytesRef(it), Field.Store.NO)
}
document += StringField(TransactionReceiptFields.BLOOM_FILTER.fieldName,
- toBytesRef(txReceipt.bloomFilter().toBytes()), Field.Store.NO)
+ toBytesRef(txReceipt.getBloomFilter().toBytes()), Field.Store.NO)
document += NumericDocValuesField(TransactionReceiptFields.CUMULATIVE_GAS_USED.fieldName,
- txReceipt.cumulativeGasUsed())
- txReceipt.status()?.let {
+ txReceipt.getCumulativeGasUsed())
+ txReceipt.getStatus()?.let {
document += NumericDocValuesField(TransactionReceiptFields.STATUS.fieldName, it.toLong())
}
diff --git a/eth-repository/src/main/kotlin/org/apache/tuweni/eth/repository/BlockchainRepository.kt b/eth-repository/src/main/kotlin/org/apache/tuweni/eth/repository/BlockchainRepository.kt
index 1012256..b7c478e 100644
--- a/eth-repository/src/main/kotlin/org/apache/tuweni/eth/repository/BlockchainRepository.kt
+++ b/eth-repository/src/main/kotlin/org/apache/tuweni/eth/repository/BlockchainRepository.kt
@@ -93,9 +93,9 @@ class BlockchainRepository
* @return a handle to the storage operation completion
*/
suspend fun storeBlock(block: Block) {
- storeBlockBody(block.header().hash(), block.body())
- blockHeaderStore.put(block.header().hash().toBytes(), block.header().toBytes())
- indexBlockHeader(block.header())
+ storeBlockBody(block.getHeader().getHash(), block.getBody())
+ blockHeaderStore.put(block.getHeader().getHash().toBytes(), block.getHeader().toBytes())
+ indexBlockHeader(block.getHeader())
}
/**
@@ -138,13 +138,13 @@ class BlockchainRepository
* @return handle to the storage operation completion
*/
suspend fun storeBlockHeader(header: BlockHeader) {
- blockHeaderStore.put(header.hash().toBytes(), header.toBytes())
+ blockHeaderStore.put(header.getHash().toBytes(), header.toBytes())
indexBlockHeader(header)
}
private suspend fun indexBlockHeader(header: BlockHeader) {
blockchainIndex.index { writer -> writer.indexBlockHeader(header) }
- for (hash in findBlocksByParentHash(header.hash())) {
+ for (hash in findBlocksByParentHash(header.getHash())) {
blockHeaderStore.get(hash.toBytes())?.let { bytes ->
indexBlockHeader(BlockHeader.fromBytes(bytes))
}
@@ -282,7 +282,7 @@ class BlockchainRepository
*/
suspend fun retrieveChainHeadHeader(): BlockHeader? {
return blockchainIndex.findByLargest(BlockHeaderFields.TOTAL_DIFFICULTY)
- ?.let { retrieveBlockHeader(it) } ?: retrieveGenesisBlock()?.header()
+ ?.let { retrieveBlockHeader(it) } ?: retrieveGenesisBlock()?.getHeader()
}
/**
@@ -347,6 +347,6 @@ class BlockchainRepository
private suspend fun setGenesisBlock(block: Block) {
return chainMetadata
- .put(GENESIS_BLOCK, block.header().hash().toBytes())
+ .put(GENESIS_BLOCK, block.getHeader().getHash().toBytes())
}
}
diff --git a/eth-repository/src/test/kotlin/org/apache/tuweni/eth/repository/BlockchainIndexTest.kt b/eth-repository/src/test/kotlin/org/apache/tuweni/eth/repository/BlockchainIndexTest.kt
index e2a1dc3..2c245a6 100644
--- a/eth-repository/src/test/kotlin/org/apache/tuweni/eth/repository/BlockchainIndexTest.kt
+++ b/eth-repository/src/test/kotlin/org/apache/tuweni/eth/repository/BlockchainIndexTest.kt
@@ -76,7 +76,7 @@ internal class BlockchainIndexTest {
val reader = DirectoryReader.open(writer)
val searcher = IndexSearcher(reader)
val collector = TopScoreDocCollector.create(10, ScoreDoc(1, 1.0f))
- searcher.search(TermQuery(Term("_id", BytesRef(header.hash().toBytes().toArrayUnsafe()))), collector)
+ searcher.search(TermQuery(Term("_id", BytesRef(header.hash.toBytes().toArrayUnsafe()))), collector)
val hits = collector.topDocs().scoreDocs
assertEquals(1, hits.size)
}
@@ -108,7 +108,7 @@ internal class BlockchainIndexTest {
val reader = DirectoryReader.open(index)
val searcher = IndexSearcher(reader)
val collector = TopScoreDocCollector.create(10, ScoreDoc(1, 1.0f))
- searcher.search(TermQuery(Term("_id", BytesRef(header.hash().toBytes().toArrayUnsafe()))), collector)
+ searcher.search(TermQuery(Term("_id", BytesRef(header.hash.toBytes().toArrayUnsafe()))), collector)
val hits = collector.topDocs().scoreDocs
assertEquals(1, hits.size)
}
@@ -139,75 +139,76 @@ internal class BlockchainIndexTest {
val reader = blockchainIndex as BlockchainIndexReader
run {
- val entries = reader.findBy(BlockHeaderFields.PARENT_HASH, header.parentHash()!!)
+ val entries = reader.findBy(BlockHeaderFields.PARENT_HASH, header.parentHash!!)
assertEquals(1, entries.size)
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
run {
- val entries = reader.findBy(BlockHeaderFields.OMMERS_HASH, header.ommersHash())
+ val entries = reader.findBy(BlockHeaderFields.OMMERS_HASH, header.ommersHash)
assertEquals(1, entries.size)
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
run {
- val entries = reader.findBy(BlockHeaderFields.COINBASE, header.coinbase())
+ val entries = reader.findBy(BlockHeaderFields.COINBASE, header.coinbase)
assertEquals(1, entries.size)
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
run {
- val entries = reader.findBy(BlockHeaderFields.STATE_ROOT, header.stateRoot())
+ val entries = reader.findBy(BlockHeaderFields.STATE_ROOT, header.stateRoot)
assertEquals(1, entries.size)
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
run {
- val entries = reader.findBy(BlockHeaderFields.STATE_ROOT, header.stateRoot())
+ val entries = reader.findBy(BlockHeaderFields.STATE_ROOT, header.stateRoot)
assertEquals(1, entries.size)
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
run {
- val entries = reader.findBy(BlockHeaderFields.DIFFICULTY, header.difficulty())
+ val entries = reader.findBy(BlockHeaderFields.DIFFICULTY, header.difficulty)
assertEquals(1, entries.size)
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
run {
- val entries = reader.findBy(BlockHeaderFields.TIMESTAMP, header.timestamp().toEpochMilli())
+ val entries = reader.findBy(BlockHeaderFields.TIMESTAMP, header.timestamp.toEpochMilli())
assertEquals(1, entries.size)
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
run {
- val entries = reader.findBy(BlockHeaderFields.NUMBER, header.number())
+ val entries = reader.findBy(BlockHeaderFields.NUMBER, header.number)
assertEquals(1, entries.size)
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
run {
- val entries = reader.findInRange(BlockHeaderFields.NUMBER, header.number().subtract(5), header.number().add(5))
+ val entries = reader.findInRange(BlockHeaderFields.NUMBER, header.number.subtract(5),
+ header.number.add(5))
assertEquals(1, entries.size)
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
run {
- val entries = reader.findBy(BlockHeaderFields.EXTRA_DATA, header.extraData())
+ val entries = reader.findBy(BlockHeaderFields.EXTRA_DATA, header.extraData)
assertEquals(1, entries.size)
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
run {
- val entries = reader.findBy(BlockHeaderFields.GAS_LIMIT, header.gasLimit())
+ val entries = reader.findBy(BlockHeaderFields.GAS_LIMIT, header.gasLimit)
assertEquals(1, entries.size, entries.toString())
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
run {
- val entries = reader.findBy(BlockHeaderFields.GAS_USED, header.gasUsed())
+ val entries = reader.findBy(BlockHeaderFields.GAS_USED, header.gasUsed)
assertEquals(1, entries.size)
- assertEquals(header.hash(), entries[0])
+ assertEquals(header.hash, entries[0])
}
}
@@ -232,10 +233,10 @@ internal class BlockchainIndexTest {
Bytes32.random()
)
blockchainIndex.index { w -> w.indexBlockHeader(header) }
- assertEquals(UInt256.valueOf(1), blockchainIndex.totalDifficulty(header.hash()))
+ assertEquals(UInt256.valueOf(1), blockchainIndex.totalDifficulty(header.hash))
val childHeader = BlockHeader(
- header.hash(),
+ header.hash,
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -254,7 +255,7 @@ internal class BlockchainIndexTest {
blockchainIndex.index { w -> w.indexBlockHeader(childHeader) }
- assertEquals(UInt256.valueOf(4), blockchainIndex.totalDifficulty(childHeader.hash()))
+ assertEquals(UInt256.valueOf(4), blockchainIndex.totalDifficulty(childHeader.hash))
}
@Test
@@ -308,37 +309,37 @@ internal class BlockchainIndexTest {
}
run {
- val entries = reader.findBy(TransactionReceiptFields.BLOOM_FILTER, txReceipt.bloomFilter().toBytes())
+ val entries = reader.findBy(TransactionReceiptFields.BLOOM_FILTER, txReceipt.bloomFilter.toBytes())
assertEquals(1, entries.size)
assertEquals(txHash, entries[0])
}
run {
- val entries = reader.findBy(TransactionReceiptFields.STATE_ROOT, txReceipt.stateRoot())
+ val entries = reader.findBy(TransactionReceiptFields.STATE_ROOT, txReceipt.stateRoot)
assertEquals(1, entries.size)
assertEquals(txHash, entries[0])
}
run {
- val entries = reader.findBy(TransactionReceiptFields.LOGGER, txReceipt.logs()[0].logger())
+ val entries = reader.findBy(TransactionReceiptFields.LOGGER, txReceipt.logs[0].logger)
assertEquals(1, entries.size)
assertEquals(txHash, entries[0])
}
run {
- val entries = reader.findBy(TransactionReceiptFields.LOG_TOPIC, txReceipt.logs()[0].topics()[0])
+ val entries = reader.findBy(TransactionReceiptFields.LOG_TOPIC, txReceipt.logs[0].topics[0])
assertEquals(1, entries.size)
assertEquals(txHash, entries[0])
}
run {
- val entries = reader.findBy(TransactionReceiptFields.STATUS, txReceiptWithStatus.status())
+ val entries = reader.findBy(TransactionReceiptFields.STATUS, txReceiptWithStatus.status)
assertEquals(1, entries.size)
assertEquals(txHash2, entries[0])
}
run {
- val entries = reader.findBy(TransactionReceiptFields.CUMULATIVE_GAS_USED, txReceipt.cumulativeGasUsed())
+ val entries = reader.findBy(TransactionReceiptFields.CUMULATIVE_GAS_USED, txReceipt.cumulativeGasUsed)
assertEquals(1, entries.size)
assertEquals(txHash, entries[0])
}
diff --git a/eth-repository/src/test/kotlin/org/apache/tuweni/eth/repository/BlockchainRepositoryTest.kt b/eth-repository/src/test/kotlin/org/apache/tuweni/eth/repository/BlockchainRepositoryTest.kt
index 1b0caf3..08644eb 100644
--- a/eth-repository/src/test/kotlin/org/apache/tuweni/eth/repository/BlockchainRepositoryTest.kt
+++ b/eth-repository/src/test/kotlin/org/apache/tuweni/eth/repository/BlockchainRepositoryTest.kt
@@ -109,9 +109,9 @@ internal class BlockchainRepositoryTest {
)
val block = Block(header, body)
repo.storeBlock(block)
- val read = repo.retrieveBlock(block.header().hash().toBytes())
+ val read = repo.retrieveBlock(block.getHeader().getHash().toBytes())
assertEquals(block, read)
- assertEquals(block.header(), repo.retrieveBlockHeader(block.header().hash()))
+ assertEquals(block.getHeader(), repo.retrieveBlockHeader(block.getHeader().getHash()))
}
@Test
@@ -146,7 +146,7 @@ internal class BlockchainRepositoryTest {
)
val header = BlockHeader(
- genesisHeader.hash(),
+ genesisHeader.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -154,7 +154,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.fromBytes(Bytes32.random()),
- genesisHeader.number().add(UInt256.valueOf(1)),
+ genesisHeader.getNumber().add(UInt256.valueOf(1)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -163,7 +163,7 @@ internal class BlockchainRepositoryTest {
Bytes32.random()
)
val biggerNumber = BlockHeader(
- header.hash(),
+ header.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -171,7 +171,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.fromBytes(Bytes32.random()),
- header.number().add(UInt256.valueOf(1)),
+ header.getNumber().add(UInt256.valueOf(1)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -180,7 +180,7 @@ internal class BlockchainRepositoryTest {
Bytes32.random()
)
val biggerNumber2 = BlockHeader(
- biggerNumber.hash(),
+ biggerNumber.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -188,7 +188,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.fromBytes(Bytes32.random()),
- header.number().add(UInt256.valueOf(2)),
+ header.getNumber().add(UInt256.valueOf(2)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -197,7 +197,7 @@ internal class BlockchainRepositoryTest {
Bytes32.random()
)
val biggerNumber3 = BlockHeader(
- biggerNumber2.hash(),
+ biggerNumber2.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -205,7 +205,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.fromBytes(Bytes32.random()),
- header.number().add(UInt256.valueOf(3)),
+ header.getNumber().add(UInt256.valueOf(3)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -219,7 +219,7 @@ internal class BlockchainRepositoryTest {
repo.storeBlockHeader(biggerNumber2)
repo.storeBlockHeader(biggerNumber3)
- assertEquals(biggerNumber3.hash(), repo.retrieveChainHeadHeader()!!.hash())
+ assertEquals(biggerNumber3.getHash(), repo.retrieveChainHeadHeader()!!.getHash())
}
@Test
@@ -253,7 +253,7 @@ internal class BlockchainRepositoryTest {
)
val header = BlockHeader(
- genesisHeader.hash(),
+ genesisHeader.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -261,7 +261,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.valueOf(1),
- genesisHeader.number().add(UInt256.valueOf(1)),
+ genesisHeader.getNumber().add(UInt256.valueOf(1)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -270,7 +270,7 @@ internal class BlockchainRepositoryTest {
Bytes32.random()
)
val biggerNumber = BlockHeader(
- header.hash(),
+ header.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -278,7 +278,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.valueOf(2),
- header.number().add(UInt256.valueOf(1)),
+ header.getNumber().add(UInt256.valueOf(1)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -287,7 +287,7 @@ internal class BlockchainRepositoryTest {
Bytes32.random()
)
val biggerNumber2 = BlockHeader(
- biggerNumber.hash(),
+ biggerNumber.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -295,7 +295,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.valueOf(3),
- header.number().add(UInt256.valueOf(2)),
+ header.getNumber().add(UInt256.valueOf(2)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -304,7 +304,7 @@ internal class BlockchainRepositoryTest {
Bytes32.random()
)
val biggerNumber3 = BlockHeader(
- biggerNumber2.hash(),
+ biggerNumber2.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -312,7 +312,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.valueOf(4),
- header.number().add(UInt256.valueOf(3)),
+ header.getNumber().add(UInt256.valueOf(3)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -326,7 +326,7 @@ internal class BlockchainRepositoryTest {
repo.storeBlock(Block(biggerNumber2, BlockBody(emptyList(), emptyList())))
repo.storeBlock(Block(biggerNumber3, BlockBody(emptyList(), emptyList())))
- assertEquals(biggerNumber3.hash(), repo.retrieveChainHeadHeader()!!.hash())
+ assertEquals(biggerNumber3.getHash(), repo.retrieveChainHeadHeader()!!.getHash())
}
@Test
@@ -359,7 +359,7 @@ internal class BlockchainRepositoryTest {
)
val header = BlockHeader(
- genesisHeader.hash(),
+ genesisHeader.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -367,7 +367,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.valueOf(1),
- genesisHeader.number().add(UInt256.valueOf(1)),
+ genesisHeader.getNumber().add(UInt256.valueOf(1)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -376,7 +376,7 @@ internal class BlockchainRepositoryTest {
Bytes32.random()
)
val biggerNumber = BlockHeader(
- header.hash(),
+ header.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -384,7 +384,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.valueOf(2),
- header.number().add(UInt256.valueOf(1)),
+ header.getNumber().add(UInt256.valueOf(1)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -393,7 +393,7 @@ internal class BlockchainRepositoryTest {
Bytes32.random()
)
val biggerNumber2 = BlockHeader(
- biggerNumber.hash(),
+ biggerNumber.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -401,7 +401,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.valueOf(3),
- header.number().add(UInt256.valueOf(2)),
+ header.getNumber().add(UInt256.valueOf(2)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -410,7 +410,7 @@ internal class BlockchainRepositoryTest {
Bytes32.random()
)
val biggerNumber3 = BlockHeader(
- biggerNumber2.hash(),
+ biggerNumber2.getHash(),
Hash.fromBytes(Bytes32.random()),
Address.fromBytes(Bytes.random(20)),
Hash.fromBytes(Bytes32.random()),
@@ -418,7 +418,7 @@ internal class BlockchainRepositoryTest {
Hash.fromBytes(Bytes32.random()),
Bytes32.random(),
UInt256.valueOf(4),
- header.number().add(UInt256.valueOf(3)),
+ header.getNumber().add(UInt256.valueOf(3)),
Gas.valueOf(3),
Gas.valueOf(2),
Instant.now().truncatedTo(ChronoUnit.SECONDS),
@@ -432,7 +432,7 @@ internal class BlockchainRepositoryTest {
repo.storeBlock(Block(biggerNumber, BlockBody(emptyList(), emptyList())))
repo.storeBlock(Block(header, BlockBody(emptyList(), emptyList())))
- assertEquals(biggerNumber3.hash(), repo.retrieveChainHeadHeader()!!.hash())
+ assertEquals(biggerNumber3.getHash(), repo.retrieveChainHeadHeader()!!.getHash())
}
@Test
diff --git a/eth/build.gradle b/eth/build.gradle
index b50cbf7..19874ca 100644
--- a/eth/build.gradle
+++ b/eth/build.gradle
@@ -13,6 +13,7 @@
description = 'Classes and utilities for working with Ethereum.'
dependencies {
+ compile 'com.fasterxml.jackson.core:jackson-databind'
compile project(':bytes')
compile project(':crypto')
compile project(':rlp')
diff --git a/eth/src/main/java/org/apache/tuweni/eth/Block.java b/eth/src/main/java/org/apache/tuweni/eth/Block.java
index d399370..24a7201 100644
--- a/eth/src/main/java/org/apache/tuweni/eth/Block.java
+++ b/eth/src/main/java/org/apache/tuweni/eth/Block.java
@@ -82,14 +82,14 @@ public final class Block {
/**
* @return the block body.
*/
- public BlockBody body() {
+ public BlockBody getBody() {
return body;
}
/**
* @return the block header.
*/
- public BlockHeader header() {
+ public BlockHeader getHeader() {
return header;
}
diff --git a/eth/src/main/java/org/apache/tuweni/eth/BlockBody.java b/eth/src/main/java/org/apache/tuweni/eth/BlockBody.java
index 77cf839..ccad1a4 100644
--- a/eth/src/main/java/org/apache/tuweni/eth/BlockBody.java
+++ b/eth/src/main/java/org/apache/tuweni/eth/BlockBody.java
@@ -78,14 +78,14 @@ public final class BlockBody {
/**
* @return the transactions of the block.
*/
- public List<Transaction> transactions() {
+ public List<Transaction> getTransactions() {
return transactions;
}
/**
* @return the list of ommers for this block.
*/
- public List<BlockHeader> ommers() {
+ public List<BlockHeader> getOmmers() {
return ommers;
}
diff --git a/eth/src/main/java/org/apache/tuweni/eth/BlockHeader.java b/eth/src/main/java/org/apache/tuweni/eth/BlockHeader.java
index 118d3de..e430a2f 100644
--- a/eth/src/main/java/org/apache/tuweni/eth/BlockHeader.java
+++ b/eth/src/main/java/org/apache/tuweni/eth/BlockHeader.java
@@ -24,6 +24,7 @@ import org.apache.tuweni.units.ethereum.Gas;
import java.time.Instant;
import javax.annotation.Nullable;
+import com.fasterxml.jackson.annotation.JsonGetter;
import com.google.common.base.Objects;
/**
@@ -155,42 +156,48 @@ public final class BlockHeader {
/**
* @return the block's beneficiary's address.
*/
- public Address coinbase() {
+ @JsonGetter("miner")
+ public Address getCoinbase() {
return coinbase;
}
/**
* @return the difficulty of the block.
*/
- public UInt256 difficulty() {
+ @JsonGetter("difficulty")
+ public UInt256 getDifficulty() {
return difficulty;
}
/**
* @return the extra data stored with the block.
*/
- public Bytes extraData() {
+ @JsonGetter("extraData")
+ public Bytes getExtraData() {
return extraData;
}
/**
* @return the gas limit of the block.
*/
- public Gas gasLimit() {
+ @JsonGetter("gasLimit")
+ public Gas getGasLimit() {
return gasLimit;
}
/**
* @return the gas used for the block.
*/
- public Gas gasUsed() {
+ @JsonGetter("gasUsed")
+ public Gas getGasUsed() {
return gasUsed;
}
/**
* @return the hash of the block header.
*/
- public Hash hash() {
+ @JsonGetter("hash")
+ public Hash getHash() {
if (hash == null) {
Bytes rlp = toBytes();
hash = Hash.hash(rlp);
@@ -201,35 +208,40 @@ public final class BlockHeader {
/**
* @return the bloom filter of the logs of the block.
*/
- public Bytes logsBloom() {
+ @JsonGetter("logsBloom")
+ public Bytes getLogsBloom() {
return logsBloom;
}
/**
* @return the hash associated with computional work on the block.
*/
- public Hash mixHash() {
+ @JsonGetter("mixHash")
+ public Hash getMixHash() {
return mixHash;
}
/**
* @return the nonce of the block.
*/
- public Bytes nonce() {
+ @JsonGetter("nonce")
+ public Bytes getNonce() {
return nonce;
}
/**
* @return the number of the block.
*/
- public UInt256 number() {
+ @JsonGetter("number")
+ public UInt256 getNumber() {
return number;
}
/**
* @return the ommer hash.
*/
- public Hash ommersHash() {
+ @JsonGetter("sha3Uncles")
+ public Hash getOmmersHash() {
return ommersHash;
}
@@ -237,35 +249,40 @@ public final class BlockHeader {
* @return the parent hash, or null if none was available.
*/
@Nullable
- public Hash parentHash() {
+ @JsonGetter("parentHash")
+ public Hash getParentHash() {
return parentHash;
}
/**
* @return the hash associated with the transaction receipts tree.
*/
- public Hash receiptsRoot() {
+ @JsonGetter("receiptsRoot")
+ public Hash getReceiptsRoot() {
return receiptsRoot;
}
/**
* @return the hash associated with the state tree.
*/
- public Hash stateRoot() {
+ @JsonGetter("stateRoot")
+ public Hash getStateRoot() {
return stateRoot;
}
/**
* @return the timestamp of the block.
*/
- public Instant timestamp() {
+ @JsonGetter("timestamp")
+ public Instant getTimestamp() {
return timestamp;
}
/**
* @return the hash associated with the transactions tree.
*/
- public Hash transactionsRoot() {
+ @JsonGetter("transactionsRoot")
+ public Hash getTransactionsRoot() {
return transactionsRoot;
}
diff --git a/eth/src/main/java/org/apache/tuweni/eth/EthJsonModule.java b/eth/src/main/java/org/apache/tuweni/eth/EthJsonModule.java
new file mode 100644
index 0000000..6b0cf39
--- /dev/null
+++ b/eth/src/main/java/org/apache/tuweni/eth/EthJsonModule.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
+ * to You 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 org.apache.tuweni.eth;
+
+import org.apache.tuweni.bytes.Bytes;
+import org.apache.tuweni.units.bigints.UInt256;
+import org.apache.tuweni.units.ethereum.Gas;
+
+import java.io.IOException;
+import java.time.Instant;
+
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.SerializerProvider;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.fasterxml.jackson.databind.ser.std.StdSerializer;
+
+public class EthJsonModule extends SimpleModule {
+
+ static class HashSerializer extends StdSerializer<Hash> {
+
+ HashSerializer() {
+ super(Hash.class);
+ }
+
+ @Override
+ public void serialize(Hash value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeString(value.toHexString());
+ }
+ }
+
+ static class AddressSerializer extends StdSerializer<Address> {
+
+ AddressSerializer() {
+ super(Address.class);
+ }
+
+ @Override
+ public void serialize(Address value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeString(value.toHexString());
+ }
+ }
+
+ static class BytesSerializer extends StdSerializer<Bytes> {
+
+ BytesSerializer() {
+ super(Bytes.class);
+ }
+
+ @Override
+ public void serialize(Bytes value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeString(value.toHexString());
+ }
+ }
+
+ static class GasSerializer extends StdSerializer<Gas> {
+
+ GasSerializer() {
+ super(Gas.class);
+ }
+
+ @Override
+ public void serialize(Gas value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeString(value.toBytes().toHexString());
+ }
+ }
+
+ static class UInt256Serializer extends StdSerializer<UInt256> {
+
+ UInt256Serializer() {
+ super(UInt256.class);
+ }
+
+ @Override
+ public void serialize(UInt256 value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeString(value.toHexString());
+ }
+ }
+
+ static class InstantSerializer extends StdSerializer<Instant> {
+
+ InstantSerializer() {
+ super(Instant.class);
+ }
+
+ @Override
+ public void serialize(Instant value, JsonGenerator gen, SerializerProvider provider) throws IOException {
+ gen.writeNumber(value.toEpochMilli());
+ }
+ }
+
+ public EthJsonModule() {
+ addSerializer(Hash.class, new HashSerializer());
+ addSerializer(Address.class, new AddressSerializer());
+ addSerializer(Bytes.class, new BytesSerializer());
+ addSerializer(Gas.class, new GasSerializer());
+ addSerializer(UInt256.class, new UInt256Serializer());
+ addSerializer(Instant.class, new InstantSerializer());
+ }
+}
diff --git a/eth/src/main/java/org/apache/tuweni/eth/Log.java b/eth/src/main/java/org/apache/tuweni/eth/Log.java
index 9f3ee0e..185053f 100644
--- a/eth/src/main/java/org/apache/tuweni/eth/Log.java
+++ b/eth/src/main/java/org/apache/tuweni/eth/Log.java
@@ -77,7 +77,7 @@ public final class Log {
*
* @return the address of the contract that produced this log.
*/
- public Address logger() {
+ public Address getLogger() {
return logger;
}
@@ -85,7 +85,7 @@ public final class Log {
*
* @return data associated with this log.
*/
- public Bytes data() {
+ public Bytes getData() {
return data;
}
@@ -93,7 +93,7 @@ public final class Log {
*
* @return indexable topics associated with this log.
*/
- public List<Bytes32> topics() {
+ public List<Bytes32> getTopics() {
return topics;
}
diff --git a/eth/src/main/java/org/apache/tuweni/eth/LogsBloomFilter.java b/eth/src/main/java/org/apache/tuweni/eth/LogsBloomFilter.java
index 4779357..8805e31 100644
--- a/eth/src/main/java/org/apache/tuweni/eth/LogsBloomFilter.java
+++ b/eth/src/main/java/org/apache/tuweni/eth/LogsBloomFilter.java
@@ -75,9 +75,9 @@ public final class LogsBloomFilter {
}
public void insertLog(final Log log) {
- setBits(keccak256(log.logger().toBytes()));
+ setBits(keccak256(log.getLogger().toBytes()));
- for (final Bytes32 topic : log.topics()) {
+ for (final Bytes32 topic : log.getTopics()) {
setBits(keccak256(topic));
}
}
diff --git a/eth/src/main/java/org/apache/tuweni/eth/Transaction.java b/eth/src/main/java/org/apache/tuweni/eth/Transaction.java
index 39619a7..8bb3e5b 100644
--- a/eth/src/main/java/org/apache/tuweni/eth/Transaction.java
+++ b/eth/src/main/java/org/apache/tuweni/eth/Transaction.java
@@ -236,21 +236,21 @@ public final class Transaction {
/**
* @return The transaction nonce.
*/
- public UInt256 nonce() {
+ public UInt256 getNonce() {
return nonce;
}
/**
* @return The transaction gas price.
*/
- public Wei gasPrice() {
+ public Wei getGasPrice() {
return gasPrice;
}
/**
* @return The transaction gas limit.
*/
- public Gas gasLimit() {
+ public Gas getGasLimit() {
return gasLimit;
}
@@ -258,7 +258,7 @@ public final class Transaction {
* @return The target contract address, or null if not present.
*/
@Nullable
- public Address to() {
+ public Address getTo() {
return to;
}
@@ -272,21 +272,21 @@ public final class Transaction {
/**
* @return The amount of Eth to transfer.
*/
- public Wei value() {
+ public Wei getValue() {
return value;
}
/**
* @return The transaction signature.
*/
- public SECP256K1.Signature signature() {
+ public SECP256K1.Signature getSignature() {
return signature;
}
/**
* @return The transaction payload.
*/
- public Bytes payload() {
+ public Bytes getPayload() {
return payload;
}
@@ -294,7 +294,7 @@ public final class Transaction {
* @return the chain id of the transaction, or null if no chain id was encoded on the transaction.
* @see <a href="https://github.com/ethereum/EIPs/blob/master/EIPS/eip-155.md">EIP-155</a>
*/
- public Integer chainId() {
+ public Integer getChainId() {
return chainId;
}
@@ -303,7 +303,7 @@ public final class Transaction {
*
* @return The hash.
*/
- public Hash hash() {
+ public Hash getHash() {
if (hash != null) {
return hash;
}
@@ -316,7 +316,7 @@ public final class Transaction {
* @return The sender of the transaction, or {@code null} if the signature is invalid.
*/
@Nullable
- public Address sender() {
+ public Address getSender() {
if (validSignature != null) {
return sender;
}
diff --git a/eth/src/main/java/org/apache/tuweni/eth/TransactionReceipt.java b/eth/src/main/java/org/apache/tuweni/eth/TransactionReceipt.java
index b79f9be..94290cc 100644
--- a/eth/src/main/java/org/apache/tuweni/eth/TransactionReceipt.java
+++ b/eth/src/main/java/org/apache/tuweni/eth/TransactionReceipt.java
@@ -148,7 +148,7 @@ public final class TransactionReceipt {
*
* @return the state root if the transaction receipt is state root-encoded; otherwise {@code null}
*/
- public Bytes32 stateRoot() {
+ public Bytes32 getStateRoot() {
return stateRoot;
}
@@ -157,7 +157,7 @@ public final class TransactionReceipt {
*
* @return the total amount of gas consumed in the block after the transaction has been processed
*/
- public long cumulativeGasUsed() {
+ public long getCumulativeGasUsed() {
return cumulativeGasUsed;
}
@@ -166,7 +166,7 @@ public final class TransactionReceipt {
*
* @return the logs generated by the transaction
*/
- public List<Log> logs() {
+ public List<Log> getLogs() {
return logs;
}
@@ -175,7 +175,7 @@ public final class TransactionReceipt {
*
* @return the logs bloom filter for the logs generated by the transaction
*/
- public LogsBloomFilter bloomFilter() {
+ public LogsBloomFilter getBloomFilter() {
return bloomFilter;
}
@@ -193,7 +193,7 @@ public final class TransactionReceipt {
*
* @return the status code if the transaction receipt is status-encoded; otherwise {@code null}
*/
- public Integer status() {
+ public Integer getStatus() {
return status;
}
diff --git a/eth/build.gradle b/eth/src/test/java/org/apache/tuweni/eth/EthJsonModuleTest.java
similarity index 58%
copy from eth/build.gradle
copy to eth/src/test/java/org/apache/tuweni/eth/EthJsonModuleTest.java
index b50cbf7..c52ab8e 100644
--- a/eth/build.gradle
+++ b/eth/src/test/java/org/apache/tuweni/eth/EthJsonModuleTest.java
@@ -10,18 +10,22 @@
* 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.
*/
-description = 'Classes and utilities for working with Ethereum.'
+package org.apache.tuweni.eth;
-dependencies {
- compile project(':bytes')
- compile project(':crypto')
- compile project(':rlp')
- compile project(':units')
+import org.apache.tuweni.junit.BouncyCastleExtension;
- testCompile project(':junit')
- testCompile 'org.bouncycastle:bcprov-jdk15on'
- testCompile 'org.junit.jupiter:junit-jupiter-api'
- testCompile 'org.junit.jupiter:junit-jupiter-params'
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
- testRuntime 'org.junit.jupiter:junit-jupiter-engine'
+@ExtendWith(BouncyCastleExtension.class)
+class EthJsonModuleTest {
+
+ @Test
+ void testSerialize() throws Exception {
+ BlockHeader header = BlockHeaderTest.generateBlockHeader();
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.registerModule(new EthJsonModule());
+ mapper.writer().writeValueAsString(header);
+ }
}
diff --git a/eth/src/test/java/org/apache/tuweni/eth/TransactionTest.java b/eth/src/test/java/org/apache/tuweni/eth/TransactionTest.java
index 4a0d189..5cc438c 100644
--- a/eth/src/test/java/org/apache/tuweni/eth/TransactionTest.java
+++ b/eth/src/test/java/org/apache/tuweni/eth/TransactionTest.java
@@ -58,7 +58,7 @@ class TransactionTest {
SECP256K1.KeyPair keyPair = SECP256K1.KeyPair.random();
Address sender = Address.fromBytes(Bytes.wrap(keccak256(keyPair.publicKey().bytesArray()), 12, 20));
Transaction tx = generateTransaction(keyPair);
- assertEquals(sender, tx.sender());
+ assertEquals(sender, tx.getSender());
}
@Test
@@ -74,6 +74,6 @@ class TransactionTest {
16 * 16 * 3);
Bytes bytes = tx.toBytes();
Transaction read = Transaction.fromBytes(bytes);
- assertEquals(16 * 16 * 3, (int) read.chainId());
+ assertEquals(16 * 16 * 3, (int) read.getChainId());
}
}
diff --git a/eth/build.gradle b/ethstats/build.gradle
similarity index 75%
copy from eth/build.gradle
copy to ethstats/build.gradle
index b50cbf7..75c99fd 100644
--- a/eth/build.gradle
+++ b/ethstats/build.gradle
@@ -10,18 +10,23 @@
* 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.
*/
-description = 'Classes and utilities for working with Ethereum.'
+
+description = 'ETHStats client library'
+
dependencies {
+ compile 'com.fasterxml.jackson.core:jackson-databind'
+ compile 'com.google.guava:guava'
+ compile 'io.vertx:vertx-core'
+ compile 'org.bouncycastle:bcprov-jdk15on'
+ compile 'org.logl:logl-api'
+ compile 'org.logl:logl-logl'
compile project(':bytes')
- compile project(':crypto')
- compile project(':rlp')
- compile project(':units')
+ compile project(':eth')
+ testCompile project(':bytes')
testCompile project(':junit')
- testCompile 'org.bouncycastle:bcprov-jdk15on'
testCompile 'org.junit.jupiter:junit-jupiter-api'
testCompile 'org.junit.jupiter:junit-jupiter-params'
-
testRuntime 'org.junit.jupiter:junit-jupiter-engine'
}
diff --git a/eth/build.gradle b/ethstats/src/main/java/org/apache/tuweni/ethstats/AuthMessage.java
similarity index 58%
copy from eth/build.gradle
copy to ethstats/src/main/java/org/apache/tuweni/ethstats/AuthMessage.java
index b50cbf7..f1561aa 100644
--- a/eth/build.gradle
+++ b/ethstats/src/main/java/org/apache/tuweni/ethstats/AuthMessage.java
@@ -10,18 +10,34 @@
* 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.
*/
-description = 'Classes and utilities for working with Ethereum.'
+package org.apache.tuweni.ethstats;
-dependencies {
- compile project(':bytes')
- compile project(':crypto')
- compile project(':rlp')
- compile project(':units')
+import com.fasterxml.jackson.annotation.JsonGetter;
- testCompile project(':junit')
- testCompile 'org.bouncycastle:bcprov-jdk15on'
- testCompile 'org.junit.jupiter:junit-jupiter-api'
- testCompile 'org.junit.jupiter:junit-jupiter-params'
+final class AuthMessage {
- testRuntime 'org.junit.jupiter:junit-jupiter-engine'
+ private final NodeInfo info;
+ private final String secret;
+ private final String id;
+
+ public AuthMessage(NodeInfo info, String id, String secret) {
+ this.info = info;
+ this.id = id;
+ this.secret = secret;
+ }
+
+ @JsonGetter("id")
+ public String getID() {
+ return id;
+ }
+
+ @JsonGetter("info")
+ public NodeInfo getInfo() {
+ return info;
+ }
+
+ @JsonGetter("secret")
+ public String getSecret() {
+ return secret;
+ }
}
diff --git a/ethstats/src/main/java/org/apache/tuweni/ethstats/BlockStats.java b/ethstats/src/main/java/org/apache/tuweni/ethstats/BlockStats.java
new file mode 100644
index 0000000..b9febd0
--- /dev/null
+++ b/ethstats/src/main/java/org/apache/tuweni/ethstats/BlockStats.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
+ * to You 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 org.apache.tuweni.ethstats;
+
+
+import org.apache.tuweni.eth.Address;
+import org.apache.tuweni.eth.BlockHeader;
+import org.apache.tuweni.eth.Hash;
+import org.apache.tuweni.units.bigints.UInt256;
+
+import java.util.List;
+
+import com.fasterxml.jackson.annotation.JsonGetter;
+
+public final class BlockStats {
+
+ private final UInt256 blockNumber;
+ private final Hash hash;
+ private final Hash parentHash;
+ private final long timestamp;
+ private final Address miner;
+ private final long gasUsed;
+ private final long gasLimit;
+ private final UInt256 difficulty;
+ private final UInt256 totalDifficulty;
+ private final List<TxStats> transactions;
+ private final Hash transactionsRoot;
+ private final Hash stateRoot;
+ private final List<BlockHeader> uncles;
+
+
+ BlockStats(
+ UInt256 blockNumber,
+ Hash hash,
+ Hash parentHash,
+ long timestamp,
+ Address miner,
+ long gasUsed,
+ long gasLimit,
+ UInt256 difficulty,
+ UInt256 totalDifficulty,
+ List<TxStats> transactions,
+ Hash transactionsRoot,
+ Hash stateRoot,
+ List<BlockHeader> uncles) {
+ this.blockNumber = blockNumber;
+ this.hash = hash;
+ this.parentHash = parentHash;
+ this.timestamp = timestamp;
+ this.miner = miner;
+ this.gasUsed = gasUsed;
+ this.gasLimit = gasLimit;
+ this.difficulty = difficulty;
+ this.totalDifficulty = totalDifficulty;
+ this.transactions = transactions;
+ this.transactionsRoot = transactionsRoot;
+ this.stateRoot = stateRoot;
+ this.uncles = uncles;
+ }
+
+ @JsonGetter("number")
+ public long getBlockNumber() {
+ return blockNumber.toLong();
+ }
+
+ @JsonGetter("hash")
+ public String getHash() {
+ return hash.toHexString();
+ }
+
+ @JsonGetter("parentHash")
+ public Hash getParentHash() {
+ return parentHash;
+ }
+
+ @JsonGetter("timestamp")
+ public long getTimestamp() {
+ return timestamp;
+ }
+
+ @JsonGetter("miner")
+ public Address getMiner() {
+ return miner;
+ }
+
+ @JsonGetter("gasUsed")
+ public long getGasUsed() {
+ return gasUsed;
+ }
+
+ @JsonGetter("gasLimit")
+ public long getGasLimit() {
+ return gasLimit;
+ }
+
+ @JsonGetter("difficulty")
+ public String getDifficulty() {
+ return difficulty.toString();
+ }
+
+ @JsonGetter("totalDifficulty")
+ public String getTotalDifficulty() {
+ return totalDifficulty.toString();
+ }
+
+ @JsonGetter("transactions")
+ public List<TxStats> getTransactions() {
+ return transactions;
+ }
+
+ @JsonGetter("transactionsRoot")
+ public String getTransactionsRoot() {
+ return transactionsRoot.toHexString();
+ }
+
+ @JsonGetter("stateRoot")
+ public Hash getStateRoot() {
+ return stateRoot;
+ }
+
+ @JsonGetter("uncles")
+ public List<BlockHeader> getUncles() {
+ return uncles;
+ }
+}
diff --git a/ethstats/src/main/java/org/apache/tuweni/ethstats/EthStatsReporter.java b/ethstats/src/main/java/org/apache/tuweni/ethstats/EthStatsReporter.java
new file mode 100644
index 0000000..e27c82b
--- /dev/null
+++ b/ethstats/src/main/java/org/apache/tuweni/ethstats/EthStatsReporter.java
@@ -0,0 +1,297 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
+ * to You 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 org.apache.tuweni.ethstats;
+
+import org.apache.tuweni.eth.EthJsonModule;
+import org.apache.tuweni.units.bigints.UInt256;
+
+import java.io.IOException;
+import java.io.UncheckedIOException;
+import java.net.URI;
+import java.time.Instant;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import io.vertx.core.Future;
+import io.vertx.core.MultiMap;
+import io.vertx.core.TimeoutStream;
+import io.vertx.core.Vertx;
+import io.vertx.core.WorkerExecutor;
+import io.vertx.core.http.HttpClient;
+import io.vertx.core.http.HttpClientOptions;
+import io.vertx.core.http.WebSocket;
+import org.logl.Logger;
+
+/**
+ * ETHNetStats reporting service.
+ * <p>
+ * This service connects to a running ethnetstats service and reports.
+ * <p>
+ * If the service is not available, the reporter will keep trying to connect periodically. The service will report
+ * statistics over time.
+ */
+public final class EthStatsReporter {
+
+ private final static ObjectMapper mapper = new ObjectMapper();
+
+ static {
+ mapper.registerModule(new EthJsonModule());
+ }
+ private final static long DELAY = 5000;
+ private final static long REPORTING_PERIOD = 1000;
+ private final static long PING_PERIOD = 15000;
+
+
+ private final String id;
+ private final Vertx vertx;
+ private final URI ethstatsServerURI;
+ private final Logger logger;
+ private final AtomicBoolean started = new AtomicBoolean(false);
+ private final AtomicBoolean waitingOnPong = new AtomicBoolean(false);
+ private final NodeInfo nodeInfo;
+ private final String secret;
+ private final AtomicReference<Integer> newTxCount = new AtomicReference<>();
+ private final Consumer<List<UInt256>> historyRequester;
+
+ private WorkerExecutor executor;
+ private HttpClient client;
+ private AtomicReference<BlockStats> newHead = new AtomicReference<>();
+ private AtomicReference<NodeStats> newNodeStats = new AtomicReference<>();
+ private AtomicReference<List<BlockStats>> newHistory = new AtomicReference<>();
+
+ /**
+ * Default constructor.
+ *
+ * @param vertx a Vert.x instance, externally managed.
+ * @param logger a logger
+ * @param ethstatsServerURI the URI to connect to eth-netstats, such as ws://www.ethnetstats.org:3000/api
+ * @param secret the secret to use when we connect to eth-netstats
+ * @param name the name of the node to be reported in the UI
+ * @param node the node name to be reported in the UI
+ * @param port the devp2p port exposed by this node
+ * @param network the network id
+ * @param protocol the version of the devp2p eth subprotocol, such as eth/63
+ * @param os the operating system on which the node runs
+ * @param osVer the version of the OS on which the node runs
+ * @param historyRequester a hook for ethstats to request block information by number.
+ */
+ public EthStatsReporter(
+ Vertx vertx,
+ Logger logger,
+ URI ethstatsServerURI,
+ String secret,
+ String name,
+ String node,
+ int port,
+ String network,
+ String protocol,
+ String os,
+ String osVer,
+ Consumer<List<UInt256>> historyRequester) {
+ this.id = UUID.randomUUID().toString();
+ this.vertx = vertx;
+ this.logger = logger;
+ this.ethstatsServerURI = ethstatsServerURI;
+ this.secret = secret;
+ this.nodeInfo = new NodeInfo(name, node, port, network, protocol, os, osVer);
+ this.historyRequester = historyRequester;
+ }
+
+ public void start() {
+ if (started.compareAndSet(false, true)) {
+ executor = vertx.createSharedWorkerExecutor("ethnetstats");
+ client = vertx.createHttpClient(new HttpClientOptions().setLogActivity(true));
+ startInternal();
+ }
+ }
+
+ public void stop() {
+ if (started.compareAndSet(true, false)) {
+ logger.debug("Stopping the service");
+ executor.close();
+ }
+ }
+
+ public void sendNewHead(BlockStats newBlockStats) {
+ newHead.set(newBlockStats);
+ }
+
+ public void sendNewPendingTransactionCount(int txCount) {
+ newTxCount.set(txCount);
+ }
+
+ public void sendNewNodeStats(NodeStats nodeStats) {
+ newNodeStats.set(nodeStats);
+ }
+
+ public void sendHistoryResponse(List<BlockStats> blocks) {
+ newHistory.set(blocks);
+ }
+
+ private void startInternal() {
+ executor.executeBlocking(this::connect, result -> {
+ if (started.get()) {
+ if ((result.failed() || !result.result())) {
+ logger.debug("Attempting to connect", result.cause());
+ attemptConnect(null);
+ }
+ }
+ });
+ }
+
+ private void attemptConnect(Void aVoid) {
+ vertx.setTimer(DELAY, handler -> this.startInternal());
+ }
+
+ private void connect(Future<Boolean> result) {
+ client.websocket(
+ ethstatsServerURI.getPort(),
+ ethstatsServerURI.getHost(),
+ ethstatsServerURI.toString(),
+ MultiMap.caseInsensitiveMultiMap().add("origin", "http://localhost"),
+ ws -> {
+ ws.closeHandler(this::attemptConnect);
+ ws.exceptionHandler(e -> {
+ logger.debug("Error while communicating with ethnetstats", e);
+
+ });
+ ws.textMessageHandler(message -> {
+ try {
+ JsonNode node = mapper.readTree(message);
+ JsonNode emitEvent = node.get("emit");
+ if (emitEvent.isArray()) {
+ String eventValue = emitEvent.get(0).textValue();
+ if (!result.isComplete()) {
+ if (!"ready".equals(eventValue)) {
+ logger.warn(message);
+ result.complete(false);
+ } else {
+ logger.debug("Connected OK! {}", message);
+ result.complete(true);
+
+ // we are connected and now sending information
+ reportPeriodically(ws);
+ writePing(ws);
+ report(ws);
+ }
+ } else {
+ handleEmitEvent((ArrayNode) emitEvent, ws);
+ }
+ } else {
+ logger.warn(message);
+ result.complete(false);
+ }
+ } catch (IOException e) {
+ throw new UncheckedIOException(e);
+ }
+ });
+
+ writeCommand(ws, "hello", new AuthMessage(nodeInfo, id, secret));
+ },
+ result::fail);
+ }
+
+ private void handleEmitEvent(ArrayNode event, WebSocket ws) {
+ String command = event.get(0).textValue();
+ switch (command) {
+ case "node-pong":
+ logger.debug("Received a pong {}", event.get(1));
+ if (!waitingOnPong.compareAndSet(true, false)) {
+ logger.warn("Received pong when we didn't expect one");
+ } else {
+ long start = event.get(1).get("clientTime").longValue();
+ long latency = (Instant.now().toEpochMilli() - start) / (2 * 1000);
+ writeCommand(ws, "latency", "latency", latency);
+ }
+ break;
+ case "history":
+ logger.debug("History request {}", event.get(1));
+ requestHistory(event.get(1));
+ break;
+ default:
+ logger.warn("Unexpected message {}", command);
+
+ }
+ }
+
+ private void requestHistory(JsonNode list) {
+ historyRequester.accept(null);
+ }
+
+ private void writePing(WebSocket ws) {
+ waitingOnPong.set(true);
+ writeCommand(ws, "node-ping", "clientTime", Instant.now().toEpochMilli());
+ }
+
+ private void reportPeriodically(WebSocket ws) {
+ TimeoutStream reportingStream = vertx.periodicStream(REPORTING_PERIOD).handler(ev -> {
+ report(ws);
+ });
+ TimeoutStream pingStream = vertx.periodicStream(PING_PERIOD).handler(ev -> {
+ writePing(ws);
+ });
+ ws.closeHandler(h -> {
+ reportingStream.cancel();
+ pingStream.cancel();
+ attemptConnect(null);
+ });
+ }
+
+ private void report(WebSocket ws) {
+ BlockStats head = newHead.getAndSet(null);
+ if (head != null) {
+ writeCommand(ws, "block", "block", head);
+ }
+ Integer count = newTxCount.getAndSet(null);
+ if (count != null) {
+ writeCommand(ws, "pending", "stats", Collections.singletonMap("pending", count));
+ }
+ NodeStats nodeStats = newNodeStats.getAndSet(null);
+ if (nodeStats != null) {
+ writeCommand(ws, "stats", "stats", nodeStats);
+ }
+ List<BlockStats> newBlocks = newHistory.getAndSet(null);
+ if (newBlocks != null && !newBlocks.isEmpty()) {
+ writeCommand(ws, "history", "history", newBlocks);
+ }
+ }
+
+ private void writeCommand(WebSocket ws, String command, Object payload) {
+ try {
+ String message =
+ mapper.writer().writeValueAsString(Collections.singletonMap("emit", Arrays.asList(command, payload)));
+ logger.debug("Sending {} message {}", command, message);
+ ws.writeTextMessage(message);
+ } catch (JsonProcessingException e) {
+ throw new UncheckedIOException(e);
+ }
+ }
+
+ private void writeCommand(WebSocket ws, String command, String key, Object payload) {
+ Map<String, Object> body = new HashMap<>();
+ body.put("id", id);
+ body.put(key, payload);
+ writeCommand(ws, command, body);
+ }
+}
diff --git a/ethstats/src/main/java/org/apache/tuweni/ethstats/NodeInfo.java b/ethstats/src/main/java/org/apache/tuweni/ethstats/NodeInfo.java
new file mode 100644
index 0000000..c027116
--- /dev/null
+++ b/ethstats/src/main/java/org/apache/tuweni/ethstats/NodeInfo.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
+ * to You 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 org.apache.tuweni.ethstats;
+
+import com.fasterxml.jackson.annotation.JsonGetter;
+
+final class NodeInfo {
+
+ static final String CLIENT_VERSION = "0.1.0";
+
+ private final String name;
+ private final String node;
+ private final int port;
+ private final String network;
+ private final String protocol;
+ private final String api = "No";
+ private final String os;
+ private final String osVer;
+ private final String client = CLIENT_VERSION;
+ private final boolean history = true;
+
+ NodeInfo(String name, String node, int port, String network, String protocol, String os, String osVer) {
+ this.name = name;
+ this.node = node;
+ this.port = port;
+ this.network = network;
+ this.protocol = protocol;
+ this.os = os;
+ this.osVer = osVer;
+ }
+
+ @JsonGetter("name")
+ public String getName() {
+ return name;
+ }
+
+ @JsonGetter("node")
+ public String getNode() {
+ return node;
+ }
+
+ @JsonGetter("port")
+ public int getPort() {
+ return port;
+ }
+
+ @JsonGetter("net")
+ public String getNetwork() {
+ return network;
+ }
+
+ @JsonGetter("protocol")
+ public String getProtocol() {
+ return protocol;
+ }
+
+ @JsonGetter("api")
+ public String getAPI() {
+ return api;
+ }
+
+ @JsonGetter("os")
+ public String getOS() {
+ return os;
+ }
+
+ @JsonGetter("os_v")
+ public String getOSVersion() {
+ return osVer;
+ }
+
+ @JsonGetter("client")
+ public String getClient() {
+ return client;
+ }
+
+ @JsonGetter("canUpdateHistory")
+ public boolean canUpdateHistory() {
+ return history;
+ }
+}
diff --git a/ethstats/src/main/java/org/apache/tuweni/ethstats/NodeStats.java b/ethstats/src/main/java/org/apache/tuweni/ethstats/NodeStats.java
new file mode 100644
index 0000000..bb08444
--- /dev/null
+++ b/ethstats/src/main/java/org/apache/tuweni/ethstats/NodeStats.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
+ * to You 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 org.apache.tuweni.ethstats;
+
+import com.fasterxml.jackson.annotation.JsonGetter;
+
+public final class NodeStats {
+ private final boolean active;
+ private final boolean syncing;
+ private final boolean mining;
+ private final int hashrate;
+ private final int peerCount;
+ private final int gasPrice;
+ private final int uptime;
+
+
+ public NodeStats(
+ boolean active,
+ boolean syncing,
+ boolean mining,
+ int hashrate,
+ int peerCount,
+ int gasPrice,
+ int uptime) {
+ this.active = active;
+ this.syncing = syncing;
+ this.mining = mining;
+ this.hashrate = hashrate;
+ this.peerCount = peerCount;
+ this.gasPrice = gasPrice;
+ this.uptime = uptime;
+ }
+
+ @JsonGetter("active")
+ public boolean isActive() {
+ return active;
+ }
+
+ @JsonGetter("syncing")
+ public boolean isSyncing() {
+ return syncing;
+ }
+
+ @JsonGetter("mining")
+ public boolean isMining() {
+ return mining;
+ }
+
+ @JsonGetter("hashrate")
+ public int getHashrate() {
+ return hashrate;
+ }
+
+ @JsonGetter("peers")
+ public int getPeerCount() {
+ return peerCount;
+ }
+
+ @JsonGetter("gasPrice")
+ public int getGasPrice() {
+ return gasPrice;
+ }
+
+ @JsonGetter("uptime")
+ public int getUptime() {
+ return uptime;
+ }
+}
diff --git a/eth/build.gradle b/ethstats/src/main/java/org/apache/tuweni/ethstats/TxStats.java
similarity index 64%
copy from eth/build.gradle
copy to ethstats/src/main/java/org/apache/tuweni/ethstats/TxStats.java
index b50cbf7..a2ddf6e 100644
--- a/eth/build.gradle
+++ b/ethstats/src/main/java/org/apache/tuweni/ethstats/TxStats.java
@@ -10,18 +10,22 @@
* 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.
*/
-description = 'Classes and utilities for working with Ethereum.'
+package org.apache.tuweni.ethstats;
-dependencies {
- compile project(':bytes')
- compile project(':crypto')
- compile project(':rlp')
- compile project(':units')
+import org.apache.tuweni.crypto.Hash;
- testCompile project(':junit')
- testCompile 'org.bouncycastle:bcprov-jdk15on'
- testCompile 'org.junit.jupiter:junit-jupiter-api'
- testCompile 'org.junit.jupiter:junit-jupiter-params'
+import com.fasterxml.jackson.annotation.JsonGetter;
- testRuntime 'org.junit.jupiter:junit-jupiter-engine'
+final class TxStats {
+
+ private final Hash hash;
+
+ TxStats(Hash hash) {
+ this.hash = hash;
+ }
+
+ @JsonGetter("hash")
+ public Hash getHash() {
+ return hash;
+ }
}
diff --git a/ethstats/src/test/java/org/apache/tuweni/ethstats/EthStatsReporterTest.java b/ethstats/src/test/java/org/apache/tuweni/ethstats/EthStatsReporterTest.java
new file mode 100644
index 0000000..63b8895
--- /dev/null
+++ b/ethstats/src/test/java/org/apache/tuweni/ethstats/EthStatsReporterTest.java
@@ -0,0 +1,129 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE
+ * file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file
+ * to You 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 org.apache.tuweni.ethstats;
+
+import org.apache.tuweni.bytes.Bytes;
+import org.apache.tuweni.bytes.Bytes32;
+import org.apache.tuweni.eth.Address;
+import org.apache.tuweni.eth.Hash;
+import org.apache.tuweni.junit.VertxExtension;
+import org.apache.tuweni.junit.VertxInstance;
+import org.apache.tuweni.units.bigints.UInt256;
+
+import java.net.URI;
+import java.util.Collections;
+
+import io.vertx.core.Vertx;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.logl.Level;
+import org.logl.Logger;
+import org.logl.logl.SimpleLogger;
+
+@ExtendWith(VertxExtension.class)
+public class EthStatsReporterTest {
+
+ //@Disabled
+ @Test
+ void testConnectToLocalEthStats(@VertxInstance Vertx vertx) throws InterruptedException {
+ Logger logger = SimpleLogger.withLogLevel(Level.DEBUG).toOutputStream(System.out).getLogger("wat");
+
+ EthStatsReporter reporter = new EthStatsReporter(
+ vertx,
+ logger,
+ URI.create("ws://localhost:3000/api"),
+ "wat",
+ "name",
+ "node",
+ 33030,
+ "10",
+ "eth/63",
+ "Windoz",
+ "64",
+ (blockNumbers) -> {
+ });
+
+
+ reporter.sendNewHead(
+ new BlockStats(
+ UInt256.ONE,
+ Hash.fromBytes(Bytes32.random()),
+ Hash.fromBytes(Bytes32.random()),
+ 3L,
+ Address.fromBytes(Bytes.random(20)),
+ 42L,
+ 43,
+ UInt256.valueOf(42L),
+ UInt256.valueOf(84L),
+ Collections.emptyList(),
+ Hash.fromBytes(Bytes32.random()),
+ Hash.fromBytes(Bytes32.random()),
+ Collections.emptyList()));
+
+ reporter.sendNewNodeStats(new NodeStats(true, false, true, 42, 9, 4000, 100));
+ reporter.sendNewPendingTransactionCount(42);
+ reporter.start();
+
+ Thread.sleep(1000);
+ reporter.sendNewHead(
+ new BlockStats(
+ UInt256.valueOf(2),
+ Hash.fromBytes(Bytes32.random()),
+ Hash.fromBytes(Bytes32.random()),
+ 3L,
+ Address.fromBytes(Bytes.random(20)),
+ 42L,
+ 43,
+ UInt256.valueOf(42L),
+ UInt256.valueOf(84L),
+ Collections.emptyList(),
+ Hash.fromBytes(Bytes32.random()),
+ Hash.fromBytes(Bytes32.random()),
+ Collections.emptyList()));
+ Thread.sleep(1000);
+ Thread.sleep(1000);
+ reporter.sendNewHead(
+ new BlockStats(
+ UInt256.valueOf(3),
+ Hash.fromBytes(Bytes32.random()),
+ Hash.fromBytes(Bytes32.random()),
+ 3L,
+ Address.fromBytes(Bytes.random(20)),
+ 42L,
+ 43,
+ UInt256.valueOf(42L),
+ UInt256.valueOf(84L),
+ Collections.emptyList(),
+ Hash.fromBytes(Bytes32.random()),
+ Hash.fromBytes(Bytes32.random()),
+ Collections.emptyList()));
+ Thread.sleep(1000);
+ reporter.sendNewHead(
+ new BlockStats(
+ UInt256.valueOf(4),
+ Hash.fromBytes(Bytes32.random()),
+ Hash.fromBytes(Bytes32.random()),
+ 3L,
+ Address.fromBytes(Bytes.random(20)),
+ 42L,
+ 43,
+ UInt256.valueOf(42L),
+ UInt256.valueOf(84L),
+ Collections.emptyList(),
+ Hash.fromBytes(Bytes32.random()),
+ Hash.fromBytes(Bytes32.random()),
+ Collections.emptyList()));
+ Thread.sleep(5000);
+ reporter.stop();
+ }
+}
diff --git a/les/src/main/kotlin/org/apache/tuweni/les/LESSubProtocolHandler.kt b/les/src/main/kotlin/org/apache/tuweni/les/LESSubProtocolHandler.kt
index 1548573..5da47cb 100644
--- a/les/src/main/kotlin/org/apache/tuweni/les/LESSubProtocolHandler.kt
+++ b/les/src/main/kotlin/org/apache/tuweni/les/LESSubProtocolHandler.kt
@@ -114,7 +114,7 @@ internal class LESSubProtocolHandler(
val bodies = ArrayList<BlockBody>()
for (blockHash in blockBodiesMessage.blockHashes) {
repo.retrieveBlock(blockHash)?.let { block ->
- bodies.add(block.body())
+ bodies.add(block.getBody())
}
}
return service.send(
@@ -167,16 +167,16 @@ internal class LESSubProtocolHandler(
return asyncCompletion {
val head = repo.retrieveChainHead()!!
val genesis = repo.retrieveGenesisBlock()!!
- val headTd = head.header().difficulty()
- val headHash = head.header().hash()
+ val headTd = head.getHeader().getDifficulty()
+ val headHash = head.getHeader().getHash()
val state = peerStateMap.computeIfAbsent(connectionId) { LESPeerState() }
state.ourStatusMessage = StatusMessage(
subProtocolIdentifier.version(),
networkId,
headTd,
headHash.toBytes(),
- head.header().number(),
- genesis.header().hash().toBytes(),
+ head.getHeader().getNumber(),
+ genesis.getHeader().getHash().toBytes(),
serveHeaders,
serveChainSince,
serveStateSince,
diff --git a/les/src/test/kotlin/org/apache/tuweni/les/LESSubProtocolHandlerTest.kt b/les/src/test/kotlin/org/apache/tuweni/les/LESSubProtocolHandlerTest.kt
index 0c40377..5b8fbab 100644
--- a/les/src/test/kotlin/org/apache/tuweni/les/LESSubProtocolHandlerTest.kt
+++ b/les/src/test/kotlin/org/apache/tuweni/les/LESSubProtocolHandlerTest.kt
@@ -163,7 +163,7 @@ constructor() {
assertNotNull(message)
assertEquals(2, message.protocolVersion)
assertEquals(UInt256.ZERO, message.flowControlBufferLimit)
- assertEquals(block.header().hash().toBytes(), message.genesisHash)
+ assertEquals(block.getHeader().getHash().toBytes(), message.genesisHash)
}
@Test
@@ -374,7 +374,7 @@ constructor() {
handler.handleNewPeerConnection("abc").await()
handler.handle("abc", 0, status).await()
handler.handle("abc", 3, BlockHeadersMessage(1, 2, listOf(header)).toBytes()).await()
- val retrieved = repo.retrieveBlockHeader(header.hash())
+ val retrieved = repo.retrieveBlockHeader(header.getHash())
assertEquals(header, retrieved)
}
diff --git a/settings.gradle b/settings.gradle
index 2db7bce..30dbabe 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -22,6 +22,7 @@ include 'dns-discovery'
include 'eth'
include 'eth-reference-tests'
include 'eth-repository'
+include 'ethstats'
include 'gossip'
include 'hobbits'
include 'hobbits-relayer'
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@tuweni.apache.org
For additional commands, e-mail: commits-help@tuweni.apache.org