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  */