Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[ETCM-263] improve BlockImport wrt checkpoints - ChainWeight #769

Merged
merged 1 commit into from
Nov 6, 2020

Conversation

rtkaczyk
Copy link
Contributor

@rtkaczyk rtkaczyk commented Nov 2, 2020

Description

Improves branch comparison wrt checkpoints during block import

Proposed Solution

Introduces a unified idea of ChainWeight

Testing

Unit tests

@rtkaczyk rtkaczyk requested review from ntallar and pslaski November 2, 2020 11:23
Copy link
Contributor

@pslaski pslaski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

only minor things

val newBlockNr = block.number
val nextExpectedBlock = state.lastFullBlockNumber + 1

println("CODO KURWY???")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💯 ❤️ 💟

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😅

def getChainWeightByNumber(blockNumber: BigInt): Option[ChainWeight] =
getHashByBlockNumber(blockNumber).flatMap(getChainWeightByHash)

// /**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can be removed now


object ChainWeight {
//FIXME: a shorter name?
def totalDifficultyOnly(td: BigInt): ChainWeight =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hmm totalDifficulty for me looks ok too.

Copy link
Contributor Author

@rtkaczyk rtkaczyk Nov 3, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather have these extra 4 letters to distinguish from ChainWeight#totalDifficulty


//Test API

def increaseTd(td: BigInt): ChainWeight =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

increaseTd => increaseTotalDifficulty

ChainWeight(0, 0)
}

