Skip to content

Commit d04455f

Browse files
Add tests for bootstrap checkpoint functionality
- Add BootstrapCheckpointSpec with 9 test cases - Add BootstrapCheckpointLoaderSpec with 5 test cases - Fix ByteString.toHex import in BootstrapCheckpointLoader - All 14 tests pass successfully Co-authored-by: realcodywburns <13103499+realcodywburns@users.noreply.github.com>
1 parent 25adc20 commit d04455f

File tree

3 files changed

+223
-0
lines changed

3 files changed

+223
-0
lines changed

src/main/scala/com/chipprbots/ethereum/blockchain/data/BootstrapCheckpointLoader.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package com.chipprbots.ethereum.blockchain.data
22

33
import com.chipprbots.ethereum.domain._
44
import com.chipprbots.ethereum.utils.BlockchainConfig
5+
import com.chipprbots.ethereum.utils.ByteStringUtils.ByteStringOps
56
import com.chipprbots.ethereum.utils.Logger
67

78
/** Loads bootstrap checkpoints into the blockchain to provide a starting point for syncing without waiting for peers.
Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
package com.chipprbots.ethereum.blockchain.data
2+
3+
import org.apache.pekko.util.ByteString
4+
5+
import org.scalamock.scalatest.MockFactory
6+
import org.scalatest.flatspec.AnyFlatSpec
7+
import org.scalatest.matchers.should.Matchers
8+
9+
import com.chipprbots.ethereum.domain._
10+
import com.chipprbots.ethereum.utils.BlockchainConfig
11+
12+
class BootstrapCheckpointLoaderSpec extends AnyFlatSpec with Matchers with MockFactory {
13+
14+
"BootstrapCheckpointLoader.loadBootstrapCheckpoints" should "return false when checkpoints are disabled" in {
15+
val mockReader = mock[BlockchainReader]
16+
val mockWriter = mock[BlockchainWriter]
17+
val loader = new BootstrapCheckpointLoader(mockReader, mockWriter)
18+
19+
implicit val config: BlockchainConfig = createTestConfig(
20+
useBootstrapCheckpoints = false,
21+
bootstrapCheckpoints = List.empty
22+
)
23+
24+
val result = loader.loadBootstrapCheckpoints()
25+
26+
result shouldBe false
27+
}
28+
29+
it should "return false when no checkpoints are configured" in {
30+
val mockReader = mock[BlockchainReader]
31+
val mockWriter = mock[BlockchainWriter]
32+
val loader = new BootstrapCheckpointLoader(mockReader, mockWriter)
33+
34+
implicit val config: BlockchainConfig = createTestConfig(
35+
useBootstrapCheckpoints = true,
36+
bootstrapCheckpoints = List.empty
37+
)
38+
39+
val result = loader.loadBootstrapCheckpoints()
40+
41+
result shouldBe false
42+
}
43+
44+
it should "return false when blockchain already has blocks beyond genesis" in {
45+
val mockReader = mock[BlockchainReader]
46+
val mockWriter = mock[BlockchainWriter]
47+
val loader = new BootstrapCheckpointLoader(mockReader, mockWriter)
48+
49+
(mockReader.getBestBlockNumber _).expects().returning(BigInt(100))
50+
51+
implicit val config: BlockchainConfig = createTestConfig(
52+
useBootstrapCheckpoints = true,
53+
bootstrapCheckpoints = List(
54+
BootstrapCheckpoint(BigInt(1000), ByteString(Array.fill[Byte](32)(0x01)))
55+
)
56+
)
57+
58+
val result = loader.loadBootstrapCheckpoints()
59+
60+
result shouldBe false
61+
}
62+
63+
it should "return true when checkpoints are loaded successfully" in {
64+
val mockReader = mock[BlockchainReader]
65+
val mockWriter = mock[BlockchainWriter]
66+
val loader = new BootstrapCheckpointLoader(mockReader, mockWriter)
67+
68+
(mockReader.getBestBlockNumber _).expects().returning(BigInt(0))
69+
70+
implicit val config: BlockchainConfig = createTestConfig(
71+
useBootstrapCheckpoints = true,
72+
bootstrapCheckpoints = List(
73+
BootstrapCheckpoint(BigInt(1000), ByteString(Array.fill[Byte](32)(0x01))),
74+
BootstrapCheckpoint(BigInt(2000), ByteString(Array.fill[Byte](32)(0x02))),
75+
BootstrapCheckpoint(BigInt(3000), ByteString(Array.fill[Byte](32)(0x03)))
76+
)
77+
)
78+
79+
val result = loader.loadBootstrapCheckpoints()
80+
81+
result shouldBe true
82+
}
83+
84+
it should "handle single checkpoint" in {
85+
val mockReader = mock[BlockchainReader]
86+
val mockWriter = mock[BlockchainWriter]
87+
val loader = new BootstrapCheckpointLoader(mockReader, mockWriter)
88+
89+
(mockReader.getBestBlockNumber _).expects().returning(BigInt(0))
90+
91+
implicit val config: BlockchainConfig = createTestConfig(
92+
useBootstrapCheckpoints = true,
93+
bootstrapCheckpoints = List(
94+
BootstrapCheckpoint(BigInt(10500839), ByteString(Array.fill[Byte](32)(0xff.toByte)))
95+
)
96+
)
97+
98+
val result = loader.loadBootstrapCheckpoints()
99+
100+
result shouldBe true
101+
}
102+
103+
// Helper method to create test config
104+
private def createTestConfig(
105+
useBootstrapCheckpoints: Boolean,
106+
bootstrapCheckpoints: List[BootstrapCheckpoint]
107+
): BlockchainConfig = {
108+
import com.chipprbots.ethereum.domain.Address
109+
import com.chipprbots.ethereum.utils.{ForkBlockNumbers, MonetaryPolicyConfig}
110+
111+
BlockchainConfig(
112+
powTargetTime = None,
113+
forkBlockNumbers = ForkBlockNumbers.Empty,
114+
treasuryAddress = Address(0),
115+
maxCodeSize = None,
116+
customGenesisFileOpt = None,
117+
customGenesisJsonOpt = None,
118+
daoForkConfig = None,
119+
accountStartNonce = com.chipprbots.ethereum.domain.UInt256.Zero,
120+
chainId = 61.toByte,
121+
networkId = 1,
122+
monetaryPolicyConfig = MonetaryPolicyConfig(
123+
firstEraBlockReward = BigInt(5000000000000000000L),
124+
firstEraReducedBlockReward = BigInt(3000000000000000000L),
125+
firstEraConstantinopleReducedBlockReward = BigInt(2000000000000000000L),
126+
eraDuration = 5000000,
127+
rewardReductionRate = 0.2
128+
),
129+
gasTieBreaker = false,
130+
ethCompatibleStorage = true,
131+
bootstrapNodes = Set.empty,
132+
checkpointPubKeys = Set.empty,
133+
allowedMinersPublicKeys = Set.empty,
134+
capabilities = List.empty,
135+
bootstrapCheckpoints = bootstrapCheckpoints,
136+
useBootstrapCheckpoints = useBootstrapCheckpoints
137+
)
138+
}
139+
}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
package com.chipprbots.ethereum.blockchain.data
2+
3+
import org.apache.pekko.util.ByteString
4+
5+
import org.scalatest.flatspec.AnyFlatSpec
6+
import org.scalatest.matchers.should.Matchers
7+
8+
class BootstrapCheckpointSpec extends AnyFlatSpec with Matchers {
9+
10+
"BootstrapCheckpoint.fromString" should "parse valid checkpoint string with 0x prefix" in {
11+
val checkpointStr = "10500839:0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef"
12+
val result = BootstrapCheckpoint.fromString(checkpointStr)
13+
14+
result shouldBe defined
15+
result.get.blockNumber shouldEqual BigInt(10500839)
16+
result.get.blockHash shouldEqual ByteString(
17+
org.bouncycastle.util.encoders.Hex.decode("1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef")
18+
)
19+
}
20+
21+
it should "parse valid checkpoint string without 0x prefix" in {
22+
val checkpointStr = "13189133:abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
23+
val result = BootstrapCheckpoint.fromString(checkpointStr)
24+
25+
result shouldBe defined
26+
result.get.blockNumber shouldEqual BigInt(13189133)
27+
result.get.blockHash shouldEqual ByteString(
28+
org.bouncycastle.util.encoders.Hex.decode("abcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890")
29+
)
30+
}
31+
32+
it should "return None for invalid format (missing colon)" in {
33+
val checkpointStr = "10500839-0x1234567890abcdef"
34+
val result = BootstrapCheckpoint.fromString(checkpointStr)
35+
36+
result shouldBe None
37+
}
38+
39+
it should "return None for invalid format (no hash)" in {
40+
val checkpointStr = "10500839:"
41+
val result = BootstrapCheckpoint.fromString(checkpointStr)
42+
43+
result shouldBe None
44+
}
45+
46+
it should "return None for invalid block number" in {
47+
val checkpointStr = "notanumber:0x1234567890abcdef"
48+
val result = BootstrapCheckpoint.fromString(checkpointStr)
49+
50+
result shouldBe None
51+
}
52+
53+
it should "return None for invalid hex hash" in {
54+
val checkpointStr = "10500839:notahexstring"
55+
val result = BootstrapCheckpoint.fromString(checkpointStr)
56+
57+
result shouldBe None
58+
}
59+
60+
it should "return None for empty string" in {
61+
val checkpointStr = ""
62+
val result = BootstrapCheckpoint.fromString(checkpointStr)
63+
64+
result shouldBe None
65+
}
66+
67+
it should "handle very large block numbers" in {
68+
val checkpointStr = "999999999999:0xfedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321"
69+
val result = BootstrapCheckpoint.fromString(checkpointStr)
70+
71+
result shouldBe defined
72+
result.get.blockNumber shouldEqual BigInt("999999999999")
73+
}
74+
75+
"BootstrapCheckpoint" should "correctly represent checkpoint data" in {
76+
val blockNumber = BigInt(19250000)
77+
val blockHash = ByteString(Array.fill[Byte](32)(0xff.toByte))
78+
val checkpoint = BootstrapCheckpoint(blockNumber, blockHash)
79+
80+
checkpoint.blockNumber shouldEqual blockNumber
81+
checkpoint.blockHash shouldEqual blockHash
82+
}
83+
}

0 commit comments

Comments
 (0)