Skip to content
This repository has been archived by the owner on Apr 23, 2019. It is now read-only.

Commit

Permalink
Merge pull request #178 from atoulme/les
Browse files Browse the repository at this point in the history
Add LES subprotocol to Cava
  • Loading branch information
atoulme authored Mar 5, 2019
2 parents 1e64434 + e4e87bb commit c01f2e5
Show file tree
Hide file tree
Showing 17 changed files with 1,706 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ package net.consensys.cava.eth.repository
import net.consensys.cava.bytes.Bytes
import net.consensys.cava.bytes.Bytes32
import net.consensys.cava.eth.Block
import net.consensys.cava.eth.BlockBody
import net.consensys.cava.eth.BlockHeader
import net.consensys.cava.eth.Hash
import net.consensys.cava.eth.TransactionReceipt
Expand All @@ -31,13 +32,13 @@ class BlockchainRepository
* Default constructor.
*
* @param chainMetadata the key-value store to store chain metadata
* @param blockStore the key-value store to store blocks
* @param blockBodyStore the key-value store to store block bodies
* @param blockHeaderStore the key-value store to store block headers
* @param blockchainIndex the blockchain index to index values
*/
(
private val chainMetadata: KeyValueStore,
private val blockStore: KeyValueStore,
private val blockBodyStore: KeyValueStore,
private val blockHeaderStore: KeyValueStore,
private val transactionReceiptsStore: KeyValueStore,
private val blockchainIndex: BlockchainIndex
Expand All @@ -53,15 +54,15 @@ class BlockchainRepository
* @return a new blockchain repository made from the metadata passed in parameter.
*/
suspend fun init(
blockStore: KeyValueStore,
blockBodyStore: KeyValueStore,
blockHeaderStore: KeyValueStore,
chainMetadata: KeyValueStore,
transactionReceiptsStore: KeyValueStore,
blockchainIndex: BlockchainIndex,
genesisBlock: Block
): BlockchainRepository {
val repo = BlockchainRepository(chainMetadata,
blockStore,
blockBodyStore,
blockHeaderStore,
transactionReceiptsStore,
blockchainIndex)
Expand All @@ -72,13 +73,23 @@ class BlockchainRepository
}

/**
* Stores a block in the repository.
* Stores a block body into the repository.
*
* @param blockBody the block body to store
* @return a handle to the storage operation completion
*/
suspend fun storeBlockBody(blockHash: Hash, blockBody: BlockBody) {
blockBodyStore.put(blockHash.toBytes(), blockBody.toBytes())
}

/**
* Stores a block into the repository.
*
* @param block the block to store
* @return a handle to the storage operation completion
*/
suspend fun storeBlock(block: Block) {
blockStore.put(block.header().hash().toBytes(), block.toBytes())
storeBlockBody(block.header().hash(), block.body())
blockHeaderStore.put(block.header().hash().toBytes(), block.header().toBytes())
indexBlockHeader(block.header())
}
Expand Down Expand Up @@ -153,18 +164,38 @@ class BlockchainRepository
* @param blockHash the hash of the block stored
* @return a future with the bytes if found
*/
suspend fun retrieveBlockBytes(blockHash: Hash): Bytes? {
return retrieveBlockBytes(blockHash.toBytes())
suspend fun retrieveBlockBodyBytes(blockHash: Hash): Bytes? {
return retrieveBlockBodyBytes(blockHash.toBytes())
}

/**
* Retrieves a block into the repository as its serialized RLP bytes representation.
* Retrieves a block body into the repository as its serialized RLP bytes representation.
*
* @param blockHash the hash of the block stored
* @return a future with the bytes if found
*/
suspend fun retrieveBlockBytes(blockHash: Bytes): Bytes? {
return blockStore.get(blockHash)
suspend fun retrieveBlockBodyBytes(blockHash: Bytes): Bytes? {
return blockBodyStore.get(blockHash)
}

/**
* Retrieves a block body into the repository.
*
* @param blockHash the hash of the block stored
* @return a future with the block if found
*/
suspend fun retrieveBlockBody(blockHash: Hash): BlockBody? {
return retrieveBlockBody(blockHash.toBytes())
}

/**
* Retrieves a block body into the repository.
*
* @param blockHash the hash of the block stored
* @return a future with the block if found
*/
suspend fun retrieveBlockBody(blockHash: Bytes): BlockBody? {
return retrieveBlockBodyBytes(blockHash)?.let { BlockBody.fromBytes(it) }
}

/**
Expand All @@ -184,7 +215,9 @@ class BlockchainRepository
* @return a future with the block if found
*/
suspend fun retrieveBlock(blockHash: Bytes): Block? {
return retrieveBlockBytes(blockHash)?.let { Block.fromBytes(it) } ?: return null
return retrieveBlockBody(blockHash)?.let {
body -> this.retrieveBlockHeader(blockHash)?.let { Block(it, body) }
} ?: return null
}

/**
Expand All @@ -194,7 +227,7 @@ class BlockchainRepository
* @return a future with the block header bytes if found
*/
suspend fun retrieveBlockHeaderBytes(blockHash: Hash): Bytes? {
return retrieveBlockBytes(blockHash.toBytes())
return retrieveBlockBodyBytes(blockHash.toBytes())
}

/**
Expand Down
25 changes: 25 additions & 0 deletions les/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
dependencies {
compile project(':bytes')
compile project(':concurrent')
compile project(':concurrent-coroutines')
compile project(':crypto')
compile project(':eth')
compile project(':eth-repository')
compile project(':kv')
compile project(':rlpx')
compile 'com.google.guava:guava'
compile 'org.logl:logl-api'

compileOnly 'io.vertx:vertx-core'
compile 'org.xerial.snappy:snappy-java'
compile 'org.bouncycastle:bcprov-jdk15on'

testCompile project(':junit')
testCompile 'io.vertx:vertx-core'
testCompile 'org.bouncycastle:bcprov-jdk15on'
testCompile 'org.junit.jupiter:junit-jupiter-api'
testCompile 'org.junit.jupiter:junit-jupiter-params'
testCompile 'org.logl:logl-logl'

testRuntime 'org.junit.jupiter:junit-jupiter-engine'
}
47 changes: 47 additions & 0 deletions les/src/main/kotlin/net/consensys/cava/les/BlockBodiesMessage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* 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 net.consensys.cava.les

import net.consensys.cava.bytes.Bytes
import net.consensys.cava.eth.BlockBody
import net.consensys.cava.rlp.RLP

internal data class BlockBodiesMessage(
val reqID: Long,
val bufferValue: Long,
val blockBodies: List<BlockBody>
) {

fun toBytes(): Bytes {
return RLP.encodeList { writer ->
writer.writeLong(reqID)
writer.writeLong(bufferValue)
writer.writeList(blockBodies) { eltWriter, blockBody -> blockBody.writeTo(eltWriter) }
}
}

companion object {

fun read(bytes: Bytes): BlockBodiesMessage {
return RLP.decodeList(
bytes
) { reader ->
BlockBodiesMessage(
reader.readLong(),
reader.readLong(),
reader.readListContents { BlockBody.readFrom(it) }
)
}
}
}
}
52 changes: 52 additions & 0 deletions les/src/main/kotlin/net/consensys/cava/les/BlockHeadersMessage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* 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 net.consensys.cava.les

import net.consensys.cava.bytes.Bytes
import net.consensys.cava.eth.BlockHeader
import net.consensys.cava.rlp.RLP

internal data class BlockHeadersMessage(
val reqID: Long,
val bufferValue: Long,
val blockHeaders: List<BlockHeader>
) {

fun toBytes(): Bytes {
return RLP.encodeList { writer ->
writer.writeLong(reqID)
writer.writeLong(bufferValue)
writer.writeList { headersWriter ->
for (bh in blockHeaders) {
headersWriter.writeRLP(bh.toBytes())
}
}
}
}

companion object {

fun read(bytes: Bytes): BlockHeadersMessage {
return RLP.decodeList(bytes) { reader ->
val reqID = reader.readLong()
val bufferValue = reader.readLong()
val headers = reader.readListContents { headersReader ->
headersReader.readList<BlockHeader> {
BlockHeader.readFrom(it)
}
}
BlockHeadersMessage(reqID, bufferValue, headers)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* 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 net.consensys.cava.les

import net.consensys.cava.bytes.Bytes
import net.consensys.cava.eth.Hash
import net.consensys.cava.rlp.RLP

internal data class GetBlockBodiesMessage(val reqID: Long, val blockHashes: List<Hash>) {

fun toBytes(): Bytes {
return RLP.encodeList { writer ->
writer.writeLong(reqID)
writer.writeList(blockHashes) { eltWriter, hash -> eltWriter.writeValue(hash.toBytes()) }
}
}

companion object {

fun read(bytes: Bytes): GetBlockBodiesMessage {
return RLP.decodeList(
bytes
) { reader ->
GetBlockBodiesMessage(
reader.readLong(),
reader.readListContents { elementReader -> Hash.fromBytes(elementReader.readValue()) })
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* 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 net.consensys.cava.les

import net.consensys.cava.bytes.Bytes
import net.consensys.cava.bytes.Bytes32
import net.consensys.cava.rlp.RLP
import net.consensys.cava.units.bigints.UInt256

internal data class GetBlockHeadersMessage(val reqID: Long, val queries: List<BlockHeaderQuery>) {

internal data class BlockHeaderQuery(
val blockNumberOrBlockHash: Bytes32,
val maxHeaders: UInt256,
val skip: UInt256,
val direction: Direction
) {

internal enum class Direction {
BACKWARDS, FORWARD
}
}

fun toBytes(): Bytes {
return RLP.encodeList { writer ->
writer.writeLong(reqID)
for (query in queries) {
writer.writeList { queryWriter ->
queryWriter.writeValue(query.blockNumberOrBlockHash)
queryWriter.writeUInt256(query.maxHeaders)
queryWriter.writeUInt256(query.skip)
queryWriter.writeInt(if (query.direction == BlockHeaderQuery.Direction.BACKWARDS) 1 else 0)
}
}
}
}

companion object {

fun read(bytes: Bytes): GetBlockHeadersMessage {
return RLP.decodeList(bytes) { reader ->
val reqId = reader.readLong()
val queries = ArrayList<BlockHeaderQuery>()
while (!reader.isComplete) {
queries.add(
reader.readList { queryReader ->
BlockHeaderQuery(
Bytes32.wrap(queryReader.readValue()),
queryReader.readUInt256(),
queryReader.readUInt256(),
if (queryReader.readInt() == 1)
BlockHeaderQuery.Direction.BACKWARDS
else
BlockHeaderQuery.Direction.FORWARD
)
})
}
GetBlockHeadersMessage(reqId, queries)
}
}
}
}
Loading

0 comments on commit c01f2e5

Please sign in to comment.