case class ChainWeight(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️

RLPList(
protocolVersion,
networkId,
//TODO: should it be an RLPList? Should we define encoding in ChainWeight object?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 for encoding in ChainWeight object but move it to the end or merge both RLPLists into one

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not yet sure how to handle that while keeping the compatibility with v63 messages

RLPList(
RLPList(
block.header.toRLPEncodable,
RLPList(block.body.transactionList.map(_.toRLPEncodable): _*),
RLPList(block.body.uncleNodesList.map(_.toRLPEncodable): _*)
),
totalDifficulty,
latestCheckpointNumber
//TODO: should it be an RLPList? Should we define encoding in ChainWeight object?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ditto

@@ -103,6 +103,9 @@ object ByteUtils {
ByteString(compactPickledBytesToArray(buffer))
}

def byteSequenceToBuffer(bytes: IndexedSeq[Byte]): ByteBuffer =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you use it in other KeyValueStorages ?

@@ -10,7 +10,7 @@

<logger name="io.iohk.ethereum.vm.VM" level="OFF" />

<root level="INFO">
<root level="DEBUG">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is it spamming too much ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reverted

@@ -92,7 +92,10 @@ class RegularSyncSpec
regularSync ! SyncProtocol.Start

peerEventBus.expectMsgClass(classOf[Subscribe])
peerEventBus.reply(MessageFromPeer(NewBlock(testBlocks.last, testBlocks.last.number), defaultPeer.id))
// It's weird that we're using block number for total difficulty but I'm too scared to fight this dragon
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😂

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test continues to be the most difficult one to follow, at least among the ones I've dealt with recently

Copy link

@ntallar ntallar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

First round of comments

case Left(executionError) =>
go(executedBlocks, remainingBlocks, 0, Some(executionError))
go(executedBlocks, remainingBlocks, parentWeight, Some(executionError))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of parentWeight shouldn't it be parentWeight.increase(blockToExecute.header)? The next block to be executed will be the son of the current one

Although I'm not sure what's the purpose of continuing executing a branch on which one of the blocks failed to be executed

src/main/scala/io/iohk/ethereum/ledger/BlockQueue.scala Outdated Show resolved Hide resolved
src/main/scala/io/iohk/ethereum/ledger/BlockQueue.scala Outdated Show resolved Hide resolved
src/main/scala/io/iohk/ethereum/ledger/BlockImport.scala Outdated Show resolved Hide resolved
src/main/scala/io/iohk/ethereum/ledger/BlockImport.scala Outdated Show resolved Hide resolved
@@ -43,6 +43,8 @@ object EthereumMessageDecoder extends MessageDecoder {
//wire protocol
case (_, Hello.code) => payload.toHello

//FIXME: I still have an issue with protocolVersion, we are use PV62 and PV63 and code names for Status and NewBlock
// suggest that there is PV64, but there isn't
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm now that you say it makes sense to have a PV64

It's weird that ETC has some duplication between the capability from Hello messages and this status field (we even use the same Versions.PV63 variable), but in copying them we should probably have that duplication as well

It might also be worth researching the difference in purposes between the 2 in case we are missing something

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we research that as part of 280? Or maybe a separate task?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm maybe it would be better to make it part of ETCM-280? In order to be sure of the approach we are taking there

We could split it later into more tasks if we detect that it's taking longer than expected

@rtkaczyk rtkaczyk force-pushed the etcm-263-improve-blockimport-checkpoints branch from a914015 to 7dd7354 Compare November 3, 2020 16:41
@@ -118,7 +118,13 @@ class GenesisDataLoader(blockchain: Blockchain, blockchainConfig: BlockchainConf
case None =>
storage.persist()
stateStorage.forcePersist(GenesisDataLoad)
blockchain.save(Block(header, BlockBody(Nil, Nil)), Nil, header.difficulty, saveAsBestBlock = true)
// TODO: factory for ChainWeight?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you have it already ;) ChainWeight.totalDifficultyOnly

@@ -31,7 +29,7 @@ class BlockHeadersStorage(val dataSource: DataSource)
blockHeader => compactPickledBytes(Pickle.intoBytes(blockHeader))

override def valueDeserializer: IndexedSeq[Byte] => BlockHeader =
bytes => Unpickle[BlockHeader].fromBytes(ByteBuffer.wrap(bytes.toArray[Byte]))
byteSequenceToBuffer _ andThen Unpickle[BlockHeader].fromBytes
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT about creating helper for byteSequenceToBuffer _ andThen Unpickle[Type].fromBytes ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to merge it ASAP, but added a TODO

case (None, None) =>
compareByDifficulty(newBranch, oldBranch)
case None =>
// TODO: should we log if parentWeight not found?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cause the code would be ugly :) This match doesn't capture the situation - there could be no parent to get the weight for

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could change it a bit it to detect that case? More of this logs never bothered, we never know when it will be useful

def genesisHash: ByteString
genesisHash: ByteString
): Status =
//TODO: explain, remove if possible
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

? :)

def as63: NewBlock63 =
NewBlock63(block, totalDifficulty)
def apply(block: Block, chainWeight: ChainWeight): NewBlock =
//TODO: explain, remove if possible
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

? :)

@ntallar ntallar added the BREAKS STATE Affects self state retro-compatibility, needs data wiping label Nov 4, 2020
Copy link

@ntallar ntallar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Last comments, got to take a look at all the changes!

Code is looking much nicer ❤️

case (None, None) =>
compareByDifficulty(newBranch, oldBranch)
case None =>
// TODO: should we log if parentWeight not found?
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we could change it a bit it to detect that case? More of this logs never bothered, we never know when it will be useful

@@ -43,6 +43,8 @@ object EthereumMessageDecoder extends MessageDecoder {
//wire protocol
case (_, Hello.code) => payload.toHello

//FIXME: I still have an issue with protocolVersion, we are use PV62 and PV63 and code names for Status and NewBlock
// suggest that there is PV64, but there isn't
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm maybe it would be better to make it part of ETCM-280? In order to be sure of the approach we are taking there

We could split it later into more tasks if we detect that it's taking longer than expected

@rtkaczyk rtkaczyk force-pushed the etcm-263-improve-blockimport-checkpoints branch from 7dd7354 to 5ef06b3 Compare November 5, 2020 16:35
Copy link

@ntallar ntallar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Synced 50k blocks from mordor without any problems! Though I had to fix an issue

.orElse(newHeaders.headOption)
.map { header =>
blockchain
.getChainWeightByHash(header.hash)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't we fetch here for the header.parentHash? Syncing to mordor fails if not due to ChainWeight for 1 not found when resolving branch

@pslaski pslaski force-pushed the etcm-263-improve-blockimport-checkpoints branch from 5ef06b3 to ee341ce Compare November 6, 2020 11:04
Copy link

@ntallar ntallar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Syncing to mordor now works, played a bit around with the mocked miner and qa checkpoints and it all worked

 .\\            //.
. \ \          / /.
.\  ,\     /` /,.-
 -.   \  /'/ /  .
 ` -   `-'  \  -
   '.       /.\`
      -    .-
      :`//.'
      .`.'
      .' BP 

@pslaski pslaski force-pushed the etcm-263-improve-blockimport-checkpoints branch from ee341ce to 6e722c8 Compare November 6, 2020 12:52
@pslaski pslaski merged commit d6a38d6 into develop Nov 6, 2020
@pslaski pslaski deleted the etcm-263-improve-blockimport-checkpoints branch November 6, 2020 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BREAKS STATE Affects self state retro-compatibility, needs data wiping
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants