github.com/deroproject/derosuite@v2.1.6-1.0.20200307070847-0f2e589c7a2b+incompatible/block/block_test.go (about) 1 // Copyright 2017-2018 DERO Project. All rights reserved. 2 // Use of this source code in any form is governed by RESEARCH license. 3 // license can be found in the LICENSE file. 4 // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 5 // 6 // 7 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY 8 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 9 // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 10 // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 11 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 12 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 13 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 14 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 15 // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 16 17 package block 18 19 import "bytes" 20 import "testing" 21 import "encoding/hex" 22 23 import "github.com/deroproject/derosuite/config" 24 25 import "github.com/deroproject/derosuite/crypto" 26 27 func Test_Generic_block_serdes(t *testing.T) { 28 var bl, bldecoded Block 29 30 genesis_tx_bytes, _ := hex.DecodeString(config.Mainnet.Genesis_Tx) 31 err := bl.Miner_TX.DeserializeHeader(genesis_tx_bytes) 32 33 if err != nil { 34 t.Errorf("Deserialization test failed for Genesis TX err %s\n", err) 35 } 36 serialized := bl.Serialize() 37 38 err = bldecoded.Deserialize(serialized) 39 40 if err != nil { 41 t.Errorf("Deserialization test failed for NULL block err %s\n", err) 42 } 43 44 } 45 46 // this tests whether the PoW depends on everything in the BLOCK except Proof 47 func Test_PoW_Dependancy(t *testing.T) { 48 var bl Block 49 genesis_tx_bytes, _ := hex.DecodeString(config.Mainnet.Genesis_Tx) 50 err := bl.Miner_TX.DeserializeHeader(genesis_tx_bytes) 51 52 if err != nil { 53 t.Errorf("Deserialization test failed for Genesis TX err %s\n", err) 54 } 55 56 Original_PoW := bl.GetPoWHash() 57 58 { 59 temp_bl := bl 60 temp_bl.Major_Version++ 61 if Original_PoW == temp_bl.GetPoWHash() { 62 t.Fatalf("POW Skipping Major Version") 63 } 64 } 65 66 { 67 temp_bl := bl 68 temp_bl.Minor_Version++ 69 if Original_PoW == temp_bl.GetPoWHash() { 70 t.Fatalf("POW Skipping Minor Version") 71 } 72 } 73 74 { 75 temp_bl := bl 76 temp_bl.Timestamp++ 77 if Original_PoW == temp_bl.GetPoWHash() { 78 t.Fatalf("POW Skipping Timestamp Version") 79 } 80 } 81 82 { 83 temp_bl := bl 84 temp_bl.Miner_TX.Version++ 85 if Original_PoW == temp_bl.GetPoWHash() { 86 t.Fatalf("POW Skipping Miner_TX") 87 } 88 } 89 90 { 91 temp_bl := bl 92 temp_bl.Nonce++ 93 if Original_PoW == temp_bl.GetPoWHash() { 94 t.Fatalf("POW Skipping Nonce") 95 } 96 } 97 98 { 99 temp_bl := bl 100 temp_bl.ExtraNonce[31] = 1 101 if Original_PoW == temp_bl.GetPoWHash() { 102 t.Fatalf("POW Skipping Extra Nonce") 103 } 104 } 105 106 { 107 temp_bl := bl 108 temp_bl.Tips = append(temp_bl.Tips, Original_PoW) 109 if Original_PoW == temp_bl.GetPoWHash() { 110 t.Fatalf("POW Skipping Tips") 111 } 112 } 113 114 { 115 temp_bl := bl 116 temp_bl.Tx_hashes = append(temp_bl.Tx_hashes, Original_PoW) 117 if Original_PoW == temp_bl.GetPoWHash() { 118 t.Fatalf("POW Skipping TXs") 119 } 120 } 121 122 { 123 temp_bl := bl 124 temp_bl.Proof[31] = 1 125 if Original_PoW != temp_bl.GetPoWHash() { 126 t.Fatalf("POW Including Proof") 127 } 128 } 129 130 } 131 132 func Test_testnet_Genesis_block_serdes(t *testing.T) { 133 134 testnet_genesis_block_hex := "010100112700000000000000000000000000000000000000000000000000000000000000000000023c01ff0001ffffffffffff07020bf6522f9152fa26cd1fc5c022b1a9e13dab697f3acf4b4d0ca6950a867a194321011d92826d0656958865a035264725799f39f6988faa97d532f972895de849496d0000000000000000000000000000000000000000000000000000000000000000000000" 135 136 testnet_genesis_block, _ := hex.DecodeString(testnet_genesis_block_hex) 137 138 var bl Block 139 err := bl.Deserialize(testnet_genesis_block) 140 141 if err != nil { 142 t.Errorf("Deserialization test failed for NULL block err %s\n", err) 143 } 144 145 // test the block serializer and deserializer whether it gives the same 146 serialized := bl.Serialize() 147 148 if !bytes.Equal(serialized, testnet_genesis_block) { 149 t.Errorf("Serialization test failed for Genesis block %X\n", serialized) 150 } 151 152 // test block id 153 if bl.GetHash() != config.Testnet.Genesis_Block_Hash { 154 t.Error("genesis block ID failed \n") 155 } 156 157 hash := bl.GetHash() 158 bl.SetExtraNonce(hash[:]) 159 for i := range hash { 160 if hash[i] != bl.ExtraNonce[i] { 161 t.Fatalf("Extra nonce test failed") 162 } 163 } 164 if bl.SetExtraNonce(hash[:0]) == nil { // this should fail 165 t.Fatalf("Extra nonce test failed") 166 } 167 if bl.SetExtraNonce(append([]byte{0}, hash[:]...)) != nil { // this should pass 168 t.Fatalf("Extra nonce test failed") 169 } 170 171 bl.ClearExtraNonce() 172 for i := range hash { 173 if 0 != bl.ExtraNonce[i] { 174 t.Fatalf("Extra nonce clearing test failed") 175 } 176 } 177 178 bl.Nonce = 99 179 bl.ClearNonce() 180 if bl.Nonce != 0 { 181 t.Fatalf("Nonce clearing failed") 182 } 183 184 bl.Deserialize(testnet_genesis_block) 185 block_work := bl.GetBlockWork() 186 bl.SetExtraNonce(hash[:]) 187 bl.Nonce = 99 188 bl.CopyNonceFromBlockWork(block_work) 189 if bl.GetHash() != config.Testnet.Genesis_Block_Hash { 190 t.Fatalf("Copynonce failed") 191 } 192 193 if nil == bl.CopyNonceFromBlockWork(hash[:]) { // this should give an error 194 t.Fatalf("Copynonce test failed") 195 } 196 197 /*if bl.GetReward() != 35184372088831 { 198 t.Error("genesis block reward failed \n") 199 200 }*/ 201 202 } 203 204 func Test_Block_serdes(t *testing.T) { 205 206 testnet_block_hex := "0202b5babbd8050000000a0000000000000000000000000000000000000000000000000000000000000000029c1201ffe0110100027f520b6b172770f100b07e82b48b78d6e76c3441c4866a5395d5e50f9a9e51932101303a1747525e84ea8d329ea58bf2988809aad19d300c9357d457c129d9d6746d0000000000000000000000000000000000000000000000000000000000000000000192d8481357c0777e57edc60cfcf24bbc0c8669d251368fa4e344bd77257dd6e001656a47142c8df3d4a87eda1ffc056289b95cc16060c79225acf8bccc73e27df4" 207 208 testnet_block, _ := hex.DecodeString(testnet_block_hex) 209 210 var bl Block 211 err := bl.Deserialize(testnet_block) 212 213 if err != nil { 214 t.Errorf("Deserialization test failed for NULL block err %s\n", err) 215 } 216 217 // test the block serializer and deserializer whether it gives the same 218 serialized := bl.Serialize() 219 220 if !bytes.Equal(serialized, testnet_block) { 221 t.Errorf("Serialization test failed for testnet block block %X\n", serialized) 222 } 223 224 // test block id we changed Pow plcament so ths test became void 225 /*if bl.GetHash() != crypto.HashHexToHash("56bd1038d603140239d6b25f2ac983e2c8cadfcba3e7065191cd411ade7c4f4f") { 226 t.Fatalf("testnet block ID failed \n") 227 }*/ 228 229 if bl.Miner_TX.GetHash() != crypto.HashHexToHash("e38d082ae3b1906823bc303dfac273d0f003fb0c90867236345e1f5746abcdf3") { 230 t.Fatalf("invalid block txs \n") 231 } 232 233 if len(bl.Tx_hashes) != 1 { 234 t.Fatalf("invalid block txs \n") 235 } 236 237 if bl.Tx_hashes[0] != crypto.HashHexToHash("656a47142c8df3d4a87eda1ffc056289b95cc16060c79225acf8bccc73e27df4") { 238 t.Fatalf("invalid block txs \n") 239 } 240 241 } 242 243 /* 244 func Test_Genesis_block_serdes(t *testing.T) { 245 246 mainnet_genesis_block_hex := "010000000000000000000000000000000000000000000000000000000000000000000010270000023c01ff0001ffffffffffff07020bf6522f9152fa26cd1fc5c022b1a9e13dab697f3acf4b4d0ca6950a867a194321011d92826d0656958865a035264725799f39f6988faa97d532f972895de849496d0000" 247 248 mainnet_genesis_block, _ := hex.DecodeString(mainnet_genesis_block_hex) 249 250 var bl Block 251 err := bl.Deserialize(mainnet_genesis_block) 252 253 if err != nil { 254 t.Errorf("Deserialization test failed for NULL block err %s\n", err) 255 } 256 257 // test the block serializer and deserializer whether it gives the same 258 serialized := bl.Serialize() 259 260 if !bytes.Equal(serialized, mainnet_genesis_block) { 261 t.Errorf("Serialization test failed for Genesis block %X\n", serialized) 262 } 263 264 // calculate POW hash 265 powhash := bl.GetPoWHash() 266 if powhash != crypto.Hash([32]byte{0xa7, 0x3b, 0xd3, 0x7a, 0xba, 0x34, 0x54, 0x77, 0x6b, 0x40, 0x73, 0x38, 0x54, 0xa8, 0x34, 0x9f, 0xe6, 0x35, 0x9e, 0xb2, 0xc9, 0x1d, 0x93, 0xbc, 0x72, 0x7c, 0x69, 0x43, 0x1c, 0x1d, 0x1f, 0x95}) { 267 t.Errorf("genesis block POW failed %x\n", powhash[:]) 268 } 269 270 // test block id 271 if bl.GetHash() != config.Mainnet.Genesis_Block_Hash { 272 t.Error("genesis block ID failed \n") 273 } 274 275 if bl.GetReward() != 35184372088831 { 276 t.Error("genesis block reward failed \n") 277 278 } 279 280 } 281 282 func Test_Block_38373_serdes(t *testing.T) { 283 284 block_hex := "0606f0cac5d405b325cd7b2cb9f7d9500f37b5faf8dacd1506a73a6261b476d1f8aea4d59e54d93989000002a1ac0201ffe5ab0201e6fcee8183d1060288195982ed85017ba561f276f17986c54be81001057d3d696be5ec49d99648192b010877b53197c749557b97aad154d4a85dff4498158ec8e16cb9034562676b091d0208000000009699cce20001d0e1a493c61ba77865f17b27223474bf93115267a596258cb291fbc18ac9cd20" 285 286 block, _ := hex.DecodeString(block_hex) 287 288 var bl Block 289 err := bl.Deserialize(block) 290 291 if err != nil { 292 t.Errorf("Deserialization test failed for NULL block err %s\n", err) 293 } 294 295 // test the block serializer and deserializer whether it gives the same 296 serialized := bl.Serialize() 297 298 if !bytes.Equal(serialized, block) { 299 t.Errorf("Serialization test failed for block %X\n", serialized) 300 } 301 302 // test block hash 303 if bl.GetHash().String() != "02727780cade8a026c01dc0e0b9a908bf6f82ca1fe3ca61f83377a276c42c8b1" { 304 t.Errorf("block hash failed \n") 305 } 306 307 powhash := bl.GetPoWHash() 308 if powhash != crypto.HashHexToHash("e918f3452df59edaeed6dfec1524adc4a191498e9aa02a709a20f97303000000") { 309 t.Errorf("block POW failed %x\n", powhash[:]) 310 } 311 312 } 313 314 func Test_Block_38374_serdes(t *testing.T) { 315 316 block_hex := "0606b7ccc5d40502727780cade8a026c01dc0e0b9a908bf6f82ca1fe3ca61f83377a276c42c8b11700800002a2ac0201ffe6ab0201f0e588d08edc06021a61261e226bad3dace02ce380c8da5abde1567cff8bb78069dae79e3a778ac72b01b62fda03efb8860fb6dd270b177f2e7a56ef7f9dd35a4af8852512653b191136020800000000e899cce2001734a9ff779afd4d1fce7a30815402fd7f7ce694be95ed69ff42e498e40af25c5511b52aff7b16df5e0712a3a5b59913f59658cb7e44201b1a78631bd87d7c3e1dc66c9fc7d5260f6f0fa99914f7a1f35d3ddb3e2a04af516f8135f6f607acfe5314f2c9c0dbe58bc981527ff90fa236b2663ee6d295ff1b5ad4add1c30cb0393d5e287c7ca687f04701485174bd0c7b2ac4a1b8982dd6e1ef8df569f7bf03668d12c99b329118c00d30e341808e94ff8ec31374104b2a37b785def153216d8bab52c3bd48d408e6d96e344344b243a3911e058909e1f26aac10482a4af1fcc86d23116a483e45d705256261ee6233ebc9b4f8993580ed2d9d7c598ae58a445134af1a325d26222418f518df2c8997c29f4495237ba6271fb2d517dd6f66c9c1ced406e5823594deb5f3952a9e80eae87ce2df8a8290cc1c3f12e474bfa38ab12845088a1f543790d8a7b7cf77e757e5299d28d7e206520b259bc55a63c3a8c987c6215f6fb186f6d87ccf299965de42a004ca38aa0d4dd16144adf2d7ce31fa74bc3bce1708e03ed2396b678c85d8d3f4d7ee76f5c13b53312c80a4240d9e6495508159aeab1f330bc331e3b81310f5ba749063677c62ee5bde87129b15241ee895e0437a808b9b03c77b86b8b641dc6bfbc70206415c2b2e497a6bc0e4dcb2ea24b75f1caec50cd2ab6426e91f41f11545d02c01f0530f23d667c4e04f16989b11ee6ade7b7a210e744fdbff45aab0e09bc718e847a5acd68c6da306e0ae9c9c5a97eae96a11968dfcdd414f8f4957ea45fd21f49fef889b86d3298224c3a2d21c4ccc9ff0fff6f04cb4a3998e5cc935afbfbfc79af766227a60a32275ad8480448b06fe78cbdaaa03acab10a6265154bf92bcec87a055e770f8c69581319a5db766b16050ddf8b448d6c784d1ec48072c702c41a864e5965c12eb450c36466f481a577fbeef6d89e8cfcdaea42e3c0dc8066b4681868b57270917c5b192d3a1457fb56bd85f2a58af0979dc1b1e6279c08e2a5013cb5643d21b17495d778dd8" 317 318 block, _ := hex.DecodeString(block_hex) 319 320 var bl, bl2 Block 321 err := bl.Deserialize(block) 322 323 if err != nil { 324 t.Errorf("Deserialization test failed for NULL block err %s\n", err) 325 } 326 327 // test the block serializer and deserializer whether it gives the same 328 serialized := bl.Serialize() 329 330 if !bytes.Equal(serialized, block) { 331 t.Errorf("Serialization test failed for block %X\n", serialized) 332 } 333 334 // test block hash 335 if bl.GetHash().String() != "d76d83e03c1d5d223c666c2cbcaa781fb74e53f8eb183a927aba81f44108bf13" { 336 t.Errorf("block hash failed \n") 337 } 338 339 powhash := bl.GetPoWHash() 340 if powhash != crypto.HashHexToHash("7457a3d344b4c3bb57f505b79c8c915ab0364657f9577a858137f39d02000000") { 341 t.Errorf(" block POW failed %x\n", powhash[:]) 342 } 343 344 err = bl2.DeserializeHeader(block) 345 346 if bl.Major_Version != bl2.Major_Version || 347 bl.Minor_Version != bl2.Minor_Version || 348 bl.Timestamp != bl2.Timestamp || 349 bl.Prev_Hash.String() != bl2.Prev_Hash.String() || 350 bl.Nonce != bl2.Nonce { 351 t.Errorf(" block Deserialize header failed %x\n", powhash[:]) 352 353 } 354 355 } 356 357 func Test_Treehash_Panic(t *testing.T) { 358 defer func() { 359 if r := recover(); r == nil { 360 t.Errorf("Treehash did not panic on 0 inputs") 361 } 362 }() 363 364 // The following is the code under test 365 var hashes []crypto.Hash 366 367 TreeHash(hashes) 368 } 369 */ 370 371 // test all invalid edge cases, which will return error 372 func Test_Block_Edge_Cases(t *testing.T) { 373 tests := []struct { 374 name string 375 blockhex string 376 }{ 377 { 378 name: "Invalid Major Version", 379 blockhex: "80808080808080808080", // Major_Version is taking more than 9 bytes, trigger error 380 }, 381 { 382 name: "Invalid Minor Version", 383 blockhex: "0280808080808080808080", // Mijor_Version is taking more than 9 bytes, trigger error 384 }, 385 386 { 387 name: "Invalid timestamp", 388 blockhex: "020280808080808080808080", // timestamp is taking more than 9 bytes, trigger error 389 }, 390 391 { 392 name: "Incomplete header", 393 blockhex: "020255", // prev hash is not provided, controlled panic 394 }, 395 396 { 397 name: "Incomplete Miner TX", 398 blockhex: "010000000000000000000000000000000000000000000000000000000000000000000010270000" + "80808080808080808080" + "023c01ff0001ffffffffffff07020bf6522f9152fa26cd1fc5c022b1a9e13dab697f3acf4b4d0ca6950a867a194321011d92826d0656958865a035264725799f39f6988faa97d532f972895de849496d0000", // miner tx has invalid version 399 }, 400 401 { 402 name: "Miner TX has wrong number of TX count", 403 blockhex: "010000000000000000000000000000000000000000000000000000000000000000000010270000" + 404 "023c01ff0001ffffffffffff07020bf6522f9152fa26cd1fc5c022b1a9e13dab697f3acf4b4d0ca6950a867a194321011d92826d0656958865a035264725799f39f6988faa97d532f972895de849496d00" + "80808080808080808080" + "00", // miner tx has invalid version 405 }, 406 407 { 408 name: "Miner TX crosses maximum height", 409 blockhex: "010000000000000000000000000000000000000000000000000000000000000000000010270000" + 410 "02" + // version 411 "3c" + // unlock time 412 "01" + // vin length 413 "ff" + // vin #1 414 "8080808070" + // height gen input 415 "01" + // vout length 416 "ffffffffffff07" + // output #1 amount 417 "02" + // output 1 type 418 "0bf6522f9152fa26cd1fc5c022b1a9e13dab697f3acf4b4d0ca6950a867a1943" + // output #1 key 419 "21" + // extra length in bytes 420 "01" + // extra pubkey tag 421 "1d92826d0656958865a035264725799f39f6988faa97d532f972895de849496d" + // tx pubkey 422 "00", // RCT signature none 423 }, 424 425 { 426 name: "Miner TX has 1 input but it is non-coinbase general tx", 427 // this tx is d0e1a493c61ba77865f17b27223474bf93115267a596258cb291fbc18ac9cd20 428 blockhex: "010000000000000000000000000000000000000000000000000000000000000000000010270000" + "02000102000da3b007a7830191d903f29306c448da088e07e70e449203aa03e001c608f95af12f2f027ecf4ed8eeb7d6058e26d22d2bdbe3f6adeef8e0d667cc9b03d9020002424603013e7de8ee9b8e6ef5fd2e9922f999bb411a850d95f7ce3a2d5f8999f60002bba0d9d700cbd279efce56bfad165faf6d83579fb7d5f287f5d0811bdf5e69b82101121bd66a3ccb0f84190333736aff061be98fe9148e49974db672ea1b8b63bdd90180fcbee93c394be919da69be2096f10c50c8b9d42173dbe42fa272b26a2831e105a03e0908440350b3efaa09d5e0886c3923bf5596b76da69852fb6b1e5ba25b01565c570715897267e23f2488424a853595dfc87f5ce62a035909bed4b496de013e95ea0895f23eec31962c3771c868c13fa45d723b66b38e433a622043bc78e4c5a52d00305c9e86d4b4ff49b2a4ee2b1d5eb76a30800470a6f94fbf1b392cd1d242d31fc9ecf19488b37bef2114863b33a7f1014f2dee44299ef486e1bb947002e086e341216fe1d486923f6f695fbf234d851a2a7a3dd205f5e354d9706e50450bdb0a09227ebbd43645fa895645c2a2745da11e223450a4be36c9457acc6fd5bd3d0416c7ab26080f5677757880c2dbad9db9f19bf342171e4320eb534256fbb5a6049871982f4ae890ecb0c0ba17a8f1f6cbfbf4a884654c635d3eee5be9afde470b36b8bc3f09d6a149503dd6dee97229f19a4e37c1d7ef369af1bb0b0409029602246979d528cbf0792b64e7c6c087ac1d149748802c6ec47a10ede5278a611603ac0503b7adad8e18c7937191763d94dc3ed0bef7b3437e065727ccfeb395f00a201a28c4966ee53663164953229f09fb866be19ca12d42eda7c137ff56e768046e7f418153bc4bb9c7f7c85d57fb120b12739cdeb849c5540eea9925b0fd030033d1b00f2f815d9a9ebbd2b4bd98c48d310f2e22b656d863ab0ecfd95164da0057d6576b9ab3905cb5e65be9569dfb10dfd8a35c84dd9a98e90c1ed70153720f0350dd0891a8fd2d7dd544a9624615f9406767e043eea458566b46b978bd9f008f44cf935b85fa503a3bea55b0da4e4b66e0319803c18e6d80db924c8760e40aa3eb2e2f136026757a205d7d0baaaadd6c3e6a4340fcc6047f036ba7b2153b040b08fbc7408cdef798c4cfbe36722630c510a10026bd459793d4974a2a2e470191e02aba9d04956e91c08f4df2db518ba29ee940c33cc01660400b3602094c0394e5f24cdcba8481bf33c308e601d377c7cc5720d969bbff0689959552eac409765a6d699850aebcfbeeb5411ae37d41a7524679845d52cd3198b8a19237a405b5c6190d3bc8f8977867fc8a2799477ea14b50d62dc88839386626715f0d3a0a7052018ccc9dc6db0ae1fd0e542bc76612f2727f0ea351700e96cf7974bb5205401e931729bed0aa81ecfeb0a5168ab547a2139034292147dac97e3c7786000085f61e561b5471615bf197d71a7d68da04be7e16cc62fb1cb9de3e537137bb081b478eae9d9321cc2a68812147f9b998b83c66ce96a698241783ad7b4898b805ee53153a9ce6db51d83e98ff7d9601e8ec42c6fef87870754971fc347bb8f60c8fe18dd6f4d56e9713a812ae2598f91298fcf51be62f5203a9a023cd40760f0d2ba05a89091af62be6d4634c1c1621eecaacae26554a5d207c6edc806816d10d47d09ed7f9a81b444ae3401fec4d51f71de3189c61da53e9c2dbfd8a60a7530cf469589b91d839d71825b88f06d35354404f21227dd2e1dfcba5b327dddb2609f829a32f5bfc5c745e70edd1fd5d0a5e4c3d2d4d07a31fc2f0ac64b0c7778c09e55808d4e4850b58c359169424a421bf5e6cce54ca4ea0d6654e2938576efa0fa93051392239287e3395312c24d59d4da308585108a5693b1412b62d6947c10df8fbcd6c0e7a9e0a7eb3035bbdacbd359cbf7f842f33a529eb3a4c01fcb5f20ae0e80b11655b37f4ee5adb32cac391ebf0695b2760d790ea9ab22644580fea066c85c6dd25f604352532882418cf47eb49f9e4d535e6e6ffafbcc7f7ef65be02194c1734855c1f22f393b8eda73ae813583a9eb854f671c2f3c8ed4a7820190b430c126311dd756c601fe063582aa5501dd82b84fc6cbf7bac6898ac1e9b4d0fbdc98081b3b6d6dba254a332100ff7a26738007e7ffa1ac80ee250e5ea6b5a0963645c3b97b60b7d715725ff6728eb0c2c5805db76939da706e65f035bcebc087b4541df6056cdb517b2ad506f6ab365764994547e7d49456caba9f3ef49a10c36df9e069478168df4f1cee1d240b6fc6307110a7b3b0ddd120f8141e2f4bc0caf5bdeafe8cae2fad18795d133096d3afc5044b721aabd1668874a2657017b02890d79e3c71d6429b74974af532ec2cdf4a972e79203f8d93a3eaa6e0233a402f5fecab9b505db8d5314e2ae298b9ffc96f8eb44ab5c8cea96fe1e0f5ab0d7071fa4f0ae24cb337b134abc3b57fc1b70335fc37f6fb12f9648d7ff03b369af06b32a364d5e31beed7469e613e445cd3096ec5248db21f86f3197213035e66e0ded5932fec2908969967a5f8df8416f968b75c57aa5af99dfbd1f0172186e8e01c04c790a472e0d486d77716e6e9241bb603208e27606a455e6954f6852dd5f0c507226cbc78d8b22555e3b540b395765f45af456877acb91cf8beb61ce6df00549e6bdc1f51e81ff1e59147a76b83154aa2f8f2f5e68d80b2cb8f8b3784cff0370f36bf2fed207846fc45f41df086df61c9bef225445134946727edc072dc8051777ed64a09d8760aa5c8461cb75540ca944bdbd0c072e7dfb7b4e634b82230461d16629d7580165bc01a248783357aca430466995a19b8e3564d46a55f6040cc80fb5be91576b2a9e35c2782ce8dc7e7bc75e2d6b3b9c8fedd912f97eb46d0f30b39e5ee3adebe4a328ea49c8e7fed968ff4c92628ee607f8aff4ee63b09f056519b364839630b32cee55ca54cf1bd63a09c2f62b0e48992f91f4eb31e48403e8f5cfbe41e3b3f6bf0c147b0b84f14c341774378e7c98da843168ae3207030c8fce329d05b28023cf6c674ae629b4f253905037b1a66cc0c790ed60f3d562050a8d2ee488a7cec8eca191577ebadfbe2738092c7eda967d56cd64a454b26b0380edcc30cc1e355963d5cbfcf663efbb8b58c060ef64ec43ff3021756e7bbf02b5c7f7f6c7ca124a716ca66f945babc4c386c99dac4026dab30760bbecf5a40f8f23928afd927341d550cfe5be42a3fd5e911f3f220ca8fa18837e0bdca7f90166fbf7646ea5992faf0fceca79e74cea74a6c02ae091aa080417d346a666050f05470b5e55a8e92159c10d060712425ecb3b3bdf288230d8e6b0a64d9656c204f362e8e990ccacd4d2fc40ee41f60849950b9593d59715c996e3afdc68107d002902cabe8938b887b2a5a655995e846622d61f3316be154193ca6b8319bfcc0cb54c02948297c96d9487f27816709c0428c9ae8a86c1838af2f01616345fb109cdbfb28275c412b7250425a1abbc55f3ff503970647dda3fa818b7b7e290a3071c1580c9c7a06c4789f3e07045f8ea1293db7d63eba6d735cbaee97d101a9600b58b877c6a25f3a3b2026debc350516d1f906a1fcd407014cb76ae2b96351804012d4129c936214e46dd6d53458d05295a462aadee6211d9aab6a15c0ec430005c78eccfd0860bfdf1f00ed6ee3b1ae5aee1c3f4754e0c1bbe6698c1d95c94045bd5ab877a3c469b981bb4d6571b6aa42d071ee7b3b2da59663434fcb337f40532daaca8714b162e4a6329e56bae76142024d1045d5b6dba01ccaa08bd8a8a0faf930cf650ec9f93439540289202c0364cf408079eeaad9fe0bbae00c1bf4e068244ad75ae76172e84f3a89f2d635bca691bbe6274fdce16ea346a13b54f90002bb7fceea3a65b240d92488de9552a49f1236c525302dfb9d20df01ae4f9ba06307ca908244bccbed95646a3c640c91ca9c3eeed3076a001c1f141759986410fea8196e03a3a27a13c6895d4c2e698a600cd73a59a55d173111cee4c9aee2b05fc160b4258d27b5596efa7c9f68674d842811e7fe488fff3032dca1c75028104481fa3ba47b90a6e1f77f30a84c82d60e86722c6862f383d8f8c6803c6275c0cd89c142e1e65a9aef44614b2817519f919734f4f208cee197f50710b987fb707bcdec3a9d8b0248a91b4c658c639ae751921b48b6941b936c3078585204213003a1883b50c09eb76c84e4487f95770bd8dd03da4856e1d8b44bc369fd383160715967021f3499304d073f197c107e32952abad6392ddb8740e2bb4b111555a00867ae43346fcbd98a7d122b49d9d860f59d7e7248ea136eba86c7b9a1dd0940b099a7e20dc2379bbb50571f5b2eb03cbfba5200dac81332f9bb93912d6020e0df749748c3b0ab0d32145ad4c852887efa39976ef95de6a627ab8ca6037e64f0c393e26627f0cc1db0938c7178496f4bcda9f1d43d88945f1fb1ae61a2a982f027b8a7700ac6fa77121c530e2476132e40d15c712461224145b0442ee2949950ac777294af00eb532ad352a0ea5e7dac5acca84cf25fe68419c4976b275982a0532392abf21ece3988d0af12a98f41fb7ca649c83cd1c03fbba47dd563e82bd03beb05c2a9cda8c2505e799f245da1264f382c0360a47e8084b66d1147c6b760880ede8338c2244ab2bb12f73a252acb0d6da4dbe643ceaf40a2d8ee35618a9012bef3406ef4163a62403befd7d3800d3120289ad30b23281f822009ed0ec8d091837ab86c7fef6e66e87305cf7360934ad75835537ef83e3ef118e3bce23de0e183f536525c7c9ac056c92b65861a093655bc1cda287ed6afe6cd85198cd480605bca20a25e214a2136a474e1eb99a5a8610141ba128e9a762756daf56542408b915572b4087ddc1475e45dff5a16f62bbc24ab139e3c6727bddc52b908bd003b2bc03335931f88073ac5ba6e81e042d6c825626eab33f49d7e4a90a20416409225ae4aedbecdf5e45ba9969fa53c2b6c1ebefa64927ef594b8d4b037c3ab00115cd35276d2c65b7b44e29921c757c700d7d98f534f2683cbeda267ce05417066f9b7fff2941e40fc77774ac2e7f25bb5eb8aec522951218fd50f7257ad68e0318748228a1a8876c1f9174d0c5f9b5a54ac0825a2a715155d6858199c7738903a6ada468cc578505fc8973539c29bf1baef3cf40386d5aded793d83b2cf2d50af25d4ce277937a59211acc8afbcf9cb3bbb977ad7696ffc1abd77e414a54b90708ba3184124607d63e81a5e2889cf292e7ab046d23b5bd0f25e22a794e18e305ae8573301112149f7cfc7f01af7b3460eacffdc306894cdb93e2e86bc29b840a577455775d4587b4c9336c7b26a4a89620d7c68d8fde193b1f3e04dbd3a89e08d29659d622b5f86f06f22083e43e96bd3bda7cfbf0038d25537de99982977a090c05d28914cde10a281af467ab4d132a7f49a5692bd1190fa5173e5297e79d07d3e0ae5e8a39a1549c21d5215320a97d505b6d5d69dbe9e4bd719290c2779001b570bff3fc40fa45550f77e1e820af910151d40942ce41d08001dbc36cdf5400c0e7ac44fe7837970ff4a4a51b90138fa0e663b174cc2b30b659af1633ce0006166a950d3fa8274bc148e898e4c81fe9a42b663c09ca2e9c7b331350f2576c0859f7342d0dd4a2a0677082810f268b0d1061e558a23217d77ee05acc48af1a09ad15f2951f2390c9b562e2a0646c15726017c4d631ed669a43efe4df0c0dfe0b69af3bfcf7fc8927a3bf510aaae48e4abc06d1bbe818cf83943091eb1f73d6085a9977ffa45d556f9a6eb493b9189100bf1f72a1909d9945c4c15dc9fc8917026c7f9a381ffb0e5e7686b477c4914c86ece8ce0e50102182c422ff054217180057783bc44bd6b031e6f45bef4a78cf5b86addffaf376d0826047527ee9eaee00e2653617a171d08f2cba67a0cd2d51ce1d6b2274cd65b7e11273d9d8557432051ece6c8abbeeda43e89ee57c61ee74306783330d749f97d8ec42821699490e01f1a328921591eec74b920eceb91d05af3261409cd2138cc5fbb724875a21fb038e4e36d79ec96cc6e9296d3a210ec4831d93e48a54a8ebc38d3076123e371807f81c48aaf20656831f3794ae7572b56892cd8de7c0b22c7beb8024565af44d03d5040b9a64a7af5a61bdd470b29bc3f43ce51dd912d3df9fe1ef710ce1b081034607cd183d533963fe0358b0bd2db820d8da24715dbf357a7157f5a781a61703b9eb11599abdabbe8a562679fe6790e5347784e61c957c206e7a82437bfc9409528f500da2e9c75eab98e0e498528c112be6ab4ecf8d66b34128187dbe845001bf3f007705537b0f801065128144da8480d9e6be0528b7544c1afa9d701284a502717f33449c9a65319e8591d0db86396a50a2089dd8c10de1979c8293fae09b6bfa8b336d858372f887b5a885a5f9393f5b109cdf38435f7b6571cd91732827b53d702d869cd9eb6790f05ee140df73752dc51315cdb2d69965da71a4bd4595b8ac1ca6b144e7d3f0f18e3495efb23d926f7b0b16884c12e573fe3c5e5a1503f5381635c3ca2ee3914f63d1e3ef61a8e9845ab434ae4d6b37bb3c1a5b2af0a5dffebc587fed7d25bed2efc2a0dd17a26040408c9e07c699429e720923cbb26b4acd02fdb45e52426dd7c76f5c3b9f30fd6eae32a99589b85636c00c11de54687c0def9702ff9f30472a04fb778ad1f1745b0595b3f5e6ea77e63ac4d46ba18c85996646fba0bf18b76762647e221a143e1d781e9be85881ac7d31a4d64de85abecacfc3e54b1d38d5cabd7dbf93fe811ce736fc54e6cf5eb939828672a0834456d0a821ceb0e50724b6a6595b7275c5759ef9e3d5330f714e9c1f1a0ec2f762b61adb6b6c561ce0f615b2f145e9b144c935671e3a763b69e9ec5cf11fe06993a9aa5f4f55205cfc3afbde63eb31146a4f1208fa4f345cceabe69c13512929bfc847d74906efd46ccc903c887a81dd23d5207379e53ab6be922d06650e8d9f137bc2a4694c38d337cc2ba84f647d08c3672fc0bc9496dd46528c093e7b1652309e1964e1d78a9fcfdd51b07945e1d8bdb98f0dd9927e351483f27ffd7aaeb34f5714fb66452ee4dc72344404c33fa2a3ecd5e3bdf38f79ea50411642774eede44e41b5a6a5261beffbcb70d87c4f84fd1c29aba07dbf92b882737ffe33cb59630aae6c99255dc2fb47a88304b6d1d5c4e11fc0dee57fe40566fa53789e9d53d02d487d127a074abdfb0a90e50039d05e56ce65bcf543c60ae4265fed00112eb77ea61b215e8372482c6dfc5065192a90c5e4005b69554a0a0dbb3394e9555a82e488396b771ade4012d3dbafb9426d1a1ed673d550ffa3d0e9f193809856a3a81bfed8f13ac20fd8b169443d504aea243df952dbc5153f9725cbc5ef87bf061153312a48d970f430245908d70ba6737acb534edca9f08752fc7035549993291f6ceb5fa1a6f42574dee2300aedbf12c9437101474708dbc40f642f9a79e9fdd0a68840d3d7e37f04d5a8d39993575032325a17f37ac332d917121db0066bd31316bc624cf6c2efc7af68a9ac3ab82a9bd0816829c617ac9a6d1ae934c0e09b5e9fd48a5c5dd872702ee2b8b8a9b26ca1fd62531c778d1b60cac31fa13656d59dc4b248a10950cf5bce65f23e56ed34aca51cb490a92325762178ffd1eff4f98e1232d85b1e7d55820f5a4d86ab5a631aef2016c48728cc615c9cbb1bf3930fc92c1f996c74f0853362e712d646d9be4c8764be9a813a218aa3839a2c3a28c58bc4cdd135543c577bb19d0097607f4b8dea4e734ce60f903a0f2a2ecc86631a35fcb2142330d419ff603ec2ef0786d744ffd9b4fb1704f11692ce5d305f87ba869b21020aed34a91fc2581f1cd2665e9bbff493637ba7201291e012b1236601d50808d464b8eef3c2e371ee43268a4092a16f2ecc3ca68169be24a870e1d650dd942373c29382e6ef8044c539298e7bbe5f97a6b9a0538b1c31b5f3f80bdcc3ecc7c21c2d3309c08c67fbc3a06383a5fcf51c907326937383609daeaa904fd9eab5eb23ef3d307202ed6234d32e3ff80504cd5d836f4260409eb26d205f2cfa0f11885b6a8ea2f4a869059fc87f993d60b91ea7ba9713e72fa36bd5a0ac846d225ff8f12f80bfe400cd79dee2534ea1d81d78da42a082d32cbea04c41b6122e18f19ded13fa80b115299d0deb5372517db5e279b97bb5f41a7a2b99434fa0192e5ac2e1ed44112a95746da6a192738b6cca0b9869a94d7d24036e4570472a7531ce079da171df2e6f77d98e001cd46a4c2a668ba056811009d0dd8e1316a8f242e6b25702ccad2ee0a0d4b18625ac5da2dfa3673a1001b8a3567c71e35d7a2e0feeb559d4287d85b2a0ff0c5d8cfbc67e1607f6d92ab2ed7554878045d776b8cf8f24a864f2110ba2f24f7e02e6af17ac858bb54f3f3e81e4e8a74b2b7d5204d43a920ad3176e10f0450abb7005049f71b83deb5d226cb590bce4b447c4a50603358c84fbdd1dcef0d4cadc70a6a2a3c366a3b9f9649a3d54694c68d35c2d58720866ade086c048b829c2d4574e8d0a75a680b0e96e89e9b7ed8615f652ca956fd5356e4eb74912ac1924de0094928c9431735dbf1106953eb47bd400d0e0d4bf95f2f3938c2a470690e18675da2666c1c60d1878c618e81e0fd9ccbcf85df878405c38736f766227d5fd2b2f77cf3059424e91335317bd938951fefbbc95a0e8cab7767c58b4dca29bb59b97ce3f9327d85d1662f8a769d5fb3de6e0e9adeab2aead39863c2c81d1f710ccd5e356d261e03c17fff949119bda86cc997579c735ffb4669df3e891a27daab8b7eeef43b7f761313b042612b1b7508841e78290a4a13204b1eed0d6de09801a8e1ee5204b2a7ad99981fcac275e12d4fa4f66cf7f4bae7b48b782582e8980f6e3a50302f63a1b15e6bf1092f3d7f55d6aa45fa13871cd42d9845474c38a50b3a901f5f2552fca8b0d3cf1860d8720021edbe6fec9c08bae1e13e987d2cda8ce11f186d7e8562335c52ca2f1f8524013a084f71c4eae2915eff7bd5f2742020224c50a9cab98fb8dde1f0a4d0f14b6f405c39f71db46769b615eb0909e9f45f9cacc69aab4699e5c117e6d4665f6f2e3970601f8fbc07210d2842f8c5990087504695de9ef320e7a866a54b49a3eaa787fe97f3f89a31d35f6a355b5f8744ca6eb696670b184de69a060411646a795202ceae647d5ecd6043cbd78325fedf5929d09d4edb8f9107eb32d1fcafff4c92fbb1fbf460f90dc6053788f3f53bbed94a2d340ae41a74fba9b024aab15591e9ad55975d1095566770743f9c89c26e23901efec3283ce8963c00423d167993e03d69d6f8a0566406c42f4e9cecd2ec4e3c54b38796224b54288e21ca14dbb82dd318e7f99020d6efda2ebe28a01ebefebdfafdd69f7b58a85065d04a6af649118fba1465d0a8e5872d7711db0990332bc53e94bccdd15ad9071c70cfb8b5786ff4bf6a93a08392009c99277090d8d919f4a6b4d686f295b596ec6a72f5f0bd7de7ae4a84605df27ae7cfa69b836af4a761d40ffa2c9b014af3f0e40ff7e14db9bd1fbcff50289851ba2c34664312a9e0ca543ed048664e956fe5f2ab2d65b82ebd31c745e02817b331cc3533ef8a2252d468b639c9863ba067bcbd169d5725bf13307f38603729fb6cd9e3b574c1fe4e194036eb782dfa83d8726e804fa3c1faf94de440c0af3ecb01a5e70953140b12c801e32722330006e74f67c3282bcb540cab6d7f50a6fc5a0251921d6c14bab4625e074b056a4c060baa7d741d23a3cbc558efc170609eff682a47b8aa9b3d39007e10802044d5482c649ccd57b517e352d7fab09001bbee1b2569f421c02a4380b94aeb7be3e676a4aa672a03515e4d839bdc9ef0c2548a116a670cbefa32fba791dcdc7bd5267fd281c369ff7f2f2db60df14c4057a267a0dc9ba307e7074478beb5e8489634f7ddcee8e2f74ec37c69bbb9f230ab2b63d513e5346087ef83f2508dffeba9ffa4cd1818483dd78ebefc1feec52022139a4810ed8039e3a071ae745ca992970819e5548064c1d337f50e4428299051f8f5831b3f155ca57acb78c2be03b716b516bbfca6a4a65fc39dece47fd9f0c4f14fcb6cdd17a2411673f776a3c6134015233aff0d1db62986f01696178e6087afd744f06b9c87087e1622f120054fdba510e8a21e73f707aa27db9bdf64503a912b5586ac14814b387c0444a9c0f6d4046490203baebe675a15eb1f5ca470289579a8e4ed52d2618bcc3713c4cf737778f8a817d65fa937e9dd9871e59da0f6d36aa145a94a00eeb4dab826098083ccf657921932470f3d15149b16d6c970cd3a55f9475f8241c8d43ddc8237012a15a5e5434a62871f40b316221da5fff0a81122b753669acd3ce96519a19461f2e32851b8b5275a707b72465ea484d410546a2432d98ec546c4cc9780a1396864afedb8fdbe0d0459cb57df86ff5b8eb0088f25fd65e114343954638510385e8d505845471ff83652f6dad5ad8999d9c0690acc8b7d29446e121e7b91276e7c077800755340d03b9848449eba7c9c9c60b68ad4fb92fc3fb607f8a7325de66fd25b76c2e87501367679fc2e9a6b0fdba06402d54d9fea13682a16dacfaa2b92f86b701b3e2f06ad838857f2ae1c9205102aeefae82895e65f1df6f24e88227465c13cfecfc9e0640280696f7438f273b0923c3a067c4769df91968e956fd926716549a8eacade5ec61874b975667400e0bc47388b50d092c01857355836e27b926e184cdae72f9a64d2543d93974c4790de4f73f1470e91954ee8de5d144037ece7a49cd42252f74161c3c966e51244703a27a37099d01e98c716198402f5750bab0548c84deb5fe937eff48dbaf037c0edc08f0d40b2f928a35b7ee731bd3d947387e72c8f7b8bcff1b1cc49761f5470f528d0890e97da28dc9e4abba4a258b161ca615c3709d8fa8f68a625f110236009003df8a4e24c8311ba8f09a08f7650ed6b39e2232ce133d2b273736d021a807f519a607f15945eba616002c57192ced90284ee7d34d892ee96429001efd98052ee4386da7690ed548d7cd0515a472123d54c0f579e95213fd63339c5f0d160c49b2168bc165f0441659010eb7d8612d88e8731a8c49a820a6c961045764780422a0f6d0c5b713fc8c0f4e29c357efea08c3fb8a14d6f4c84c3fd577b3c8230d95121ad6214bc7aa2b7915659df893637df2453867b63b39eea80bffc845ad0715fd1cd4f69abfddf09300fe84fcfc79f4fafe2018009869d5a97e9509f87e0b2a1726b96bef22e405b9aacd1d21df707ecf2db40b58df32ccd6690c0031a5076f20c3c0803628fc06c2aeebe8f60196041929fb4dc14aed67c14b8f6855820e6e2ef2d89de7d53d23619157ce69af8d3e20ac95b422281937bee030435bde04ef68d754b46046f9ad240f4127b30d1b4e96da105545e51c1f74ff2bcf4ea301b38a600eea78731b4b9fbd42bf072aaa46859b267486e2343f09377b7003c804000ef4ba1559fc4be7046f1dc450d30a5cbb9641409c3b5ad1f3f9720c338c03ab09742e7b796e70e38e71a58020278f0d610840826ddf0a40c630ffea16d9070648c12ca58d5fcdfaf4206115e8a32edfb68025b34a53a4172f2d43b3f97a0c8addab23a9590bead1ca4a346b6c24dce051d5b1877a8fbf2735760c106aae0856452c006a094626747b8f842762796e4098a5ff3800eb1d845cbf335d273b0854f0ff720c378dcd82e6f0f3145b9604d9f6d3fb6be8718688014cdaf8eecc082b42d0b1aa3c1b65c754bddcffac4664b5a4b344e8ea4409c0a21c1d907db70d9cdcbd2598d009f172d9379d0df85b1d1b212a8ad0e76da1fe45a58fbd73d50fb418571c7607367edcfb85382adc61f1e458f52fffc888f7e5e4a9e7934fc409998334b30af055af278703b357b150348acf93bff1dbf289ec25f78b9e4ddd0138ace5b07dea9ddd12d0b9dd8f0235e9307f7752649e2bc5b2dc7a7916eb3205300a55ddc27d92744519b6a48e6d4bf008f9b6086b6b37b4372608145b86da091c47a5e8edea1ea5cb3f45561bef042ce04de2525ccac2c14073f3ee9d9f4e074431c40537f8576cbde5962e35cec5674219455f75eb36efdae5f3f7b43ad2005717801bbaa04c5d89d0f99bfa38e0d7fa1a7691e5f62f7b5cb86a3d72d5790fd6d7a7e17594a13ff66fe4a92c897cd75618ab1f4b80db4146737aa813d22003be5d1cb1e8d9370cea903e8f3a38492742aefd6a1775f0d791d080185acaca0661dff75eff83f4dd61efedbaf0ea8add0791d1c55efafc41dff6db100f015b01b55459b6e2e2c6adddab446a64fec7dba45d2176762c846a4b364696c9a5cb028fc9fbd8ae37c43fdc67221e3cdd4336192b6fc358391b578634943c0ee60b0f54f7f7082ab495884b15ddc8c731573458d02615acc5dcde97bcbb4d8996f800dda1cf367bd346dbe5aa771fecaece17be3edaa392960502865bc7759fae0405b9a86a7b63b65997dd99cb160ebf9c10c6488c8c1b93b7a28f291fec342f66092bce09e85dc0097b5b1226cd0a3ee1d63b1fe6260409e2b19a23459f54e8ff06716b2d4500eaed0c9de2d1b866c311086f12c8f69820ed58dea99ecf16d97006076f90c3ec49f85188453f0656180bd6ad45d24a585478d90ff993d65e76b70a2c0df3fc3d51bb70dcb49bdbc74939fb7bf114bf2c1ec5848cf5fd6d2fe486026a10af2f1cdf5892daa6dc371a0a2b475c1e5b89194d2455908512ac644d90062cb19d91654cf571a6d7791e21a4eb6b4f975213b9177489075490e84abe360b632801fbecac16a8b986e9e2b55c2c32bc1635955f3cf11fdbab03173ab3380bc1cf3c6cba721767aedc4b595797b917fdc0ec82ea03048a1673a927bb70d000f5dc254addf719b9aa6e108ac7dcf2ce8292bd7ec946db2ac265dc644af78904d883ac58288ba89f2b160901a77e45f337f12b02f0d3bb4efe7952c94072fd08eec3f9f1495e443873e2f997e652808d740a7ee5bb198ad448aab21750bfeb02464c2c029bcd3c4bee376a69006422ebc3d45b812254aa58fac0a2abba20b108721d1ead3581b7965d94ae788febd5f110947a60c3e146ad14068e0a6c47af05de9acfefbbef3e6a6178c289ca20eb0e09e3f72f25ee30404da2bdec75b3310a5a177f5a822920faef0ba6328dc7432c479b62c87a4e4528ccd6b65aabe019079e023c7dc848f4dd9f1f1f262def7be70db031fbe7e3854e4c3a9d5df24b2a029b5785bacdc13f6597ae055109aed0e609104423b56ed4165593f649be8358086d511f0098e27eb7e8e4d5beeb3af06c31d28865a8aa4e82f2bc14796eeec70afaf11af54c1e22c3e3ea8043d2549be8c9d8f7ad34a96b485ff657e82a0dd20672f2ca42ff48811f9301fc5e19cccd94dc7ebad78ba510b46f023cae22ba7d09c63be94d2e57c3519ebed74cda1889aa7e9b341beea8551f967ded767309e20f2fd04a4505e9c07f832f82e516833ebc9e9c31f19ae0f2d48035163a9a31d00442213927a27d39a326f717d29b58d7ddfc9eff0352c5a6214f13bc50829515095fedea297fc110131463dbbc3f9bfc7dabb1c432774eaa91a911fe73ad8ef501f2d015bb2eaaaf27c501cfdf85cabd5f1dd4b7739e78b452175691b55def060bed4131ca1a1b690528592506253d6cb4e37539f5c700b1e01b757f05a4516a04801c48a618a1a799e37a56814b7d1f2add785145175d78f9eff545cf9a9ba409222f2178571629416abd98690c3ac5a85ad977495d9e59e38f47189f2ac3d40bdb49609a4aa39c99aecb8e8078302ded060dc4e56ee1cd4dce848b7faf56490994cf7aaaae1339b1b176a1976c010c129db71be12d423a3ae5463765742f3a0c9debd90e7301891b2a682921ed2c41c2170a6dc5aaf7aae0575332f5e0d4d305e2abdd3a7eea75ea8ee195df9e54852f8527e38fe58ad478973d7bf43e221a05392cf1c720754a9fd941738a6f122279a09c3641a11b5d3a359e27df3401c201d0f3fae81a1dd4a0d888f1a87a688baac84f9b4f15cc8f9a97cd23748c3f1f06b51a5f9355288753ffa4af18cc6e04c63a0ee87494defb26391517da512d520e63d8a2d930911a06b12e38f9102a8ab3c5840eb5e7af04e4f0d7b579c8146000a35b81855c31ae4ad8883b88f914034f0f83581d5ae7ae8797112ec3f9ac95076edc15bb6ab2963883ae642d6776d24ef0ce382d3bf9505220eca2ef72be5602e8a0dde2272e457044eeaeee357c167f4ab6c4d6b6152c64e3e06e67764528028fb8f93cf70c74f883eff9a9673d3b633348f96b67fa9cb1e71e16f37baf8d025774ab6f14fe12fb134702316a2d1b8e74a14a8f47a0005fc641b55f59f22b036a49ccf82695fb3167ab261597a71640c48cc3ee92998e0b0d2fbc42a7328508b05fe1c3af404720f5fa20f314c8c66f3899b9eb3a522c20aa432a0c9e6ff00f75193df78acdf8a2a06dd13f94c038dc80533951024d0c573d627c431a9a8a04adf8785a1bdad7764b4845117d17415250befaf63fda7f8a6ad859b54e8f6006b8be48250ad250d50d6b7dccecb3b78900c912fb1cfd61dddcb60abc29a354042dfcbb4d9bf5d671fdf064f16337252248ddfb1c9fe718f718e047649e568d0868419e8a61ace8725703ad7dcf984e2287f43c60f07efde0c04ea8fad62a7f0a3f55da4e482395941d26342f8f5a05f1510be04722efa76c0d46644a29f6810d27a9dbd556140d0da822d46af28c8b39922d2a1df14bf3444e80558c2789210a6a543143fbd0891e10754c0c4470985bf64d6b41f8f6b1703257df539f721503b6900eacad33f32a469d39b0cd6e85b8801903c4a26e4d39f4611261e142da0782e1b6efbf1f75015bbb65754e57b0269bac63e9914e7e7c422aa598ffb56f0a2be19f9abc31e0ffa17123053a23bcf8eb2c8f81e369fa9b7082bb3e12a66d0244186df9f980c8af9aa8de23f8af390963371f96ef29093f85198f43f432650f7d4b5cc3a10307dffd1356806c3ff177afbd6ce75236cd968d39759065150faf8b77b4649e7a27d85a11c074366016ef2288dfac9a1be81c055162f6ced2a267490e46f097ff5401172114b07ffa5084d9f847db081ffbdd1fee526aace221f3e7302dfe3051b9025ceac281e1e849a302cc35f99ee7d1be38db8c610600f3f47f6ca5686d8310e6e86c3273521ceb2331fac241b560227df4f665228f0d400bf23e5b38312b8f3470a721e80b7fa2faeef1cbf2c6737a53ae9740244397f257452c9307d3a21fabb7f5b3b4313bd64cbbac5cda3ede550d9692d38cad6f0dc753c0214aec42671a04664b78066b5ab21ac7f66398cb426a00360518cfb0ec2c3d8b0b0031e7be639c8546855852c621b0cd280741b3d4f3248e0bcbcba2f01aff1cbfa2ccef6667b2667e989f2c2716e877810d927d3c2ebc36b7c30015c77c970a1e0179bdcbdb05966262226348d391b0a6bfc32a5235a5b7d890114c9d7a79f42e680ad298bc877699ba1285571ba7de0092f1ca05e502554cb9fe386967cd7d1ff95fd9f71572a1443b18a99cdfe299efd9a285f7e9af24cc88f56dee47ad96b45989eaf34e9d7d5e13f8ddbb8f00a0b09ca0edee729eb3bbc8e4ee2a8f47242845179b08fcf803529ca103b585d214329f3265fe08659264e777b769012e307ea1857c918a06bfc98e1b5abd30f670e61ca1d7e89b1c69660bdddbf98cf2659b356ba2897764a3de284f8c2cac192137dcdd6fcff19a504f18c7ff322bb14eeaad2b7328b453d0512b4699fde282739f606c0ce57ed89b93e2fa9a7c6f217144d7d111adec314197ae5c59cc29797d11e80552080ff72405fecef23452331aa4c101718bb8aa644ca2c1f7aa9d1ff37702b7cc0d9565148a9a71fdfa3d229db78fc4e02077b3c22c24cf08cef8199a2249602d7484147747772a801259f1f5a5cb0d63988603d1843e4b89fe27cc33ae4662956597281725aaa7df7cab6b7242182a55316991c97ae78ecc7488fb724db87a255e05d20b0cdd966c5eebca749755d05193e9d5f2a6f3d2f02c79df8dbacd879f8ab3a0e6188e29428c0bad0b9709720637e7f9ae00a238339bdf9f350a534f98b483f45c2fc672bb40e006a66f671acb10b10eaf95b21a48cde450ad6dd235f6bc2265202d4f35ccddbf39408e7dfa4a34df5526b9209403abb6ac5e01507190a1839c36735678266d1a8af06da07ced4794d9a11170b8b0d29d5bea0b9c23e4136fcaeddf5be878d3be105c3d7babe763da980533b8d5c00283333deaf4c96857729f0de65b8fbb3552053f612df880418092e678bb99fa2023a374845c8fe5a61add00e0adf37b2ad913f1ed369ced6a09e0e28b929e306b1d995c96cb137576bf99940dce05c2f07f5bf94d97490331daf79e68917e844d4772429e9389756217a7229b7e9be514011ebac5de10e94cec729da48a1d14676f189e026181a4092bca8f61d5b14ad0350e658716067e71ba9175a0742b4e2778c97c4e5d297a7ae084500d5b145c5dad4c6be7d1559cb67348c95a41108e6a01d040d1f522715f0613b210826b47f14c3842535cdd7f343410616e3fb656b1d75583eda0517f2974958aaf342f89270e0463f0dda529349dafc6f1eb0d7342128e609d9dabff683624d1beb97429036e5895554bede81c84b17eb3e293976ea0d72d851e9d116b4cac7e61cd545043a183ed1ec174a186386adb3317f6183c569257cf26f35b98b31c17ab79e8d68b1b961ba046a95b1443ceaf9cc797a7cfa067d9db42f6dfe75b8763b33236292c9652376fabf1359de0809599be3b219798def5ae4d353be09c048e7bb12e8fd5cf2d0d85b1097445615c5b3656105d0ceed81b385871a0071907f705d0a8524e552b898a72a0bf5213f7cbbd6174f0c9949f34fcbead4680ff2c757ad04a5b00566134c412c5bd7687cd36c250c1849405a25f99f9e0b2fe7be477998305cce1c1ab7369b2f4ed847e61a2da26a549edc86e2d5807f55cb1fb44c06941572d10e7b9108cbf9d6dcfcbfd273439aea9647a3ddd096da15bc7aa19b5b59b20e6cae7a8666f7dc4a96ab03c81f80542fa7cf97e3dff4d3f44d66b71847036ab0b95534ddb0f3a0386e91de5a6f7744df5489169913e2e9c60547e4303e829febd10d4d600b9def6018d17be6e28ebd7dc6b67ca68f3accbe86510a1af87bdbf65d9029eb4788a3e5e6d7fd1dffe85316a738f79f3173b7d0b0a5d78bc7ca5c919229d0e1d42a340106899fd5454c9229b836811bdac6e62b9c7f6e0721b4756c98270569855a7552ec1837562200cee4312b0c510601d353f76888ef1aaf5f0285b0577e79f90c9af5be37c29964634e2aac4541c9ad97f4f45ac845703bc22e77816981e1e0fad0e5513980ed0ce54e688e6485111886fb0170ec90cf9caf05ad81146d9d1888c433b2f2e9ba4d44c45315c4c319536c959c82a00c6fa1064f00eae019e8a7fb9a8866ba4223575327e1d2369e5a06fcaf55959968e91f24be756a3624197204430894200a1024afe368af484ae817059180b8810780edefca8b83dc0770da8f99cabf6103b98f3b10e49437b1b0fb21e17df80a3f2ec98a131e971569f54d21bc1a36f96085ac7e7e749f7c7732c6df3cef5106a4c710811c0dc0868053a202c605814610c6388070618e67b3ddfe63bb00dc60b10a80304204bbef8db21d53fa411a9679efd4a95277f3cd6d304aab5eeef23d1073c74e4870a73c4b89230b06484c9e81659df065d6241b387e14428758c2aa86bd225d6708ed31b11bc5f1a10a9d4be03bee814223aaa178b505196f71691a154b4c31b98806876c06bfbd5ed8dae789525ac5a2c33182a9d495e409560cfe577c83e3fb20dd7dcced2a4f997c33b7f9f9555c2be40e45fce468f3b32bd537b28ad88eecf0b05ec812764b10577942c828551d5a77c382de6890065b4c2341dde0c101b434c021f00fa2600676c442569b529fd5d4c792758d8af4699449c541bc9e2043de4071a42d5fc11b0a86aec4f6521c8dbcac758b8ee24441392f900405d2399d34e0ad875b078a09f613f7c7f10d1d90ab4edf7fa8a1c93fa7f97085c9163a3775c09cd47b27f71ff0d09612d378021bcd43a08e8bcd3b6122664f5fb8301d486da0e37c69d7dbbdca16017dc1b6a533f9a030756ecaadd725e7ef008fbfe88035b0d56169ea19d42d42810a8f9e745de37a6a9bb54451afe1ebf2f1f6750774de703ee385d251a97d034353310f56c5b021ff161830da75582d7e25ae7a0e6c8030e4feefd8a09cd5fe346f5657c11bde29873d635ffa32a9cfc2f9dbe746b5e5109214adde26d55fc7fd32f33754f6296e4d8af0ca4436b7ee1afed3853db06b70b57ed8cf86d6b7a64a1157319bfb4e3c192855443695b061b2cea6974b7acea0de6141186564867898e065024dfe4725ec3ab4a1c214fc0ffe657bd967d039509c8d383dcfaa0036a5a94060e6e4eff043bbd002320f875059d1bd5b31d0f3b089dfa4377f27864c06edfabf3275d9a67487dccce109b79d947d37e75105ca704f9deef2e758f6a58104fa66a5b5946aabd35f4a48ed30ef4f0d55cd599ecc70acb49b388e2c57f3300e9a3f718821572dff1717539785c516d901a081445c702f2aabbd97264e975dbbcc99cd5174e16311dc89bc17725cdf8294742d77edb03791aa2bc92a0bb6c3ac6b7c864990cae1cb7387c6bf8bfbe8f4a560b12f6b20eb97420d856541d2331978385e1acdc0ae7840c926b1f471d55198a087d93d80d8ae760a71c56d67c4845f7507e1d1838e7edc68402537cec3574c2a19661e00b76d5b7562ccff0456885be0af993d7e2aa0ecbb0b7d4b412b5f6f14501ce070bc8c6357345c3e75d2a9c4ad83b174b0f3d7c710f409ec2e94b0b679ead57f6061d29ee670f06dfd66cacbe7e9a5ff597bcc9bed590efa4b4f1a751faa545d40ec1b2063d770e54023ae0dcc892da00197839cfa3deb813ae76e137e9a0e18f03a67d626e1a40f4c128b5262b5c15219a69db5cdea04c6da29876f71559e73105121feedbffbfda70e55a9dcfc7f3ba6ac3269466105ad7bcb8c0d867a9fb1d00", 429 }, 430 } 431 432 for _, test := range tests { 433 block, err := hex.DecodeString(test.blockhex) 434 if err != nil { 435 t.Fatalf("Block hex could not be hex decoded") 436 } 437 438 t.Logf("%s failed", test.name) 439 var bl Block 440 err = bl.Deserialize(block) 441 442 if err == nil { 443 t.Fatalf("%s failed", test.name) 444 } 445 446 } 447 } 448 449 /* 450 // this edge case occurred in monero and affected all CryptoNote coins 451 // bug occured when > 512 transactions were present, causing monero network to split and halt 452 // test case from monero block 202612 bbd604d2ba11ba27935e006ed39c9bfdd99b76bf4a50654bc1e1e61217962698 453 // the test is empty because we do NOT support v1 transactions 454 // however, this test needs to be added for future attacks 455 func Test_Treehash_Egde_Case(t *testing.T) { 456 457 } 458 */