From 3926d4c2592f41f5311bce6b27b9b74315aba43f Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Tue, 14 May 2019 20:57:05 +0800 Subject: [PATCH 01/91] Update test contracts submodule: support coinbase and suicide. --- scripts/contracts/tests/contracts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/contracts/tests/contracts b/scripts/contracts/tests/contracts index a7b95c771..a7a2ff2f9 160000 --- a/scripts/contracts/tests/contracts +++ b/scripts/contracts/tests/contracts @@ -1 +1 @@ -Subproject commit a7b95c771722f8bd4f3db5697b388c06434067f2 +Subproject commit a7a2ff2f9d11da4f9f944e268d70c8d274678de6 From 6b9baa857a979ad5a1aef27247a216d9f50bcdfc Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 15 May 2019 11:13:35 +0800 Subject: [PATCH 02/91] Add test of getting coinbase using auto-exec. --- scripts/contracts/tests/test/integrate/auto_exec.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/scripts/contracts/tests/test/integrate/auto_exec.js b/scripts/contracts/tests/test/integrate/auto_exec.js index 9dd79d613..4f30830ee 100644 --- a/scripts/contracts/tests/test/integrate/auto_exec.js +++ b/scripts/contracts/tests/test/integrate/auto_exec.js @@ -20,9 +20,11 @@ let param; let hash; // test data -const bin = '608060405234801561001057600080fd5b5060cf8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c55699c14604e578063844cbc43146076575b600080fd5b348015605957600080fd5b506060608a565b6040518082815260200191505060405180910390f35b348015608157600080fd5b5060886090565b005b60005481565b60008081548092919060010191905055505600a165627a7a72305820d5b2c5380ae2f0103722d0da7d082e8f342e2a017de0fd63f11c48cfc4a0b0140029'; +const bin = '608060405234801561001057600080fd5b506101a1806100206000396000f300608060405260043610610057576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff1680630c55699c1461005c5780634826c2be14610087578063844cbc43146100de575b600080fd5b34801561006857600080fd5b506100716100f5565b6040518082815260200191505060405180910390f35b34801561009357600080fd5b5061009c6100fb565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b3480156100ea57600080fd5b506100f3610121565b005b60005481565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1681565b600080815480929190600101919050555041600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505600a165627a7a723058203e04df92be8ab872ae22ab17a37324afaea0956de6408cb798dcb2394353f1e70029'; const abi = [{ constant: true, inputs: [], name: 'x', outputs: [{ name: '', type: 'uint256' }], payable: false, stateMutability: 'view', type: 'function', +}, { + constant: true, inputs: [], name: 'coinBase', outputs: [{ name: '', type: 'address' }], payable: false, stateMutability: 'view', type: 'function', }, { constant: false, inputs: [], name: 'autoExec', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', }]; @@ -69,6 +71,13 @@ describe('\n\ntest auto exec\n\n', () => { expect(+ret).to.be.above(1); }); + it('get the coinbase after auto exec', async () => { + const contract = genContract(abi, addr); + const ret = await contract.methods.coinBase().call('pending'); + logger.debug('\nThe coinBase:\n', ret); + expect(ret).to.not.equal('0x0000000000000000000000000000000000000000'); + }); + it('should not exec tx', async () => { const res = await autoExec(); logger.debug('\nSend tx ok:\n', JSON.stringify(res)); From e1882fd71ecbbf45402ff3755daa05d8794d249f Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 15 May 2019 11:52:47 +0800 Subject: [PATCH 03/91] Add test of refunding token when suicide. --- .travis.yml | 14 ++++ scripts/contracts/tests/package.json | 1 + .../tests/test/integrate/lifetime.js | 81 +++++++++++++++++++ 3 files changed, 96 insertions(+) create mode 100644 scripts/contracts/tests/test/integrate/lifetime.js diff --git a/.travis.yml b/.travis.yml index f8495607f..9ffc20576 100644 --- a/.travis.yml +++ b/.travis.yml @@ -152,3 +152,17 @@ jobs: - ./bin/cita start test-chain/0 script: - npm run-script auto_exec + + - <<: *stage-contract-test-sha3-secp256k1 + name: Integrate Lifetime + install: + - cd $TRAVIS_BUILD_DIR/target/install + - ./bin/cita create + --nodes "127.0.0.1:4100" + --contract_arguments "SysConfig.economicalModel=1 PriceManager.quotaPrice=1" + --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" + --init_token 0x1000000 + - ./bin/cita setup test-chain/0 + - ./bin/cita start test-chain/0 + script: + - npm run-script lifetime diff --git a/scripts/contracts/tests/package.json b/scripts/contracts/tests/package.json index 226995a70..81100f454 100644 --- a/scripts/contracts/tests/package.json +++ b/scripts/contracts/tests/package.json @@ -27,6 +27,7 @@ "batch_tx": "eslint test/integrate/batch_tx.js && mocha test/integrate/batch_tx.js -t 20s --exit", "permission": "eslint test/integrate/permission.js && mocha test/integrate/permission.js -t 20s --exit", "auto_exec": "eslint test/integrate/auto_exec.js && mocha test/integrate/auto_exec.js -t 20s --exit", + "lifetime": "eslint test/integrate/lifetime.js && mocha test/integrate/lifetime.js -t 20s --exit", "lint": "eslint test", "lint-fix": "eslint --fix test" }, diff --git a/scripts/contracts/tests/test/integrate/lifetime.js b/scripts/contracts/tests/test/integrate/lifetime.js new file mode 100644 index 000000000..7ae0b58f2 --- /dev/null +++ b/scripts/contracts/tests/test/integrate/lifetime.js @@ -0,0 +1,81 @@ +const chai = require('chai'); +const util = require('../helpers/util'); +const config = require('../config'); + +const { expect } = chai; +const { + citaSDK, logger, genTxParams, genContract, getTxReceipt, +} = util; + +const { superAdmin } = config; + +// tmp +let addr; +let param; +let hash; +let balance; +const value = '0x100000'; + +// test data +const bin = '6080604052336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055506000600260006101000a81548160ff0219169083151502179055506103aa8061006e6000396000f300608060405260043610610083576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff168063054f7d9c1461008557806341c0e1b5146100b457806360fe47b1146100cb57806362a5af3b146100f85780636a28f0001461010f5780636d4ce63c146101265780638da5cb5b14610151575b005b34801561009157600080fd5b5061009a6101a8565b604051808215151515815260200191505060405180910390f35b3480156100c057600080fd5b506100c96101bb565b005b3480156100d757600080fd5b506100f660048036038101908080359060200190929190505050610280565b005b34801561010457600080fd5b5061010d610315565b005b34801561011b57600080fd5b50610124610332565b005b34801561013257600080fd5b5061013b61034f565b6040518082815260200191505060405180910390f35b34801561015d57600080fd5b50610166610359565b604051808273ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16815260200191505060405180910390f35b600260009054906101000a900460ff1681565b60001515600260009054906101000a900460ff161515141515610246576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f546869732066756e6374696f6e2069732066726f7a656e2e000000000000000081525060200191505060405180910390fd5b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b60001515600260009054906101000a900460ff16151514151561030b576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260188152602001807f546869732066756e6374696f6e2069732066726f7a656e2e000000000000000081525060200191505060405180910390fd5b8060018190555050565b6001600260006101000a81548160ff021916908315150217905550565b6000600260006101000a81548160ff021916908315150217905550565b6000600154905090565b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff16815600a165627a7a72305820c3bf27393a60762b7e0ea2853f01849fccbc0f1c065fad2f2db0db1a005e36ee0029'; +const abi = [{ + constant: true, inputs: [], name: 'frozen', outputs: [{ name: '', type: 'bool' }], payable: false, stateMutability: 'view', type: 'function', +}, { + constant: false, inputs: [], name: 'kill', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', +}, { + constant: false, inputs: [{ name: 'x', type: 'uint256' }], name: 'set', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', +}, { + constant: false, inputs: [], name: 'freeze', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', +}, { + constant: false, inputs: [], name: 'unfreeze', outputs: [], payable: false, stateMutability: 'nonpayable', type: 'function', +}, { + constant: true, inputs: [], name: 'get', outputs: [{ name: '', type: 'uint256' }], payable: false, stateMutability: 'view', type: 'function', +}, { + constant: true, inputs: [], name: 'owner', outputs: [{ name: '', type: 'address' }], payable: false, stateMutability: 'view', type: 'function', +}, { + inputs: [], payable: true, stateMutability: 'payable', type: 'constructor', +}, { payable: true, stateMutability: 'payable', type: 'fallback' }]; + +describe('\n\nDeploy a contract\n\n', () => { + it('should send a tx: deploy_contract', async () => { + param = await genTxParams(superAdmin); + const res = await citaSDK.base.deploy( + bin, + { ...param, value }, + ); + logger.debug('\nDeploy a contract:\n', res.contractAddress); + addr = res.contractAddress; + }); +}); + +describe('\n\ntest lifetime of contract\n\n', () => { + it('get the balance of superAdmin and contract', async () => { + balance = await citaSDK.base.getBalance(superAdmin.address, 'pending'); + const res = await citaSDK.base.getBalance(addr, 'pending'); + logger.debug('\nThe balance of admin: %s,\nand contract: %s\n', balance, res); + expect(+res).to.equal(+value); + }); + + it('should send a suicide tx', async () => { + const contract = genContract(abi, addr); + const res = await contract.methods.kill().send(param); + logger.debug('\nSend tx ok:\n', JSON.stringify(res)); + expect(res.status).to.equal('OK'); + ({ hash } = res); + }); + + it('should get receipt:', async () => { + const res = await getTxReceipt(hash); + logger.debug('\nget receipt:\n', res); + expect(res.errorMessage).to.be.null; + }); + + it('get the balance of superAdmin and contract', async () => { + const resAdmin = await citaSDK.base.getBalance(superAdmin.address, 'pending'); + const resCont = await citaSDK.base.getBalance(addr, 'pending'); + logger.debug('\nThe balance of admin: %s\nThe contract: %s', resAdmin, resCont); + expect(+resCont).to.equal(0); + // Not equal balance+value: cause the tx fee. + expect(+resAdmin).to.be.above(+balance); + }); +}); From bf464ce72c7089261efe48ea5a1a6343563f5677 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 15 May 2019 20:23:46 +0800 Subject: [PATCH 04/91] Bump Rust version to `v1.34.2`. [skip audit] --- .circleci/config.yml | 2 +- .travis.yml | 2 +- Cargo.lock | 62 ++++++++++++++++++++++---------------------- env.sh | 2 +- 4 files changed, 34 insertions(+), 34 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 9c6083d32..ddd2efb04 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -107,7 +107,7 @@ alias: - &job-default docker: - - image: cita/cita-build:ubuntu-18.04-20190429 + - image: cita/cita-build:ubuntu-18.04-20190515 working_directory: ~/cita-build resource_class: xlarge diff --git a/.travis.yml b/.travis.yml index 9ffc20576..e36c48dde 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ stages: - Release - IntegrateTest before_install: - - docker pull cita/cita-build:ubuntu-18.04-20190429 + - docker pull cita/cita-build:ubuntu-18.04-20190515 jobs: include: diff --git a/Cargo.lock b/Cargo.lock index 9db567f23..8e590324b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,7 +125,7 @@ dependencies = [ [[package]] name = "authority_manage" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -260,7 +260,7 @@ dependencies = [ [[package]] name = "blake2b" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -523,7 +523,7 @@ dependencies = [ [[package]] name = "cita-crypto" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -534,7 +534,7 @@ dependencies = [ [[package]] name = "cita-crypto-trait" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] @@ -542,7 +542,7 @@ dependencies = [ [[package]] name = "cita-directories" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -550,7 +550,7 @@ dependencies = [ [[package]] name = "cita-ed25519" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -645,7 +645,7 @@ dependencies = [ [[package]] name = "cita-merklehash" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -705,7 +705,7 @@ dependencies = [ [[package]] name = "cita-secp256k1" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -722,7 +722,7 @@ dependencies = [ [[package]] name = "cita-sm2" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -736,7 +736,7 @@ dependencies = [ [[package]] name = "cita-types" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1117,7 +1117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "db" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1187,7 +1187,7 @@ dependencies = [ [[package]] name = "engine" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1250,7 +1250,7 @@ dependencies = [ [[package]] name = "error" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" [[package]] name = "error-chain" @@ -1311,7 +1311,7 @@ dependencies = [ [[package]] name = "ethcore-bloom-journal" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1592,7 +1592,7 @@ dependencies = [ [[package]] name = "hashable" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "blake2b 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1794,7 +1794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-proto" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1811,7 +1811,7 @@ dependencies = [ [[package]] name = "jsonrpc-types" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1825,7 +1825,7 @@ dependencies = [ [[package]] name = "jsonrpc-types-internals" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1907,7 +1907,7 @@ dependencies = [ [[package]] name = "libproto" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-merklehash 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2063,7 +2063,7 @@ dependencies = [ [[package]] name = "logger" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2426,7 +2426,7 @@ dependencies = [ [[package]] name = "panic_hook" version = "0.0.1" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2553,7 +2553,7 @@ dependencies = [ [[package]] name = "proof" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2576,7 +2576,7 @@ dependencies = [ [[package]] name = "pubsub" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "pubsub_kafka 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2587,7 +2587,7 @@ dependencies = [ [[package]] name = "pubsub_kafka" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2599,7 +2599,7 @@ dependencies = [ [[package]] name = "pubsub_rabbitmq" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "amqp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2608,7 +2608,7 @@ dependencies = [ [[package]] name = "pubsub_zeromq" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2934,7 +2934,7 @@ dependencies = [ [[package]] name = "rlp" version = "0.2.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2946,7 +2946,7 @@ dependencies = [ [[package]] name = "rlp_derive" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3159,7 +3159,7 @@ dependencies = [ [[package]] name = "snappy" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3784,7 +3784,7 @@ dependencies = [ [[package]] name = "tx_pool" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -3926,7 +3926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "util" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#73402b55138919f85b50b066f2e5c1f8b32e6b3c" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", diff --git a/env.sh b/env.sh index de223f4e8..6e2335b49 100755 --- a/env.sh +++ b/env.sh @@ -13,7 +13,7 @@ fi if test -f "${SOURCE_DIR}/Cargo.toml"; then readonly CONTAINER_NAME='cita_build_container' - readonly DOCKER_IMAGE='cita/cita-build:ubuntu-18.04-20190429' + readonly DOCKER_IMAGE='cita/cita-build:ubuntu-18.04-20190515' else readonly CONTAINER_NAME='cita_run_container' readonly DOCKER_IMAGE='cita/cita-run:ubuntu-18.04-20190419' From 7fadd0340a6d64f0733f619a7bdeb11b526fff37 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Thu, 16 May 2019 16:02:11 +0800 Subject: [PATCH 05/91] Update release guide: Add submodule part. [skip ci] --- release_guide.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/release_guide.md b/release_guide.md index 609f4865e..4078301a6 100644 --- a/release_guide.md +++ b/release_guide.md @@ -83,7 +83,11 @@ Broadcast internal mail: Merge the bug fixes occurred during the test into the release branch `release-x.y.z`. -If the test passes, modify the update log and update the release date with other information. +If the test passes: + +* Create a `tag` of corresponding version +* Update `submodule` using `tag` +* Modify the update log and update the release date with other information ## Merge Branch @@ -117,7 +121,8 @@ git push origin vx.y.z ***The transition branch is named `merge-master-to-develop`*** -Merge the `master` branch into the `develop` branch. Because of the branch protection, we need to create a middle branch `merge-master-to-develop` via `pull request`. +Merge the `master` branch into the `develop` branch. +Because of the branch protection, we need to create a middle branch `merge-master-to-develop` via `pull request`. 1. Update the `master` branch code as follows: @@ -283,7 +288,11 @@ git push origin release-x.y.z 测试过程中出现的 Bug 修复合并入发布分支 `release-x.y.z`。 -当测试通过时,修改更新日志,更新版本发布日期等信息。 +测试通过后: + +* `submodule` 创建对应版本 `tag` +* 使用 `tag` 方式更新 `submodule` +* 修改更新日志,更新版本发布日期等信息 ## 合并分支 From fddf9a58a2f3087f418628fb9a59b5fc503a70b7 Mon Sep 17 00:00:00 2001 From: yubo Date: Thu, 16 May 2019 11:19:19 +0000 Subject: [PATCH 06/91] [skip audit]fix bug --- cita-network/src/node_manager.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/cita-network/src/node_manager.rs b/cita-network/src/node_manager.rs index 64c208b25..c31a5f4d7 100644 --- a/cita-network/src/node_manager.rs +++ b/cita-network/src/node_manager.rs @@ -577,12 +577,9 @@ impl AddConnectedNodeReq { node_status.session_id = Some(*repeated_id); node_status.score += SUCCESS_DIALING_SCORE; - let _ = service - .connected_addrs - .entry(self.session_id) - .and_modify(|v| { - v.trans_addr = Some(dialing_addr); - }); + let _ = service.connected_addrs.entry(*repeated_id).and_modify(|v| { + v.trans_addr = Some(dialing_addr); + }); } } } From 343a5fa470221704a0914e6e8aff906de8247551 Mon Sep 17 00:00:00 2001 From: yubo Date: Fri, 17 May 2019 11:46:34 +0800 Subject: [PATCH 07/91] [skip audit] use new bft commit --- cita-bft | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cita-bft b/cita-bft index 588c7cac9..7041bda10 160000 --- a/cita-bft +++ b/cita-bft @@ -1 +1 @@ -Subproject commit 588c7cac9b839466a6f32d185bf7435765bae498 +Subproject commit 7041bda10499e88e7646f5df707b8058c09c9c67 From dff14c04799978e5c2f2ff749b5c996f013027ff Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Fri, 17 May 2019 11:55:18 +0800 Subject: [PATCH 08/91] Skip audit temporarily. [skip travis] --- .circleci/config.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index ddd2efb04..be3e9771a 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -145,7 +145,9 @@ jobs: - restore_cache: *restore-security-audit-cache - run: name: Check Security Audit - command: make security_audit + command: | + echo "Add it back when bump protobuf to `v2.6.0`." + # make security_audit - save_cache: *save-security-audit-cache "Check Contracts": From 5d7dc87b2e2eb684bf99e470d3af5e81b109f99a Mon Sep 17 00:00:00 2001 From: yubo Date: Fri, 17 May 2019 10:41:44 +0000 Subject: [PATCH 09/91] [skip audit] fix for operation repeated peer key --- cita-network/src/node_manager.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/cita-network/src/node_manager.rs b/cita-network/src/node_manager.rs index c31a5f4d7..b41c6d5a1 100644 --- a/cita-network/src/node_manager.rs +++ b/cita-network/src/node_manager.rs @@ -617,11 +617,6 @@ impl AddConnectedNodeReq { .connected_addrs .insert(self.session_id, TransformAddr::new(session_info.addr, None)); - // Add connected peer keys - let _ = service - .connected_peer_keys - .insert(self.init_msg.peer_key, self.session_id); - // If it is an active connection, need to set this node in known_addrs has been connected. if self.ty == SessionType::Outbound { if let Some(ref mut node_status) = @@ -633,6 +628,12 @@ impl AddConnectedNodeReq { } } + // Add connected peer keys + // Because AddRepeatedNodeReq maybe already did above action + let _ = service + .connected_peer_keys + .insert(self.init_msg.peer_key, self.session_id); + info!( "[NodeManager] connected_addrs info: {:?}", service.connected_addrs @@ -751,8 +752,23 @@ impl AddRepeatedNodeReq { if let Some(ref mut node_status) = service.known_addrs.get_mut(&self.addr) { node_status.session_id = Some(self.session_id); node_status.score += SUCCESS_DIALING_SCORE; - } + if let Some(session_info) = service.pending_connected_addrs.remove(&self.session_id) { + let _ = service.connected_addrs.insert( + self.session_id, + TransformAddr::new(session_info.addr, Some(self.addr)), + ); + } else { + let _ = service + .connected_addrs + .entry(self.session_id) + .and_modify(|v| { + v.trans_addr = Some(self.addr); + }); + } + } else { + warn!("[NodeManager] Cant find repeated sessionid in known addrs"); + } // This dialing is finished. service.dialing_node = None; } From 09b1b25bb6cb1328b09d7486ed8083d566a0ba79 Mon Sep 17 00:00:00 2001 From: yubo Date: Fri, 17 May 2019 18:56:10 +0800 Subject: [PATCH 10/91] Update node_manager.rs --- cita-network/src/node_manager.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cita-network/src/node_manager.rs b/cita-network/src/node_manager.rs index b41c6d5a1..a464b7bb9 100644 --- a/cita-network/src/node_manager.rs +++ b/cita-network/src/node_manager.rs @@ -767,7 +767,7 @@ impl AddRepeatedNodeReq { }); } } else { - warn!("[NodeManager] Cant find repeated sessionid in known addrs"); + warn!("[NodeManager] Cant find repeated sock addr in known addrs"); } // This dialing is finished. service.dialing_node = None; From defd05f8c3437dfcf9580bf016b6b9a4c0e6aa15 Mon Sep 17 00:00:00 2001 From: leeyr Date: Sat, 18 May 2019 12:23:51 +0800 Subject: [PATCH 11/91] Fix: Should not unwrap on handle_remote_msg.[skip travis] --- cita-auth/src/handler.rs | 172 +++++++++++++++++++++++---------------- 1 file changed, 104 insertions(+), 68 deletions(-) diff --git a/cita-auth/src/handler.rs b/cita-auth/src/handler.rs index 86b0f9e38..162605594 100644 --- a/cita-auth/src/handler.rs +++ b/cita-auth/src/handler.rs @@ -393,100 +393,136 @@ impl MsgHandler { self.history_heights.update_time_stamp(); } - pub fn handle_remote_msg(&mut self) { - loop { - // send request to get chain id if we have not got it - // chain id need version - // so get chain id after get version - if self.chain_id.is_none() && self.config_info.version.is_some() { - trace!("chain id is not ready"); - let msg: Message = MiscellaneousReq::new().into(); - self.tx_pub - .send(( - routing_key!(Auth >> MiscellaneousReq).into(), - msg.try_into().unwrap(), - )) - .unwrap(); - } + fn daily_task(&mut self) { + if self.is_need_proposal_new_block && self.is_ready() { + self.dispatcher.proposal_tx_list( + (self.history_heights.next_height() - 1) as usize, // todo fix bft + &self.tx_pub, + &self.config_info, + ); + // after proposal new block clear flag + self.is_need_proposal_new_block = false; + } + } - // block hashes of some height we not have - // we will send request for these height - if !self.history_heights.is_init() { - trace!("history block hashes is not ready"); - self.send_block_tx_hashes_req(true); + fn get_chain_id(&mut self) { + if self.chain_id.is_none() && self.config_info.version.is_some() { + trace!("chain id is not ready"); + let msg: Message = MiscellaneousReq::new().into(); + if let Ok(rabbit_mq_msg) = msg.try_into() { + if let Err(e) = self + .tx_pub + .send((routing_key!(Auth >> MiscellaneousReq).into(), rabbit_mq_msg)) + { + error!("Send MiscellaneousReq message error {:?}", e); + } + } else { + error!("Can not get rabbit mq message from MiscellaneousReq."); } + } + } - // Daily tasks - { - if self.is_need_proposal_new_block && self.is_ready() { - self.dispatcher.proposal_tx_list( - (self.history_heights.next_height() - 1) as usize, // todo fix bft - &self.tx_pub, - &self.config_info, - ); - // after proposal new block clear flag - self.is_need_proposal_new_block = false; - } + fn process_msg(&mut self) { + if let Ok((key, payload)) = self.rx_sub.recv_timeout(Duration::new(3, 0)) { + if Message::try_from(&payload).is_err() { + error!("Can not get message from payload {:?}", &payload); + return; } - // process message from MQ - if let Ok((key, payload)) = self.rx_sub.recv_timeout(Duration::new(3, 0)) { - let mut msg = Message::try_from(&payload).unwrap(); - let rounting_key = RoutingKey::from(&key); - trace!("process message key = {}", key); - match rounting_key { - // we got this message when chain reach new height or response the BlockTxHashesReq - routing_key!(Chain >> BlockTxHashes) => { - let block_tx_hashes = msg.take_block_tx_hashes().unwrap(); + let mut msg = Message::try_from(&payload).unwrap(); + let rounting_key = RoutingKey::from(&key); + trace!("process message key = {}", key); + match rounting_key { + // we got this message when chain reach new height or response the BlockTxHashesReq + routing_key!(Chain >> BlockTxHashes) => { + if let Some(block_tx_hashes) = msg.take_block_tx_hashes() { self.deal_block_tx_hashes(&block_tx_hashes) + } else { + error!("Can not get block tx hashes from message {:?}.", msg); } - routing_key!(Executor >> BlackList) => { - let black_list = msg.take_black_list().unwrap(); + } + routing_key!(Executor >> BlackList) => { + if let Some(black_list) = msg.take_black_list() { self.deal_black_list(&black_list); + } else { + error!("Can not get black list from message {:?}.", msg); } - routing_key!(Net >> Request) | routing_key!(Jsonrpc >> RequestNewTxBatch) => { + } + routing_key!(Net >> Request) | routing_key!(Jsonrpc >> RequestNewTxBatch) => { + if let Some(newtx_req) = msg.take_request() { let is_local = rounting_key.is_sub_module(SubModules::Jsonrpc); - let newtx_req = msg.take_request().unwrap(); self.deal_request(is_local, newtx_req); + } else { + error!("Can not get request from message {:?}.", msg); } - routing_key!(Executor >> Miscellaneous) => { - let miscellaneous = msg.take_miscellaneous().unwrap(); + } + routing_key!(Executor >> Miscellaneous) => { + if let Some(miscellaneous) = msg.take_miscellaneous() { self.deal_miscellaneous(&miscellaneous); + } else { + error!("Can not get miscellaneous from message {:?}.", msg); } - routing_key!(Snapshot >> SnapshotReq) => { - let snapshot_req = msg.take_snapshot_req().unwrap(); + } + routing_key!(Snapshot >> SnapshotReq) => { + if let Some(snapshot_req) = msg.take_snapshot_req() { self.deal_snapshot(&snapshot_req); + } else { + error!("Can not get snapshot from message {:?}.", msg); } - routing_key!(Net >> GetBlockTxn) => { - let mut get_block_txn = msg.take_get_block_txn().unwrap(); + } + routing_key!(Net >> GetBlockTxn) => { + if let Some(mut get_block_txn) = msg.take_get_block_txn() { let origin = msg.get_origin(); self.deal_get_block_txn(&mut get_block_txn, origin); + } else { + error!("Can not get block txn from message {:?}.", msg); } - // Compact proposal - routing_key!(Consensus >> VerifyBlockReq) => { - if !self.is_ready() { - info!("Net/Consensus >> CompactProposal: auth is not ready"); - } else { - self.deal_signed_proposal(msg); - } + } + // Compact proposal + routing_key!(Consensus >> VerifyBlockReq) => { + if !self.is_ready() { + info!("Net/Consensus >> CompactProposal: auth is not ready"); + } else { + self.deal_signed_proposal(msg); } - routing_key!(Net >> BlockTxn) => { - if !self.is_ready() || self.verify_block_req.is_none() { - info!("Net >> BlockTxn: auth is not ready"); - } else { - let verify_block_req = self.verify_block_req.clone(); - if let Some(verify_block_req) = verify_block_req { - self.deal_block_txn(msg, verify_block_req); - } + } + routing_key!(Net >> BlockTxn) => { + if !self.is_ready() || self.verify_block_req.is_none() { + info!("Net >> BlockTxn: auth is not ready"); + } else { + let verify_block_req = self.verify_block_req.clone(); + if let Some(verify_block_req) = verify_block_req { + self.deal_block_txn(msg, verify_block_req); } } - _ => { - error!("receive unexpected message key {}", key); - } + } + _ => { + error!("receive unexpected message key {}", key); } } } } + pub fn handle_remote_msg(&mut self) { + loop { + // send request to get chain id if we have not got it + // chain id need version + // so get chain id after get version + self.get_chain_id(); + + // block hashes of some height we not have + // we will send request for these height + if !self.history_heights.is_init() { + trace!("history block hashes is not ready"); + self.send_block_tx_hashes_req(true); + } + + // Daily tasks + self.daily_task(); + + // process message from MQ + self.process_msg(); + } + } fn deal_block_tx_hashes(&mut self, block_tx_hashes: &BlockTxHashes) { let height = block_tx_hashes.get_height(); From 06a313eb3ce5f5d55479a563caddb0d9183f3bb9 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 13 May 2019 11:33:05 +0800 Subject: [PATCH 12/91] Check the shell and fix. --- env.sh | 4 +- scripts/amend_system_contracts.sh | 16 ++-- scripts/cita | 146 ++++++++++++++--------------- scripts/cita_config.sh | 8 +- scripts/release.sh | 8 +- scripts/replace_default_feature.sh | 6 +- 6 files changed, 92 insertions(+), 96 deletions(-) diff --git a/env.sh b/env.sh index 6e2335b49..eb278ad66 100755 --- a/env.sh +++ b/env.sh @@ -38,7 +38,7 @@ fi # Expose parameter for docker needs something like "-p 1337:1337 -p 1338:1338", but not "-p 1337:1337 1338:1338" EXPOSE_PARAM=() for port in "${EXPOSE[@]}"; do - EXPOSE_PARAM+=" -p ${port}" + EXPOSE_PARAM+=(-p ${port}) done # Docker Arguments @@ -65,7 +65,7 @@ if ! docker ps | grep "${CONTAINER_NAME}" > '/dev/null' 2>&1; then --env "USER_ID=${USER_ID}" \ --workdir "${WORKDIR}" \ --name "${CONTAINER_NAME}" \ - ${EXPOSE_PARAM[@]} "${DOCKER_IMAGE}" \ + "${EXPOSE_PARAM[@]}" "${DOCKER_IMAGE}" \ /bin/bash -c "${INIT_CMD}" # Wait entrypoint.sh to finish sleep 3 diff --git a/scripts/amend_system_contracts.sh b/scripts/amend_system_contracts.sh index 7c26bec7a..89a0402d3 100755 --- a/scripts/amend_system_contracts.sh +++ b/scripts/amend_system_contracts.sh @@ -1,11 +1,11 @@ #!/bin/bash set -e -if [[ `uname` == 'Darwin' ]] +if [[ $(uname) == 'Darwin' ]] then - SOURCE_DIR=$(realpath $(dirname $0)/..) + SOURCE_DIR=$(realpath "$(dirname "$0")"/..) else - SOURCE_DIR=$(readlink -f $(dirname $0)/..) + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/..) fi if [ "$1" = "help" ]; then @@ -20,8 +20,8 @@ if [ "$1" = "help" ]; then fi # Clean tmp files -rm -rf ${SOURCE_DIR}/tmp -rm -f ${SOURCE_DIR}/scripts/genesis.json +rm -rf "${SOURCE_DIR}"/tmp +rm -f "${SOURCE_DIR}"/scripts/genesis.json # Just get the genensis.json scripts/create_cita_config.py create \ @@ -30,10 +30,10 @@ scripts/create_cita_config.py create \ --nodes "127.0.0.1:4000" \ && cp tmp/0/genesis.json scripts/ \ && cd ./scripts/txtool/txtool \ -&& python3 ${SOURCE_DIR}/scripts/amend_system_contracts.py \ +&& python3 "${SOURCE_DIR}"/scripts/amend_system_contracts.py \ --privkey "$1" \ --chain_id "$2" \ --version "$3" \ --url "$4" \ -&& rm -rf ${SOURCE_DIR}/tmp \ -&& rm -f ${SOURCE_DIR}/scripts/genesis.json +&& rm -rf "${SOURCE_DIR}"/tmp \ +&& rm -f "${SOURCE_DIR}"/scripts/genesis.json diff --git a/scripts/cita b/scripts/cita index 4fd2d3add..feb72cb52 100755 --- a/scripts/cita +++ b/scripts/cita @@ -3,17 +3,16 @@ # ex: ts=4 sw=4 et # Commands Paths -if [ `uname` == 'Darwin' ]; then - CITA_BIN="$(dirname $(realpath $0))" +if [[ $(uname) == 'Darwin' ]]; then + CITA_BIN=$(dirname "$(realpath "$0")") else - CITA_BIN="$(dirname $(readlink -f $0))" + CITA_BIN=$(dirname "$(readlink -f "$0")") fi -CITA_SCRIPTS="$(dirname $CITA_BIN)/scripts" +CITA_SCRIPTS=$(dirname "$CITA_BIN")/scripts if [ "$1" != "bebop" ]; then - stat $CITA_BIN/cita-env > /dev/null 2>&1 - if [ $? -eq 0 ]; then - $CITA_BIN/cita-env bin/cita bebop $@ + if stat "$CITA_BIN"/cita-env > /dev/null 2>&1; then + "$CITA_BIN"/cita-env bin/cita bebop "$@" else echo -e "\033[0;31mPlease run this command after build 🎨" echo -e "\033[0;32mRun \`cita bebop\` to preview help! 🎸 \033[0m\n" @@ -30,21 +29,21 @@ set -e # Add cita scripts into system executable paths export PATH=$CITA_BIN:$PATH SERVICES=( forever auth bft chain executor jsonrpc network ) -SCRIPT=`basename $0` +SCRIPT=$(basename "$0") COMMAND=$1 NODE_NAME=$2 -NODE_PATH="$(dirname $CITA_BIN)/${NODE_NAME}" +NODE_PATH="$(dirname "$CITA_BIN")/${NODE_NAME}" NODE_LOGS_DIR="${NODE_PATH}/logs" NODE_DATA_DIR="${NODE_PATH}/data" -TNODE=`echo ${NODE_NAME} | sed 's/\//%2f/g'` +TNODE=$(echo "${NODE_NAME}" | sed 's/\//%2f/g') sudo(){ set -o noglob if [ "$(whoami)" == "root" ] ; then - $* + "$@" else - /usr/bin/sudo $* + /usr/bin/sudo "$@" fi set +o noglob } @@ -129,27 +128,27 @@ EOF # BUILDING COMMANDS create() { - $CITA_SCRIPTS/create_cita_config.py $@ + "$CITA_SCRIPTS"/create_cita_config.py "$@" } append() { - $CITA_SCRIPTS/create_cita_config.py $@ + "$CITA_SCRIPTS"/create_cita_config.py "$@" } # SERVICE CONTROL COMMANDS start_rabbitmq() { # Config and start RabbitMQ - if [[ `uname` == 'Darwin' ]] + if [[ $(uname) == 'Darwin' ]] then - ps -ax | grep rabbitmq-server | grep -v grep > /dev/null || brew services restart rabbitmq > /dev/null + pgrep -f rabbitmq-server > /dev/null || brew services restart rabbitmq > /dev/null RABBITMQ_USER=cita_monitor RABBITMQ_PASSWD=cita_monitor - sudo rabbitmqctl list_vhosts | grep ${NODE_NAME} > /dev/null || sudo rabbitmqctl add_vhost ${NODE_NAME} > /dev/null - sudo rabbitmqctl set_permissions -p ${NODE_NAME} guest '.*' '.*' '.*' > /dev/null + sudo rabbitmqctl list_vhosts | grep "${NODE_NAME}" > /dev/null || sudo rabbitmqctl add_vhost "${NODE_NAME}" > /dev/null + sudo rabbitmqctl set_permissions -p "${NODE_NAME}" guest '.*' '.*' '.*' > /dev/null sudo rabbitmq-plugins enable rabbitmq_management > /dev/null sudo rabbitmqctl list_users | grep ${RABBITMQ_USER} > /dev/null || sudo rabbitmqctl add_user ${RABBITMQ_USER} ${RABBITMQ_PASSWD} > /dev/null sudo rabbitmqctl set_user_tags ${RABBITMQ_USER} monitoring > /dev/null - sudo rabbitmqctl set_permissions -p ${NODE_NAME} ${RABBITMQ_USER} '.*' '.*' '.*' > /dev/null + sudo rabbitmqctl set_permissions -p "${NODE_NAME}" ${RABBITMQ_USER} '.*' '.*' '.*' > /dev/null else flock -x -w 30 /tmp/rabbitmq.lock -c "ps -C rabbitmq-server > /dev/null || sudo /etc/init.d/rabbitmq-server restart > /dev/null" RABBITMQ_USER=cita_monitor @@ -167,12 +166,11 @@ do_setup() { for i in {1..3} do start_rabbitmq - curl http://localhost:15672/ > /dev/null 2>&1 - if [ $? -eq 0 ]; then + if curl http://localhost:15672/ > /dev/null 2>&1; then return 0 fi done - echo "Failed to start RabbitMQ" + echo "Failed to start RabbitMQ after $i times." exit 1 } @@ -182,7 +180,7 @@ do_start() { mock=$2 # Make sure log directory exists - mkdir -p ${NODE_LOGS_DIR} + mkdir -p "${NODE_LOGS_DIR}" # Tricky if [[ -z ${mock} ]]; then @@ -192,18 +190,18 @@ do_start() { fi # Start cita-forever - if [ -z ${debug} ]; then - cita-forever -c ${config} start 2>&1 + if [ -z "${debug}" ]; then + cita-forever -c "${config}" start 2>&1 else RUST_LOG=cita_auth=${debug},cita_chain=${debug},cita_executor=${debug},cita_jsonrpc=${debug},cita_network=${debug},cita_bft=${debug},\ core_executor=${debug},engine=${debug},jsonrpc_types=${debug},libproto=${debug},proof=${debug},txpool=${debug},core=${debug} \ - cita-forever -c ${config} start 2>&1 + cita-forever -c "${config}" start 2>&1 fi # Wait for the node to come up WAIT=3 while [ $WAIT -gt 0 ]; do - WAIT=`expr $WAIT - 1` + WAIT="$(( WAIT - 1 ))" sleep 1 do_ping if [ "${PING_STATUS}" == "pong" ]; then @@ -234,19 +232,17 @@ do_stop() { # DIAGNOSTIC COMMANDS PING_STATUS="" do_ping() { - for service in forever; do - pidfile="${NODE_PATH}/.cita-${service}.pid" - if [ ! -e $pidfile ]; then - PING_STATUS="pang" - return - fi + pidfile="${NODE_PATH}/.cita-forever.pid" + if [[ ! -e "$pidfile" ]]; then + PING_STATUS="pang" + return + fi - alive=`ps -p $(cat ${pidfile}) | wc -l` - if [ "${alive}" -le "1" ]; then - PING_STATUS="pang" - return - fi - done + alive=$(ps -p "$(cat "${pidfile}")" | wc -l) + if [ "${alive}" -le "1" ]; then + PING_STATUS="pang" + return + fi PING_STATUS="pong" } @@ -254,17 +250,17 @@ do_ping() { do_top() { for service in "${SERVICES[@]}"; do pidfile="${NODE_PATH}/.cita-${service}.pid" - if [ -e $pidfile ]; then - ps -p `cat ${pidfile}` -f | tail -n +2 + if [ -e "$pidfile" ]; then + ps -p "$(cat "${pidfile}")" -f | tail -n +2 fi done } do_status() { - for pid_file in `find . -name "*.pid"`; do - pid=$(cat ${pid_file}) - ps -A -o command=50,pid,time|grep ${pid} |grep -v "grep" || true - done + while IFS= read -r -d '' pid_file; do + pid=$(cat "${pid_file}") + pgrep -f "${pid}" || true + done < <(find . -name "*.pid") } @@ -277,15 +273,15 @@ do_clean() { fi # Move data/ and logs/ into backup directory - backup_dir="$(pwd)/backup.$(date -Iseconds)" - mkdir -p ${backup_dir} - if [ -e ${NODE_DATA_DIR} ] ; then - echo "mv ${NODE_DATA_DIR} ${backup_dir}/" - mv ${NODE_DATA_DIR} ${backup_dir}/ + backup_dir=$(pwd)/backup.$(date -Iseconds) + mkdir -p "${backup_dir}" + if [ -e "${NODE_DATA_DIR}" ] ; then + echo "mv ${NODE_DATA_DIR} ${backup_dir}" + mv "${NODE_DATA_DIR}" "${backup_dir}" fi - if [ -e ${NODE_LOGS_DIR} ] ; then - echo "mv ${NODE_LOGS_DIR} ${backup_dir}/" - mv ${NODE_LOGS_DIR} ${backup_dir}/ + if [ -e "${NODE_LOGS_DIR}" ] ; then + echo "mv ${NODE_LOGS_DIR} ${backup_dir}" + mv "${NODE_LOGS_DIR}" "${backup_dir}" fi } @@ -298,20 +294,20 @@ do_backup() { # Copy data/ and logs/ into backup directory backup_dir="$(pwd)/backup.$(date -Iseconds)" - mkdir -p ${backup_dir} - if [ -e ${NODE_DATA_DIR} ] ; then + mkdir -p "${backup_dir}" + if [ -e "${NODE_DATA_DIR}" ] ; then echo "cp -r ${NODE_DATA_DIR} ${backup_dir}/" - cp -r ${NODE_DATA_DIR} ${backup_dir}/ + cp -r "${NODE_DATA_DIR}" "${backup_dir}"/ fi - if [ -e ${NODE_LOGS_DIR} ] ; then + if [ -e "${NODE_LOGS_DIR}" ] ; then echo "cp -r ${NODE_LOGS_DIR} ${backup_dir}/" - cp -r ${NODE_LOGS_DIR} ${backup_dir}/ + cp -r "${NODE_LOGS_DIR}" "${backup_dir}"/ fi } do_logs() { service0=$1 - if [ -z ${service0} ]; then + if [ -z "${service0}" ]; then echo "'${SCRIPT} logs' requires exactly 2 arguments." echo echo "Usage: ${SCRIPT} logs NODE_NAME SERVICE" @@ -320,7 +316,7 @@ do_logs() { fi for service in "${SERVICES[@]}"; do - if [[ $service = $service0 || "cita-${service}" = $service0 ]]; then + if [[ $service = "$service0" || cita-"${service}" = "$service0" ]]; then tail -f "${NODE_LOGS_DIR}/cita-${service}.log" exit 0 fi @@ -331,7 +327,7 @@ do_logs() { } do_logrotate() { - logs=$(ls -1 ${NODE_LOGS_DIR}/cita-*.log) + logs=$(ls -1 "${NODE_LOGS_DIR}"/cita-*.log) cita-forever logrotate > /dev/null 2>&1 # Wait for services to rotate their logs @@ -346,14 +342,14 @@ do_logrotate() { clear_rabbit_mq() { MQ_COMMAND="curl -i -u guest:guest -H content-type:application/json -XDELETE http://localhost:15672/api/queues/${TNODE}" - $MQ_COMMAND/auth > /dev/null 2>&1 || true - $MQ_COMMAND/chain > /dev/null 2>&1 || true - $MQ_COMMAND/consensus > /dev/null 2>&1 || true - $MQ_COMMAND/jsonrpc > /dev/null 2>&1 || true - $MQ_COMMAND/network > /dev/null 2>&1 || true - $MQ_COMMAND/network_tx > /dev/null 2>&1 || true - $MQ_COMMAND/network_consensus > /dev/null 2>&1 || true - $MQ_COMMAND/executor > /dev/null 2>&1 || true + "$MQ_COMMAND"/auth > /dev/null 2>&1 || true + "$MQ_COMMAND"/chain > /dev/null 2>&1 || true + "$MQ_COMMAND"/consensus > /dev/null 2>&1 || true + "$MQ_COMMAND"/jsonrpc > /dev/null 2>&1 || true + "$MQ_COMMAND"/network > /dev/null 2>&1 || true + "$MQ_COMMAND"/network_tx > /dev/null 2>&1 || true + "$MQ_COMMAND"/network_consensus > /dev/null 2>&1 || true + "$MQ_COMMAND"/executor > /dev/null 2>&1 || true } node_down_check() { @@ -385,12 +381,12 @@ case "${COMMAND}" in ;; create) - create $@ + create "$@" exit 0 ;; append) - append $@ + append "$@" exit 0 ;; @@ -412,7 +408,7 @@ fi # Enter the node directory pushd . > /dev/null -cd ${NODE_PATH} +cd "${NODE_PATH}" case "${COMMAND}" in setup) @@ -426,7 +422,7 @@ case "${COMMAND}" in # Make sure the RabbitMQ fresh clear_rabbit_mq - do_start $3 $4 + do_start "$3" "$4" ;; stop) @@ -441,7 +437,7 @@ case "${COMMAND}" in # Make sure the RabbitMQ fresh clear_rabbit_mq - do_start $3 $4 + do_start "$3" "$4" ;; ping) @@ -473,7 +469,7 @@ case "${COMMAND}" in ;; logs) - do_logs $3 + do_logs "$3" ;; backup) diff --git a/scripts/cita_config.sh b/scripts/cita_config.sh index 4a5d130c5..a02e9d1c9 100755 --- a/scripts/cita_config.sh +++ b/scripts/cita_config.sh @@ -1,12 +1,12 @@ #!/bin/bash # Enviroments -CITA_BIN=$(realpath $(dirnamme $0)) -CITA_SCRIPTS=$(dirname $CITA_BIN)/scripts +CITA_BIN=$(realpath "$(dirnamme "$0")") +CITA_SCRIPTS=$(dirname "$CITA_BIN")/scripts # Wrap the create script. -if [ -e $CITA_SCRIPTS/create_cita_config.py ]; then - $CITA_SCRIPTS/create_cita_config.py $@ +if [ -e "$CITA_SCRIPTS"/create_cita_config.py ]; then + "$CITA_SCRIPTS"/create_cita_config.py "$@" else echo -e "\033[0;31mPlease run this command after build 🎨" fi diff --git a/scripts/release.sh b/scripts/release.sh index a91f0b087..e4d0d967f 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -1,13 +1,13 @@ #!/bin/bash -if [[ `uname` == 'Darwin' ]] +if [[ $(uname) == 'Darwin' ]] then - SOURCE_DIR=$(realpath $(dirname $(realpath $0))/..) + SOURCE_DIR=$(realpath "$(dirname "$(realpath "$0")")"/..) else - SOURCE_DIR=$(readlink -f $(dirname $(realpath $0))/..) + SOURCE_DIR=$(readlink -f "$(dirname "$(realpath "$0")")"/..) fi -cd ${SOURCE_DIR} +cd "${SOURCE_DIR}" || exit if [ $# -ne 1 ] ; then echo "usage: $0 debug|release" diff --git a/scripts/replace_default_feature.sh b/scripts/replace_default_feature.sh index c3fd0fff5..00b9dc7c4 100755 --- a/scripts/replace_default_feature.sh +++ b/scripts/replace_default_feature.sh @@ -11,9 +11,9 @@ function replace_default_feature () { fi local before_feature='[ \t]*default[ \t]*=[ \t]*\[.*\"' local after_feature='\".*' - find "${workspacedir}" -mindepth 2 -name "Cargo.toml" \ - | xargs grep -l "^${before_feature}${old_feature}${after_feature}" \ - | while read cargotoml; do + find "${workspacedir}" -mindepth 2 -name "Cargo.toml" -print0 \ + | xargs -0 grep -l "^${before_feature}${old_feature}${after_feature}" \ + | while read -r cargotoml; do if [ -f "${cargotoml}" ]; then echo "[Info ] Replace [${old_feature}] by [${new_feature}] for [${cargotoml}] ..." sed -i "s/\(${before_feature}\)${old_feature}\(${after_feature}\)\$/\1${new_feature}\2/" "${cargotoml}" From 11804b34e2379772abd0988dc9ec3d52482f7f66 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 13 May 2019 21:16:44 +0800 Subject: [PATCH 13/91] Rename `cita` to `cita.sh`. --- scripts/{cita => cita.sh} | 0 scripts/release.sh | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename scripts/{cita => cita.sh} (100%) diff --git a/scripts/cita b/scripts/cita.sh similarity index 100% rename from scripts/cita rename to scripts/cita.sh diff --git a/scripts/release.sh b/scripts/release.sh index e4d0d967f..713831751 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -42,7 +42,7 @@ done #strip target/install/bin/* # 2) cita -cp -rf scripts/cita target/install/bin/ +cp -rf scripts/cita.sh target/install/bin/cita # 3) contract cp -rf scripts/contracts target/install/scripts/ From d3547efa4e1d9cd2e41189b856f6b37ddc123a1f Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Sat, 18 May 2019 14:55:17 +0800 Subject: [PATCH 14/91] Add shellcheck into travis CI. --- .travis.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.travis.yml b/.travis.yml index e36c48dde..51c1112da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ services: git: depth: 1 stages: + - CheckShell - Release - IntegrateTest before_install: @@ -18,6 +19,11 @@ before_install: jobs: include: + - stage: CheckShell + script: + # Fail if any of these files have warnings + - shellcheck scripts/*.sh env.sh + - stage: Release name: Release for Integrate Test language: node_js From db1de77a18dbca828b1dcfb06b8207af0dfe62b6 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Tue, 21 May 2019 21:14:17 +0800 Subject: [PATCH 15/91] Add the timeout of snapshot test. [skip travis] --- tests/integrate_test/cita_snapshot_test.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/integrate_test/cita_snapshot_test.sh b/tests/integrate_test/cita_snapshot_test.sh index dadf013cd..9b91bf66c 100755 --- a/tests/integrate_test/cita_snapshot_test.sh +++ b/tests/integrate_test/cita_snapshot_test.sh @@ -52,7 +52,7 @@ sleep 10 echo "4) Check all nodes grow up ..." for id in {0..2}; do echo "chech_height_growth_normal $id ..." - timeout=`check_height_growth_normal $id 15`||(echo "FAILED" + timeout=`check_height_growth_normal $id 30`||(echo "FAILED" echo "error msg: ${timeout}" exit 1) done From 4953e58718b59bb219047e655735cdc88faf9e12 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" Date: Sat, 25 May 2019 13:14:50 +0000 Subject: [PATCH 16/91] Bump tar from 2.2.1 to 2.2.2 in /scripts/contracts/tests Bumps [tar](https://github.com/npm/node-tar) from 2.2.1 to 2.2.2. - [Release notes](https://github.com/npm/node-tar/releases) - [Commits](https://github.com/npm/node-tar/compare/v2.2.1...v2.2.2) --- scripts/contracts/tests/yarn.lock | 30 +++++++++++++++++++++--------- 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/scripts/contracts/tests/yarn.lock b/scripts/contracts/tests/yarn.lock index c3ece95e4..3d3670655 100644 --- a/scripts/contracts/tests/yarn.lock +++ b/scripts/contracts/tests/yarn.lock @@ -1357,10 +1357,10 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= -fstream@^1.0.2, fstream@^1.0.8: - version "1.0.11" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" - integrity sha1-XB+x8RdHcRTwYyoOtLcbPLD9MXE= +fstream@^1.0.12, fstream@^1.0.8: + version "1.0.12" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045" + integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg== dependencies: graceful-fs "^4.1.2" inherits "~2.0.0" @@ -1419,7 +1419,7 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -glob@7.1.3, glob@^7.1.2, glob@^7.1.3: +glob@7.1.3, glob@^7.1.2: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" integrity sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ== @@ -1431,6 +1431,18 @@ glob@7.1.3, glob@^7.1.2, glob@^7.1.3: once "^1.3.0" path-is-absolute "^1.0.0" +glob@^7.1.3: + version "7.1.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255" + integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + global@~4.3.0: version "4.3.2" resolved "https://registry.yarnpkg.com/global/-/global-4.3.2.tgz#e76989268a6c74c38908b1305b10fc0e394e9d0f" @@ -3175,12 +3187,12 @@ tar.gz@^1.0.5: tar "^2.1.1" tar@^2.1.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - integrity sha1-jk0qJWwOIYXGsYrWlK7JaLg8sdE= + version "2.2.2" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40" + integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA== dependencies: block-stream "*" - fstream "^1.0.2" + fstream "^1.0.12" inherits "2" text-table@^0.2.0: From f180a7d201e96845b35cfeb07f99fdd3b6249619 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Tue, 28 May 2019 15:29:53 +0800 Subject: [PATCH 17/91] Use cita-logger crate. [skip travis] --- Cargo.lock | 134 +++++++++--------- cita-auth/Cargo.toml | 2 +- cita-auth/src/main.rs | 4 +- cita-bft | 2 +- cita-chain/Cargo.toml | 2 +- cita-chain/core/Cargo.toml | 4 +- cita-chain/core/src/lib.rs | 4 +- cita-chain/src/main.rs | 4 +- cita-chain/types/Cargo.toml | 2 +- cita-chain/types/src/lib.rs | 4 +- cita-executor/Cargo.toml | 2 +- cita-executor/core/Cargo.toml | 2 +- .../core/src/contracts/solc/node_manager.rs | 4 +- .../contracts/solc/permission_management.rs | 4 +- .../core/src/contracts/solc/quota_manager.rs | 4 +- .../core/src/contracts/solc/sys_config.rs | 4 +- .../src/contracts/solc/user_management.rs | 4 +- cita-executor/core/src/executive.rs | 2 +- cita-executor/core/src/lib.rs | 4 +- .../core/src/libexecutor/executor.rs | 4 +- cita-executor/core/src/state/mod.rs | 2 +- cita-executor/evm/Cargo.toml | 2 +- cita-executor/evm/src/lib.rs | 4 +- cita-executor/src/main.rs | 4 +- cita-forever | 2 +- cita-jsonrpc/Cargo.toml | 2 +- cita-jsonrpc/src/main.rs | 4 +- cita-network/Cargo.toml | 2 +- cita-network/src/config.rs | 1 - cita-network/src/main.rs | 4 +- cita-network/src/mq_agent.rs | 1 - cita-network/src/network.rs | 1 - cita-network/src/node_manager.rs | 1 - cita-network/src/p2p_protocol/mod.rs | 1 - .../src/p2p_protocol/node_discovery.rs | 1 - cita-network/src/p2p_protocol/transfer.rs | 1 - cita-network/src/synchronizer.rs | 1 - tests/box_executor/Cargo.toml | 2 +- tests/box_executor/src/main.rs | 4 +- tests/box_executor/src/runner.rs | 2 +- tests/chain-executor-mock/Cargo.toml | 2 +- tests/chain-executor-mock/src/main.rs | 4 +- tests/chain_performance_by_mq/Cargo.toml | 2 +- tests/chain_performance_by_mq/src/main.rs | 4 +- tests/consensus-mock/Cargo.toml | 2 +- tests/consensus-mock/src/main.rs | 4 +- tools/relayer-parser/Cargo.toml | 2 +- tools/relayer-parser/src/main.rs | 4 +- tools/snapshot_tool/Cargo.toml | 2 +- tools/snapshot_tool/src/main.rs | 2 +- 50 files changed, 130 insertions(+), 136 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e590324b..c2c0ced71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,7 +125,7 @@ dependencies = [ [[package]] name = "authority_manage" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -260,7 +260,7 @@ dependencies = [ [[package]] name = "blake2b" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -315,12 +315,12 @@ version = "0.1.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -393,12 +393,12 @@ version = "0.1.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -414,6 +414,7 @@ version = "0.1.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", @@ -421,7 +422,6 @@ dependencies = [ "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -445,6 +445,7 @@ version = "0.1.0" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.1.0", @@ -455,7 +456,6 @@ dependencies = [ "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "lru 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -478,6 +478,7 @@ dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -485,7 +486,6 @@ dependencies = [ "engine 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "min-max-heap 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ntp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -504,6 +504,7 @@ version = "0.6.0" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", @@ -513,7 +514,6 @@ dependencies = [ "error 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", @@ -523,7 +523,7 @@ dependencies = [ [[package]] name = "cita-crypto" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -534,7 +534,7 @@ dependencies = [ [[package]] name = "cita-crypto-trait" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] @@ -542,7 +542,7 @@ dependencies = [ [[package]] name = "cita-directories" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -550,7 +550,7 @@ dependencies = [ [[package]] name = "cita-ed25519" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -570,6 +570,7 @@ dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", @@ -583,7 +584,6 @@ dependencies = [ "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", @@ -597,9 +597,9 @@ dependencies = [ name = "cita-forever" version = "0.1.0" dependencies = [ + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -610,6 +610,7 @@ name = "cita-jsonrpc" version = "0.1.0" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -622,7 +623,6 @@ dependencies = [ "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -642,10 +642,23 @@ dependencies = [ "ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cita-logger" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "log4rs 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", + "signal-hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cita-merklehash" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -660,6 +673,7 @@ version = "0.6.0" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -667,7 +681,6 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "notify 4.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -686,6 +699,7 @@ name = "cita-relayer-parser" version = "0.1.0" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.1.0", @@ -694,7 +708,6 @@ dependencies = [ "hyper 0.11.22 (git+https://github.com/cryptape/hyper.git?branch=reuse_port)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", @@ -705,7 +718,7 @@ dependencies = [ [[package]] name = "cita-secp256k1" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -722,7 +735,7 @@ dependencies = [ [[package]] name = "cita-sm2" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -736,7 +749,7 @@ dependencies = [ [[package]] name = "cita-types" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -788,13 +801,13 @@ version = "0.1.0" dependencies = [ "bloomchain 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rlp_derive 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -811,11 +824,11 @@ dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", @@ -844,6 +857,7 @@ dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-merklehash 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-secp256k1 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -855,7 +869,6 @@ dependencies = [ "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -882,6 +895,7 @@ dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-merklehash 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-secp256k1 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -901,7 +915,6 @@ dependencies = [ "largest-remainder-method 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1117,14 +1130,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "db" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "elastic-array 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "parity-rocksdb 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1187,7 +1200,7 @@ dependencies = [ [[package]] name = "engine" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1250,7 +1263,7 @@ dependencies = [ [[package]] name = "error" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" [[package]] name = "error-chain" @@ -1311,7 +1324,7 @@ dependencies = [ [[package]] name = "ethcore-bloom-journal" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1356,12 +1369,12 @@ name = "evm" version = "0.1.0" dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "common-types 0.1.0", "db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1592,7 +1605,7 @@ dependencies = [ [[package]] name = "hashable" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "blake2b 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1794,13 +1807,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-proto" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1811,7 +1824,7 @@ dependencies = [ [[package]] name = "jsonrpc-types" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1825,7 +1838,7 @@ dependencies = [ [[package]] name = "jsonrpc-types-internals" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1907,14 +1920,14 @@ dependencies = [ [[package]] name = "libproto" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-merklehash 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "grpc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "protobuf 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2060,19 +2073,6 @@ dependencies = [ "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "logger" -version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" -dependencies = [ - "chrono 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "log4rs 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", - "signal-hook 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "lru" version = "0.1.8" @@ -2426,10 +2426,10 @@ dependencies = [ [[package]] name = "panic_hook" version = "0.0.1" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2553,7 +2553,7 @@ dependencies = [ [[package]] name = "proof" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2576,7 +2576,7 @@ dependencies = [ [[package]] name = "pubsub" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "pubsub_kafka 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2587,19 +2587,19 @@ dependencies = [ [[package]] name = "pubsub_kafka" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rdkafka 0.12.0 (git+https://github.com/fede1024/rust-rdkafka.git?rev=84d4062)", ] [[package]] name = "pubsub_rabbitmq" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "amqp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2608,10 +2608,10 @@ dependencies = [ [[package]] name = "pubsub_zeromq" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "zmq 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2934,7 +2934,7 @@ dependencies = [ [[package]] name = "rlp" version = "0.2.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2946,7 +2946,7 @@ dependencies = [ [[package]] name = "rlp_derive" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3159,7 +3159,7 @@ dependencies = [ [[package]] name = "snappy" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3168,12 +3168,12 @@ dependencies = [ name = "snapshot_tool" version = "0.2.0" dependencies = [ + "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "error 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] @@ -3784,7 +3784,7 @@ dependencies = [ [[package]] name = "tx_pool" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -3926,7 +3926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "util" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#f2ae26f263350dc4ce586d93dec78bd09aedb275" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -4173,6 +4173,7 @@ dependencies = [ "checksum cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" +"checksum cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c0fccf6b33be6ab71808f2b5bb36206acef2eee9f5d0d29f87b81327242b521" "checksum cita-merklehash 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum cita-secp256k1 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum cita-sm2 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" @@ -4300,7 +4301,6 @@ dependencies = [ "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum log-mdc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7" "checksum log4rs 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "25e0fc8737a634116a2deb38d821e4400ed16ce9dcb0d628a978d399260f5902" -"checksum logger 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum lru 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5fb41c1934bda881f2ab7ad8afa2ec25b8e0453563bfb09854bf3c319b1c96c3" "checksum lru-cache 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4d06ff7ff06f729ce5f4e227876cb88d10bc59cd4ae1e09fbb2bde15c850dc21" "checksum lz4-sys 1.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a41fe7bc4964530eb26cf243b6ca0348a5d67949957840fe6489d5322a3ce937" diff --git a/cita-auth/Cargo.toml b/cita-auth/Cargo.toml index 1ceaa6aa9..e263b2dc7 100644 --- a/cita-auth/Cargo.toml +++ b/cita-auth/Cargo.toml @@ -10,12 +10,12 @@ cpuprofiler = "0.0.3" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" +cita-logger = "0.1.0" cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-directories = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } error = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } tx_pool = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/cita-auth/src/main.rs b/cita-auth/src/main.rs index fa2830da9..7ae31f4ec 100644 --- a/cita-auth/src/main.rs +++ b/cita-auth/src/main.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -80,7 +80,7 @@ extern crate jsonrpc_types; #[macro_use] extern crate libproto; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate lru; extern crate pubsub; #[cfg(test)] diff --git a/cita-bft b/cita-bft index 7041bda10..72cf820cc 160000 --- a/cita-bft +++ b/cita-bft @@ -1 +1 @@ -Subproject commit 7041bda10499e88e7646f5df707b8058c09c9c67 +Subproject commit 72cf820cc057bf5b3860cdf5e41a1cd6b9030989 diff --git a/cita-chain/Cargo.toml b/cita-chain/Cargo.toml index d37ead0a8..d6460c18a 100644 --- a/cita-chain/Cargo.toml +++ b/cita-chain/Cargo.toml @@ -9,13 +9,13 @@ dotenv = "0.13.0" clap = "2" byteorder = { version = "1", default-features = false } serde_json = "1.0" +cita-logger = "0.1.0" cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-directories = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } error = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } jsonrpc-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } core = { path = "./core" } common-types = { path = "./types" } diff --git a/cita-chain/core/Cargo.toml b/cita-chain/core/Cargo.toml index 099a6d636..93d988614 100644 --- a/cita-chain/core/Cargo.toml +++ b/cita-chain/core/Cargo.toml @@ -15,8 +15,8 @@ bit-set = "0.4" time = "0.1" crossbeam = "0.2" transient-hashmap = "0.4.0" +cita-logger = "0.1.0" libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-ed25519 = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-secp256k1 = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } @@ -37,7 +37,7 @@ pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develo rand = "0.3" cpuprofiler = "0.0.3" tempdir = "0.3.7" -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita-logger = "0.1.0" [features] default = ["secp256k1", "sha3hash"] diff --git a/cita-chain/core/src/lib.rs b/cita-chain/core/src/lib.rs index 75c560054..08cac6fe8 100644 --- a/cita-chain/core/src/lib.rs +++ b/cita-chain/core/src/lib.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -19,7 +19,7 @@ extern crate byteorder; #[macro_use] extern crate libproto; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate cita_merklehash; extern crate hashable; extern crate lru_cache; diff --git a/cita-chain/src/main.rs b/cita-chain/src/main.rs index afa080b51..38a8c787a 100644 --- a/cita-chain/src/main.rs +++ b/cita-chain/src/main.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -77,7 +77,7 @@ extern crate jsonrpc_types; #[macro_use] extern crate libproto; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate proof; extern crate pubsub; extern crate serde_json; diff --git a/cita-chain/types/Cargo.toml b/cita-chain/types/Cargo.toml index 9d3e07ef9..2330d2d07 100644 --- a/cita-chain/types/Cargo.toml +++ b/cita-chain/types/Cargo.toml @@ -18,7 +18,7 @@ serde_derive = "1.0" bloomchain = "0.2" lazy_static = "0.2" time = "0.1" -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita-logger = "0.1.0" proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } db = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/cita-chain/types/src/lib.rs b/cita-chain/types/src/lib.rs index 972f21568..f7b762159 100644 --- a/cita-chain/types/src/lib.rs +++ b/cita-chain/types/src/lib.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -30,7 +30,7 @@ extern crate util; extern crate lazy_static; extern crate time; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate db as cita_db; extern crate proof; diff --git a/cita-executor/Cargo.toml b/cita-executor/Cargo.toml index 6138034fc..bba8f769d 100644 --- a/cita-executor/Cargo.toml +++ b/cita-executor/Cargo.toml @@ -11,11 +11,11 @@ crossbeam-channel = "0.2" serde_json = "1.0" serde_derive = "1.0" grpc = "0.5.0" +cita-logger = "0.1.0" cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-directories = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } error = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/cita-executor/core/Cargo.toml b/cita-executor/core/Cargo.toml index 09afa732e..bb21e6e3b 100644 --- a/cita-executor/core/Cargo.toml +++ b/cita-executor/core/Cargo.toml @@ -4,9 +4,9 @@ version = "0.1.0" authors = ["Parity Technologies ", "Cryptape Technologies "] [dependencies] +cita-logger = "0.1.0" libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } byteorder = { version = "1", default-features = false } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-merklehash = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } snappy = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/cita-executor/core/src/contracts/solc/node_manager.rs b/cita-executor/core/src/contracts/solc/node_manager.rs index 8e2644125..bb9f93365 100644 --- a/cita-executor/core/src/contracts/solc/node_manager.rs +++ b/cita-executor/core/src/contracts/solc/node_manager.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -134,7 +134,7 @@ impl<'a> NodeManager<'a> { #[cfg(test)] mod tests { - extern crate logger; + extern crate cita_logger as logger; use super::{party_seats, shuffle, NodeManager}; use cita_types::H160; diff --git a/cita-executor/core/src/contracts/solc/permission_management.rs b/cita-executor/core/src/contracts/solc/permission_management.rs index 6b6e2f980..b6b0793be 100644 --- a/cita-executor/core/src/contracts/solc/permission_management.rs +++ b/cita-executor/core/src/contracts/solc/permission_management.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -182,7 +182,7 @@ pub fn contains_resource( #[cfg(test)] mod tests { - extern crate logger; + extern crate cita_logger as logger; use super::contains_resource; use super::{PermissionManagement, Resource, DEFAULT_SUPER_ADEMIN}; diff --git a/cita-executor/core/src/contracts/solc/quota_manager.rs b/cita-executor/core/src/contracts/solc/quota_manager.rs index 57df815d6..f05b2c649 100644 --- a/cita-executor/core/src/contracts/solc/quota_manager.rs +++ b/cita-executor/core/src/contracts/solc/quota_manager.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -195,7 +195,7 @@ impl<'a> QuotaManager<'a> { #[cfg(test)] mod tests { - extern crate logger; + extern crate cita_logger as logger; use super::{QuotaManager, AQL_VALUE, AUTO_EXEC_QL_VALUE, BQL_VALUE}; use cita_types::H160; diff --git a/cita-executor/core/src/contracts/solc/sys_config.rs b/cita-executor/core/src/contracts/solc/sys_config.rs index d2dc7f2b7..27be4704b 100644 --- a/cita-executor/core/src/contracts/solc/sys_config.rs +++ b/cita-executor/core/src/contracts/solc/sys_config.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -348,7 +348,7 @@ impl<'a> SysConfig<'a> { #[cfg(test)] mod tests { - extern crate logger; + extern crate cita_logger as logger; use super::{EconomicalModel, SysConfig, TokenInfo}; use cita_types::Address; diff --git a/cita-executor/core/src/contracts/solc/user_management.rs b/cita-executor/core/src/contracts/solc/user_management.rs index 8f2ae3977..f8ce4b9ad 100644 --- a/cita-executor/core/src/contracts/solc/user_management.rs +++ b/cita-executor/core/src/contracts/solc/user_management.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -96,7 +96,7 @@ impl<'a> UserManagement<'a> { #[cfg(test)] mod tests { - extern crate logger; + extern crate cita_logger as logger; use super::UserManagement; use cita_types::{Address, H160}; diff --git a/cita-executor/core/src/executive.rs b/cita-executor/core/src/executive.rs index 5e487b5b9..312933503 100644 --- a/cita-executor/core/src/executive.rs +++ b/cita-executor/core/src/executive.rs @@ -1210,7 +1210,7 @@ impl<'a, B: 'a + StateBackend> Executive<'a, B> { #[cfg(test)] mod tests { - extern crate logger; + extern crate cita_logger as logger; extern crate rustc_hex; //////////////////////////////////////////////////////////////////////////////// diff --git a/cita-executor/core/src/lib.rs b/cita-executor/core/src/lib.rs index a6491abc1..f3eb06db6 100644 --- a/cita-executor/core/src/lib.rs +++ b/cita-executor/core/src/lib.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -21,7 +21,7 @@ extern crate cita_crypto_trait; extern crate libproto; extern crate snappy; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate lru_cache; extern crate proof; extern crate rlp; diff --git a/cita-executor/core/src/libexecutor/executor.rs b/cita-executor/core/src/libexecutor/executor.rs index 4718693d9..3defdef8c 100644 --- a/cita-executor/core/src/libexecutor/executor.rs +++ b/cita-executor/core/src/libexecutor/executor.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -465,7 +465,7 @@ pub fn make_consensus_config(sys_config: GlobalSysConfig) -> ConsensusConfig { } #[cfg(test)] mod tests { - extern crate logger; + extern crate cita_logger as logger; extern crate tempdir; use cita_crypto::{CreateKey, KeyPair}; diff --git a/cita-executor/core/src/state/mod.rs b/cita-executor/core/src/state/mod.rs index 9a27dc51b..2b058dadd 100644 --- a/cita-executor/core/src/state/mod.rs +++ b/cita-executor/core/src/state/mod.rs @@ -1196,8 +1196,8 @@ impl fmt::Debug for State { #[cfg(test)] mod tests { + extern crate cita_logger as logger; extern crate libproto; - extern crate logger; extern crate rustc_hex; //////////////////////////////////////////////////////////////////////////////// diff --git a/cita-executor/evm/Cargo.toml b/cita-executor/evm/Cargo.toml index 0dfa3ccfc..3ea76e81b 100644 --- a/cita-executor/evm/Cargo.toml +++ b/cita-executor/evm/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" authors = ["Parity Technologies ", "Cryptape Technologies "] [dependencies] +cita-logger = "0.1.0" cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } lazy_static = "0.2" @@ -11,7 +12,6 @@ util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" bit-set = "0.4" common-types = { path = "../../cita-chain/types" } rlp = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } rustc-hex = "1.0" db = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/cita-executor/evm/src/lib.rs b/cita-executor/evm/src/lib.rs index ed6e4fa48..bda2e54e1 100644 --- a/cita-executor/evm/src/lib.rs +++ b/cita-executor/evm/src/lib.rs @@ -17,12 +17,12 @@ //! Ethereum virtual machine. extern crate bit_set; +#[cfg_attr(feature = "evm-debug", macro_use)] +extern crate cita_logger as logger; pub extern crate cita_types; extern crate common_types as types; extern crate db as cita_db; extern crate hashable; -#[cfg_attr(feature = "evm-debug", macro_use)] -extern crate logger; extern crate rlp; extern crate rustc_hex; extern crate util; diff --git a/cita-executor/src/main.rs b/cita-executor/src/main.rs index 4a13005f3..32b84ee31 100644 --- a/cita-executor/src/main.rs +++ b/cita-executor/src/main.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -101,7 +101,7 @@ extern crate jsonrpc_types; #[macro_use] extern crate libproto; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate proof; extern crate pubsub; #[macro_use] diff --git a/cita-forever b/cita-forever index 98151d3c9..b7ed8570d 160000 --- a/cita-forever +++ b/cita-forever @@ -1 +1 @@ -Subproject commit 98151d3c9fd89445e08946d01e113dacb8f76002 +Subproject commit b7ed8570d6762c2d3c4c607da7f6379538157eba diff --git a/cita-jsonrpc/Cargo.toml b/cita-jsonrpc/Cargo.toml index 8a9ce241f..0964ebf6b 100644 --- a/cita-jsonrpc/Cargo.toml +++ b/cita-jsonrpc/Cargo.toml @@ -14,9 +14,9 @@ serde_json = "1.0" cpuprofiler = "0.0.3" dotenv = "0.13.0" clap = "2" +cita-logger = "0.1.0" util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } error = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } jsonrpc-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/cita-jsonrpc/src/main.rs b/cita-jsonrpc/src/main.rs index a181697e6..303b10ec1 100644 --- a/cita-jsonrpc/src/main.rs +++ b/cita-jsonrpc/src/main.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -68,7 +68,7 @@ extern crate libc; #[macro_use] extern crate libproto; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate net2; extern crate num_cpus; extern crate pubsub; diff --git a/cita-network/Cargo.toml b/cita-network/Cargo.toml index c9c083958..c18be746a 100644 --- a/cita-network/Cargo.toml +++ b/cita-network/Cargo.toml @@ -9,11 +9,11 @@ tentacle-discovery = "0.2.4" tentacle = "0.2.0-alpha.14" tokio = "0.1.14" futures = "0.1.25" +cita-logger = "0.1.0" cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } jsonrpc-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } serde = "1.0.84" serde_json = "1.0" diff --git a/cita-network/src/config.rs b/cita-network/src/config.rs index 05d60a157..376151232 100644 --- a/cita-network/src/config.rs +++ b/cita-network/src/config.rs @@ -16,7 +16,6 @@ // along with this program. If not, see . use cita_types::{clean_0x, Address}; -use logger::info; use serde_derive::Deserialize; use std::fs::File; use std::io::Read; diff --git a/cita-network/src/main.rs b/cita-network/src/main.rs index f3e2fbbd0..4f40b4241 100644 --- a/cita-network/src/main.rs +++ b/cita-network/src/main.rs @@ -79,6 +79,9 @@ //! [`network_message_to_pubsub_message`]: ./citaprotocol/fn.network_message_to_pubsub_message.html //! +#[macro_use] +extern crate cita_logger as logger; + pub mod cita_protocol; pub mod config; pub mod mq_agent; @@ -98,7 +101,6 @@ use crate::synchronizer::Synchronizer; use clap::App; use dotenv; use futures::prelude::*; -use logger::{debug, info}; use notify::{RecommendedWatcher, RecursiveMode, Watcher}; use std::path::Path; use std::sync::mpsc::channel; diff --git a/cita-network/src/mq_agent.rs b/cita-network/src/mq_agent.rs index 40cbaa75f..42708c471 100644 --- a/cita-network/src/mq_agent.rs +++ b/cita-network/src/mq_agent.rs @@ -20,7 +20,6 @@ use crate::node_manager::NodesManagerClient; use libproto::router::{MsgType, RoutingKey, SubModules}; use libproto::routing_key; use libproto::{Message, TryFrom}; -use logger::{trace, warn}; use pubsub::channel::{unbounded, Receiver, Sender}; use pubsub::start_pubsub; use std::thread; diff --git a/cita-network/src/network.rs b/cita-network/src/network.rs index 02c25cdac..dd6e652ad 100644 --- a/cita-network/src/network.rs +++ b/cita-network/src/network.rs @@ -27,7 +27,6 @@ use libproto::routing_key; use libproto::snapshot::{Cmd, Resp, SnapshotResp}; use libproto::{Message as ProtoMessage, OperateType, Response}; use libproto::{TryFrom, TryInto}; -use logger::{error, info, trace, warn}; use pubsub::channel::{unbounded, Receiver, Sender}; use serde_json; use std::iter::FromIterator; diff --git a/cita-network/src/node_manager.rs b/cita-network/src/node_manager.rs index a464b7bb9..8de3d6277 100644 --- a/cita-network/src/node_manager.rs +++ b/cita-network/src/node_manager.rs @@ -22,7 +22,6 @@ use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use cita_types::Address; use fnv::FnvHashMap as HashMap; use libproto::{Message as ProtoMessage, TryInto}; -use logger::{debug, error, info, trace, warn}; use notify::DebouncedEvent; use pubsub::channel::{select, tick, unbounded, Receiver, Sender}; use rand; diff --git a/cita-network/src/p2p_protocol/mod.rs b/cita-network/src/p2p_protocol/mod.rs index d87b20adf..f711af299 100644 --- a/cita-network/src/p2p_protocol/mod.rs +++ b/cita-network/src/p2p_protocol/mod.rs @@ -19,7 +19,6 @@ use crate::node_manager::{ AddRepeatedNodeReq, ConnectedSelfReq, DelConnectedNodeReq, DialedErrorReq, NodesManagerClient, PendingConnectedNodeReq, }; -use logger::{info, warn}; use tentacle::{ context::ServiceContext, error, diff --git a/cita-network/src/p2p_protocol/node_discovery.rs b/cita-network/src/p2p_protocol/node_discovery.rs index 0940a52ef..c1da0da3a 100644 --- a/cita-network/src/p2p_protocol/node_discovery.rs +++ b/cita-network/src/p2p_protocol/node_discovery.rs @@ -16,7 +16,6 @@ // along with this program. If not, see . use crate::node_manager::{AddNodeReq, GetRandomNodesReq, NodeSource, NodesManagerClient}; -use logger::{info, warn}; use pubsub::channel::unbounded; use tentacle::{ builder::MetaBuilder, diff --git a/cita-network/src/p2p_protocol/transfer.rs b/cita-network/src/p2p_protocol/transfer.rs index 33116bb74..4dddefdff 100644 --- a/cita-network/src/p2p_protocol/transfer.rs +++ b/cita-network/src/p2p_protocol/transfer.rs @@ -20,7 +20,6 @@ use crate::network::{NetworkClient, RemoteMessage}; use crate::node_manager::{AddConnectedNodeReq, InitMsg, NetworkInitReq, NodesManagerClient}; use bytes::BytesMut; use libproto::{Message as ProtoMessage, TryFrom, TryInto}; -use logger::{info, warn}; use tentacle::{ builder::MetaBuilder, context::{ProtocolContext, ProtocolContextMutRef}, diff --git a/cita-network/src/synchronizer.rs b/cita-network/src/synchronizer.rs index 00f8321a0..813173347 100644 --- a/cita-network/src/synchronizer.rs +++ b/cita-network/src/synchronizer.rs @@ -22,7 +22,6 @@ use libproto::router::{MsgType, RoutingKey, SubModules}; use libproto::routing_key; use libproto::{Message, OperateType, SyncRequest, SyncResponse}; use libproto::{TryFrom, TryInto}; -use logger::{debug, error, info, warn}; use pubsub::channel::{unbounded, Receiver, Sender}; use rand::{thread_rng, Rng, ThreadRng}; use std::collections::{BTreeMap, HashSet, VecDeque}; diff --git a/tests/box_executor/Cargo.toml b/tests/box_executor/Cargo.toml index aecc63f40..1d6b442c6 100644 --- a/tests/box_executor/Cargo.toml +++ b/tests/box_executor/Cargo.toml @@ -11,11 +11,11 @@ clap = "2" rustc-serialize = "0.3" dotenv = "0.13.0" bincode = "0.8.0" +cita-logger = "0.1.0" libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } rlp = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/tests/box_executor/src/main.rs b/tests/box_executor/src/main.rs index 9ccddd9b8..2b7ddda63 100644 --- a/tests/box_executor/src/main.rs +++ b/tests/box_executor/src/main.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -26,7 +26,7 @@ extern crate hashable; extern crate proof; extern crate rustc_serialize; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate pubsub; extern crate rlp; diff --git a/tests/box_executor/src/runner.rs b/tests/box_executor/src/runner.rs index c05ca1581..5842e4232 100644 --- a/tests/box_executor/src/runner.rs +++ b/tests/box_executor/src/runner.rs @@ -1,9 +1,9 @@ extern crate bincode; extern crate cita_crypto as crypto; +extern crate cita_logger as logger; extern crate cita_types; extern crate clap; extern crate dotenv; -extern crate logger; extern crate proof; extern crate pubsub; extern crate rlp; diff --git a/tests/chain-executor-mock/Cargo.toml b/tests/chain-executor-mock/Cargo.toml index 6d77e2007..9b5ac2962 100644 --- a/tests/chain-executor-mock/Cargo.toml +++ b/tests/chain-executor-mock/Cargo.toml @@ -11,11 +11,11 @@ clap = "2" rustc-serialize = "0.3" dotenv = "0.13.0" bincode = "0.8.0" +cita-logger = "0.1.0" libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } rlp = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/tests/chain-executor-mock/src/main.rs b/tests/chain-executor-mock/src/main.rs index bb337812b..fd6311d3d 100644 --- a/tests/chain-executor-mock/src/main.rs +++ b/tests/chain-executor-mock/src/main.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -26,7 +26,7 @@ extern crate proof; extern crate rustc_serialize; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate pubsub; extern crate rlp; #[macro_use] diff --git a/tests/chain_performance_by_mq/Cargo.toml b/tests/chain_performance_by_mq/Cargo.toml index 88ff62a6f..fdc7be9d1 100644 --- a/tests/chain_performance_by_mq/Cargo.toml +++ b/tests/chain_performance_by_mq/Cargo.toml @@ -7,13 +7,13 @@ authors = ["Cryptape Technologies "] serde = "1.0" serde_derive = "1.0" clap = "2" +cita-logger = "0.1.0" libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } rustc-serialize = "0.3" cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } dotenv = "0.13.0" -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } bincode = "0.8.0" cpuprofiler = "0.0.3" diff --git a/tests/chain_performance_by_mq/src/main.rs b/tests/chain_performance_by_mq/src/main.rs index cd2e42e74..f8acc5243 100644 --- a/tests/chain_performance_by_mq/src/main.rs +++ b/tests/chain_performance_by_mq/src/main.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -28,7 +28,7 @@ extern crate proof; extern crate rustc_serialize; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate pubsub; #[macro_use] extern crate serde_derive; diff --git a/tests/consensus-mock/Cargo.toml b/tests/consensus-mock/Cargo.toml index 498a2fdca..4a5e20a27 100644 --- a/tests/consensus-mock/Cargo.toml +++ b/tests/consensus-mock/Cargo.toml @@ -7,6 +7,7 @@ authors = ["Cryptape Technologies "] serde = "1.0" serde_derive = "1.0" bincode = "0.8.0" +cita-logger = "0.1.0" libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } clap = "2" @@ -14,7 +15,6 @@ pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develo cita-types = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } chrono = "0.4.2" [features] diff --git a/tests/consensus-mock/src/main.rs b/tests/consensus-mock/src/main.rs index c2228f1c4..2a2e061eb 100644 --- a/tests/consensus-mock/src/main.rs +++ b/tests/consensus-mock/src/main.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -23,7 +23,7 @@ extern crate clap; #[macro_use] extern crate libproto; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate proof; extern crate pubsub; #[macro_use] diff --git a/tools/relayer-parser/Cargo.toml b/tools/relayer-parser/Cargo.toml index 206da8db5..f586e63bd 100644 --- a/tools/relayer-parser/Cargo.toml +++ b/tools/relayer-parser/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" authors = ["Cryptape Technologies "] [dependencies] -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +cita-logger = "0.1.0" serde = "1.0" serde_derive = "1.0" serde_json = "1.0" diff --git a/tools/relayer-parser/src/main.rs b/tools/relayer-parser/src/main.rs index a0bf870a2..6bff5efdf 100644 --- a/tools/relayer-parser/src/main.rs +++ b/tools/relayer-parser/src/main.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -33,7 +33,7 @@ extern crate core; extern crate jsonrpc_types; extern crate libproto; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; mod arguments; mod communication; diff --git a/tools/snapshot_tool/Cargo.toml b/tools/snapshot_tool/Cargo.toml index a9015aefa..c5d47b18d 100644 --- a/tools/snapshot_tool/Cargo.toml +++ b/tools/snapshot_tool/Cargo.toml @@ -7,8 +7,8 @@ authors = ["Cryptape Technologies "] dotenv = "0.13.0" clap = "2" fs2 = "0.4.3" +cita-logger = "0.1.0" util = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -logger = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } error = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/tools/snapshot_tool/src/main.rs b/tools/snapshot_tool/src/main.rs index ae1401da6..7cb3c3474 100644 --- a/tools/snapshot_tool/src/main.rs +++ b/tools/snapshot_tool/src/main.rs @@ -22,7 +22,7 @@ extern crate fs2; #[macro_use] extern crate libproto; #[macro_use] -extern crate logger; +extern crate cita_logger as logger; extern crate pubsub; #[macro_use] extern crate util; From 483104615fade290d3c723b0c6f05d2c30400a1d Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 29 May 2019 11:07:38 +0800 Subject: [PATCH 18/91] Replace the sleep with timeout. [skip travis] --- tests/integrate_test/cita_basic.sh | 7 ++----- tests/integrate_test/cita_snapshot_test.sh | 4 +--- tests/integrate_test/cita_tls_basic.sh | 4 +--- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/integrate_test/cita_basic.sh b/tests/integrate_test/cita_basic.sh index f9dd6e7bd..097fd15a3 100755 --- a/tests/integrate_test/cita_basic.sh +++ b/tests/integrate_test/cita_basic.sh @@ -39,11 +39,9 @@ for i in {0..3} ; do done echo "DONE" -sleep 60 - ################################################################################ echo -n "4) check height growth normal ... " -timeout=$(check_height_growth_normal 0 15)||(echo "FAILED" +timeout=$(check_height_growth_normal 0 60)||(echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" @@ -67,8 +65,7 @@ echo "${timeout}s DONE" ################################################################################ echo -n "7) start node2, check height growth ... " bin/cita bebop start node/2 trace > /dev/null & -sleep 24 #wait for recovery from stop -timeout=$(check_height_growth_normal 0 15) || (echo "FAILED" +timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" diff --git a/tests/integrate_test/cita_snapshot_test.sh b/tests/integrate_test/cita_snapshot_test.sh index 9b91bf66c..430a8c94e 100755 --- a/tests/integrate_test/cita_snapshot_test.sh +++ b/tests/integrate_test/cita_snapshot_test.sh @@ -46,13 +46,11 @@ for id in {0,1,2}; do done echo "DONE" -sleep 10 - ################################################################################ echo "4) Check all nodes grow up ..." for id in {0..2}; do echo "chech_height_growth_normal $id ..." - timeout=`check_height_growth_normal $id 30`||(echo "FAILED" + timeout=`check_height_growth_normal $id 60`||(echo "FAILED" echo "error msg: ${timeout}" exit 1) done diff --git a/tests/integrate_test/cita_tls_basic.sh b/tests/integrate_test/cita_tls_basic.sh index b3ba7fb4f..ba733da2a 100755 --- a/tests/integrate_test/cita_tls_basic.sh +++ b/tests/integrate_test/cita_tls_basic.sh @@ -40,11 +40,9 @@ for i in {0..3} ; do done echo "DONE" -sleep 60 - ################################################################################ echo -n "4) check height growth normal ... " -timeout=$(check_height_growth_normal 0 15)||(echo "FAILED" +timeout=$(check_height_growth_normal 0 60)||(echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" From e8a25fe52fb9d2ed1e9144c526064709c5078d01 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Thu, 30 May 2019 11:50:13 +0800 Subject: [PATCH 19/91] Split the integrate test. --- .circleci/config.yml | 94 ++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 86 insertions(+), 8 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index be3e9771a..88ad801c8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -220,20 +220,27 @@ jobs: HASH_ALGO: sm3hash CRYPTO_ALGO: sm2 - "Integrate Test Part-1": + "Basic Test": <<: *job-default steps: - restore_cache: *restore-source-codes-cache - restore_cache: *restore-release-cache - run: *after-restore-release-cache - run: - name: Basic Integrate Test + name: Basic Test command: ./tests/integrate_test/cita_basic.sh + + "Basic Tls Test": + <<: *job-default + steps: + - restore_cache: *restore-source-codes-cache + - restore_cache: *restore-release-cache + - run: *after-restore-release-cache - run: - name: Basic Tls Integrate Test + name: Basic Tls Test command: ./tests/integrate_test/cita_tls_basic.sh - "Integrate Test Part-2": + "JSON-RPC Mock Test in Charge Mode": <<: *job-default steps: - restore_cache: *restore-source-codes-cache @@ -247,18 +254,63 @@ jobs: command: | echo "We should add it back later." # ./tests/integrate_test/cita_jsonrpc_schema_mock.sh charge + + "JSON-RPC Mock Test in Quota Mode": + <<: *job-default + steps: + - restore_cache: *restore-source-codes-cache + - restore_cache: *restore-release-cache + - run: *after-restore-release-cache + - run: + name: JSON-RPC Mock Test in Quota Mode + command: ./tests/integrate_test/cita_jsonrpc_schema_mock.sh quota + + "Test Transfer Value in Charge Mode": + <<: *job-default + steps: + - restore_cache: *restore-source-codes-cache + - restore_cache: *restore-release-cache + - run: *after-restore-release-cache - run: name: Test Transfer Value in Charge Mode command: ./tests/integrate_test/cita_charge_mode.sh + + "Test Executor Process SignProposal/BlockWithProof": + <<: *job-default + steps: + - restore_cache: *restore-source-codes-cache + - restore_cache: *restore-release-cache + - run: *after-restore-release-cache - run: name: Test Executor Process SignProposal/BlockWithProof command: ./tests/integrate_test/box_executor_test.sh + + "Test Snapshot Taking And Restoring": + <<: *job-default + steps: + - restore_cache: *restore-source-codes-cache + - restore_cache: *restore-release-cache + - run: *after-restore-release-cache - run: name: Test Snapshot Taking And Restoring command: ./tests/integrate_test/cita_snapshot_test.sh + + "Test Amend": + <<: *job-default + steps: + - restore_cache: *restore-source-codes-cache + - restore_cache: *restore-release-cache + - run: *after-restore-release-cache - run: name: Test Amend command: ./tests/integrate_test/cita_amend_test.sh + + "Test Executor Process Invalid Proof": + <<: *job-default + steps: + - restore_cache: *restore-source-codes-cache + - restore_cache: *restore-release-cache + - run: *after-restore-release-cache - run: name: Test Executor Process Invalid Proof command: ./tests/integrate_test/cita_bft_resend.sh @@ -372,12 +424,32 @@ workflows: requires: - "Release" - - "Integrate Test Part-1": + - "Basic Test": requires: - "Release" - - "Integrate Test Part-2": + - "Basic Tls Test": requires: - "Release" + + - "JSON-RPC Mock Test in Charge Mode": + requires: + - "Release" + - "JSON-RPC Mock Test in Quota Mode": + requires: + - "Release" + - "Test Transfer Value in Charge Mode": + requires: + - "Release" + - "Test Snapshot Taking And Restoring": + requires: + - "Release" + - "Test Amend": + requires: + - "Release" + - "Test Executor Process Invalid Proof": + requires: + - "Release" + - "Discovery Test for network": requires: - "Release" @@ -406,8 +478,14 @@ workflows: - "Passed": requires: - - "Integrate Test Part-1" - - "Integrate Test Part-2" + - "Basic Test" + - "Basic Tls Test" + - "JSON-RPC Mock Test in Charge Mode" + - "JSON-RPC Mock Test in Quota Mode" + - "Test Transfer Value in Charge Mode" + - "Test Snapshot Taking And Restoring" + - "Test Amend" + - "Test Executor Process Invalid Proof" - "Discovery Test for network" - "Byzantine Test in Quota Mode" - "Byzantine Test in Charge Mode" From 3be5fb90c7c4572f4fd5032dead00ecca83a033e Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Thu, 30 May 2019 12:05:16 +0800 Subject: [PATCH 20/91] Remove uselsee cleanup in test scripts. [skip travis] --- tests/integrate_test/box_executor_test.sh | 19 ++-------- tests/integrate_test/cita_amend_test.sh | 27 ++++---------- tests/integrate_test/cita_basic.sh | 28 +++++---------- tests/integrate_test/cita_bft_resend.sh | 19 +++------- tests/integrate_test/cita_byzantinetest.sh | 24 ++++--------- tests/integrate_test/cita_charge_mode.sh | 35 +++++-------------- tests/integrate_test/cita_discovery.sh | 15 ++------ .../cita_jsonrpc_schema_mock.sh | 20 +++-------- tests/integrate_test/cita_snapshot_test.sh | 28 ++++----------- tests/integrate_test/cita_tls_basic.sh | 28 +++++---------- 10 files changed, 62 insertions(+), 181 deletions(-) diff --git a/tests/integrate_test/box_executor_test.sh b/tests/integrate_test/box_executor_test.sh index e03390e2c..8825c48f1 100755 --- a/tests/integrate_test/box_executor_test.sh +++ b/tests/integrate_test/box_executor_test.sh @@ -27,12 +27,7 @@ cd ${BINARY_DIR} echo "DONE" ################################################################################ -echo -n "1) cleanup ... " -cleanup ${CHAIN_NAME} -echo -n "DONE" - -################################################################################ -echo -n "2) generate config ... " +echo -n "1) generate config ... " if [ ! -d "resource" ]; then mkdir resource fi @@ -49,7 +44,7 @@ ${BINARY_DIR}/scripts/create_cita_config.py create \ echo -n "DONE" ################################################################################ -echo -n "3) start cita-chain and cita-executor on ${NODE_NAME} ... " +echo -n "2) start cita-chain and cita-executor on ${NODE_NAME} ... " ${BINARY_DIR}/bin/cita setup ${NODE_NAME} curl -i -u guest:guest -H content-type:application/json -XDELETE \ @@ -63,16 +58,8 @@ executor_pid=$! echo -n "DONE" ## ################################################################################ -echo -n "4) testing ... " +echo -n "3) testing ... " AMQP_URL=amqp://guest:guest@localhost/${NODE_NAME} \ timeout 100s ${BINARY_DIR}/bin/box_executor \ -m ${SOURCE_DIR}/tests/interfaces/config/blockchain.yaml echo -n "DONE" - -################################################################################ -echo -n "5) stop cita-chain and cita-executor on ${NODE_NAME}" -kill "${chain_pid}" -kill "${executor_pid}" -cleanup ${CHAIN_NAME} -echo -n "PASS" -exit 0 diff --git a/tests/integrate_test/cita_amend_test.sh b/tests/integrate_test/cita_amend_test.sh index 440fdf17c..3679c8f4e 100755 --- a/tests/integrate_test/cita_amend_test.sh +++ b/tests/integrate_test/cita_amend_test.sh @@ -22,19 +22,14 @@ cd "${BINARY_DIR}" echo "DONE" ################################################################################ -echo "1) Clean Up ..." -cleanup "${CHAIN_NAME}" -echo "DONE" - -################################################################################ -echo "2) Generate CITA configurations ..." +echo "1) Generate CITA configurations ..." ${BINARY_DIR}/scripts/create_cita_config.py create \ --nodes "127.0.0.1:4000" \ --super_admin "${SUPER_ADMIN}" echo "DONE" ################################################################################ -echo "3) Run node-0" +echo "2) Run node-0" ${BINARY_DIR}/bin/cita bebop setup ${CHAIN_NAME}/0 > /dev/null ${BINARY_DIR}/bin/cita bebop start ${CHAIN_NAME}/0 trace echo "DONE" @@ -42,7 +37,7 @@ echo "DONE" sleep 10 ################################################################################ -echo "4) Check node grow up ..." +echo "3) Check node grow up ..." echo "chech_height_growth_normal 0 ..." timeout=`check_height_growth_normal 0 15`||(echo "FAILED" echo "error msg: ${timeout}" @@ -50,7 +45,7 @@ timeout=`check_height_growth_normal 0 15`||(echo "FAILED" echo "${timeout}s DONE" ################################################################################ -echo "5) Amend chain name ..." +echo "4) Amend chain name ..." cd ${BINARY_DIR}/scripts/txtool/txtool curl -X POST --data '{"jsonrpc":"2.0","method":"getMetaData","params":["latest"],"id":1}' 127.0.0.1:1337 \ @@ -70,7 +65,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"getMetaData","params":["latest"] | grep "\"chainName\"\:\"0est-chain\"" ################################################################################ -echo "6) Amend abi ..." +echo "5) Amend abi ..." cd ${BINARY_DIR}/scripts/txtool/txtool # set abi of 0xffffffffffffffffffffffffffffffffff020000 as "amendabitest" @@ -89,7 +84,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"getAbi","params":["0xfffffffffff | grep "616d656e6461626974657374" ################################################################################ -echo "7) Amend balance ..." +echo "6) Amend balance ..." cd ${BINARY_DIR}/scripts/txtool/txtool # set balance of 0xffffffffffffffffffffffffffffffffff020000 as 1234(0x4d2) @@ -108,7 +103,7 @@ curl -X POST --data '{"jsonrpc":"2.0","method":"getBalance","params":["0xfffffff | grep "0x4d2" ################################################################################ -echo "8) Amend code ..." +echo "7) Amend code ..." cd ${BINARY_DIR}/scripts/txtool/txtool # set code of 0xffffffffffffffffffffffffffffffffff020004 as "deadbeef" @@ -125,11 +120,3 @@ sleep 10 # hex of 1234 curl -X POST --data '{"jsonrpc":"2.0","method":"getCode","params":["0xffffffffffffffffffffffffffffffffff020004", "latest"],"id":1}' 127.0.0.1:1337 \ | grep "0xdeadbeef" - -################################################################################ -echo "9) Clean Up ..." -cd ${BINARY_DIR} -${BINARY_DIR}/bin/cita bebop stop ${CHAIN_NAME}/0 - -cleanup -echo "DONE" diff --git a/tests/integrate_test/cita_basic.sh b/tests/integrate_test/cita_basic.sh index 097fd15a3..316ecda32 100755 --- a/tests/integrate_test/cita_basic.sh +++ b/tests/integrate_test/cita_basic.sh @@ -16,12 +16,7 @@ cd ${BINARY_DIR} echo "DONE" ################################################################################ -echo -n "1) cleanup ... " -cleanup -echo "DONE" - -################################################################################ -echo -n "2) generate config ... " +echo -n "1) generate config ... " ./scripts/create_cita_config.py create \ --chain_name "node" \ --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ @@ -30,7 +25,7 @@ echo -n "2) generate config ... " echo "DONE" ################################################################################ -echo -n "3) start nodes ... " +echo -n "2) start nodes ... " for i in {0..3} ; do bin/cita bebop setup node/$i > /dev/null done @@ -40,14 +35,14 @@ done echo "DONE" ################################################################################ -echo -n "4) check height growth normal ... " +echo -n "3) check height growth normal ... " timeout=$(check_height_growth_normal 0 60)||(echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" ################################################################################ -echo -n "5) stop node3, check height growth ... " +echo -n "4) stop node3, check height growth ... " bin/cita bebop stop node/3 > /dev/null timeout=$(check_height_growth_normal 0 15) || (echo "FAILED" echo "error msg: ${timeout}" @@ -55,7 +50,7 @@ timeout=$(check_height_growth_normal 0 15) || (echo "FAILED" echo "${timeout}s DONE" ################################################################################ -echo -n "6) stop node2, check height stopped ... " +echo -n "5) stop node2, check height stopped ... " bin/cita bebop stop node/2 > /dev/null timeout=$(check_height_stopped 0 27) || (echo "FAILED" echo "error msg: ${timeout}" @@ -63,7 +58,7 @@ timeout=$(check_height_stopped 0 27) || (echo "FAILED" echo "${timeout}s DONE" ################################################################################ -echo -n "7) start node2, check height growth ... " +echo -n "6) start node2, check height growth ... " bin/cita bebop start node/2 trace > /dev/null & timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" echo "error msg: ${timeout}" @@ -71,7 +66,7 @@ timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" echo "${timeout}s DONE" ################################################################################ -echo -n "8) start node3, check synch ... " +echo -n "7) start node3, check synch ... " node0_height=$(get_height 0) if [ $? -ne 0 ] ; then @@ -85,7 +80,7 @@ timeout=$(check_height_sync 3 0) || (echo "FAILED" echo "${timeout}s DONE" ################################################################################ -echo -n "9) stop all nodes, check height changed after restart ... " +echo -n "8) stop all nodes, check height changed after restart ... " before_height=$(get_height 0) if [ $? -ne 0 ] ; then echo "failed to get_height: ${before_height}" @@ -112,7 +107,7 @@ fi echo "${timeout}s DONE" ################################################################################ -echo -n "10) stop&clean node3, check height synch after restart ... " +echo -n "9) stop&clean node3, check height synch after restart ... " bin/cita bebop stop node/3 > /dev/null bin/cita bebop clean node/3 > /dev/null bin/cita bebop start node/3 trace > /dev/null & @@ -120,8 +115,3 @@ timeout=$(check_height_sync 3 0) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" - -################################################################################ -echo -n "11) cleanup ... " -cleanup -echo "DONE" diff --git a/tests/integrate_test/cita_bft_resend.sh b/tests/integrate_test/cita_bft_resend.sh index 544a533fc..88a1b8112 100755 --- a/tests/integrate_test/cita_bft_resend.sh +++ b/tests/integrate_test/cita_bft_resend.sh @@ -23,12 +23,7 @@ cd "${BINARY_DIR}" echo "DONE" ################################################################################ -echo "1) Clean Up ..." -cleanup "${CHAIN_NAME}" -echo "DONE" - -################################################################################ -echo "2) Generate CITA configurations ..." +echo "1) Generate CITA configurations ..." ${BINARY_DIR}/scripts/create_cita_config.py create \ --nodes "127.0.0.1:4000" \ --super_admin "${SUPER_ADMIN}" \ @@ -37,7 +32,7 @@ ${BINARY_DIR}/scripts/create_cita_config.py create \ echo "DONE" ################################################################################ -echo "3) Start CITA components manually" +echo "2) Start CITA components manually" ${BINARY_DIR}/bin/cita bebop setup ${CHAIN_NAME}/0 ${BINARY_DIR}/bin/cita bebop start ${CHAIN_NAME}/0 trace sleep 3 @@ -56,7 +51,7 @@ timeout=`check_height_growth_normal 0 $wait_timeout` || (echo "FAILED" exit 1) ################################################################################ -echo "4) Kill cita-executor and cita-chain, and rm -rf data/statedb" +echo "3) Kill cita-executor and cita-chain, and rm -rf data/statedb" jobs -l | grep cita-executor | awk '{print $2}' | xargs -I {} kill {} sleep 3 jobs -l | grep cita-chai | awk '{print $2}' | xargs -I {} kill {} @@ -64,7 +59,7 @@ rm -rf data/statedb sleep 10 ################################################################################ -echo "5) Restart CITA" +echo "4) Restart CITA" kill ${auth_pid} ${bft_pid} ${jsonrpc_pid} ${network_pid} cd ${BINARY_DIR} @@ -74,9 +69,3 @@ wait_timeout=30 timeout=`check_height_growth_normal 0 $wait_timeout` || (echo "FAILED" echo "error msg: ${timeout}" exit 1) - - -################################################################################ -echo "6) Cleanup" -cleanup "${CHAIN_NAME}" -echo "DONE" diff --git a/tests/integrate_test/cita_byzantinetest.sh b/tests/integrate_test/cita_byzantinetest.sh index bd87b8e52..14f85af70 100755 --- a/tests/integrate_test/cita_byzantinetest.sh +++ b/tests/integrate_test/cita_byzantinetest.sh @@ -20,14 +20,9 @@ echo -n "0) prepare ... " cd ${BINARY_DIR} echo "DONE" -################################################################################ -echo -n "1) cleanup ... " -cleanup -echo "DONE" - ################################################################################ -echo -n "2) generate config ... " +echo -n "1) generate config ... " ./scripts/create_cita_config.py create \ --chain_name "node" \ --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ @@ -37,7 +32,7 @@ echo -n "2) generate config ... " echo "DONE" ################################################################################ -echo -n "3) start nodes ... " +echo -n "2) start nodes ... " for i in {0..3} ; do bin/cita bebop setup node/$i > /dev/null done @@ -47,14 +42,14 @@ done echo "DONE" ################################################################################ -echo -n "4) check alive ... " +echo -n "3) check alive ... " timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" echo "failed to check_height_growth 0: ${timeout}" exit 1) echo "${timeout}s DONE" ################################################################################ -echo "5) set delay at one nodes, , output time used for produce block growth" +echo "4) set delay at one nodes, , output time used for produce block growth" delay=10000 for i in {0..3}; do id=$(($i%4)) @@ -74,7 +69,7 @@ for i in {0..3}; do done ################################################################################ -echo "6) set delay at two nodes, output time used for produce block" +echo "5) set delay at two nodes, output time used for produce block" delay=3000 for i in {0..3}; do id1=$i @@ -104,7 +99,7 @@ for i in {0..3}; do done ################################################################################ -echo "7) set delay at all nodes, output time used for produce block" +echo "6) set delay at all nodes, output time used for produce block" for i in {0..6}; do delay=$((i*400)) timeout=$(check_height_growth_normal 0 60) ||(echo "FAILED" @@ -123,10 +118,3 @@ for i in {0..6}; do sleep 4 echo "${timeout}s DONE" done - -echo "DONE" - -echo "11) cleanup" -cleanup -echo "DONE" -exit 0 diff --git a/tests/integrate_test/cita_charge_mode.sh b/tests/integrate_test/cita_charge_mode.sh index 8e887a740..8a50b414d 100755 --- a/tests/integrate_test/cita_charge_mode.sh +++ b/tests/integrate_test/cita_charge_mode.sh @@ -16,12 +16,7 @@ cd ${BINARY_DIR} echo "DONE" ################################################################################ -echo -n "1) cleanup ... " -cleanup -echo "DONE" - -################################################################################ -echo -n "2) generate config ... " +echo -n "1) generate config ... " ./scripts/create_cita_config.py \ create \ --chain_name "node" \ @@ -35,7 +30,7 @@ echo -n "2) generate config ... " echo "DONE" ################################################################################ -echo -n "3) start nodes ... " +echo -n "2) start nodes ... " for i in {0..3} ; do ./bin/cita bebop setup node/$i > /dev/null done @@ -45,21 +40,21 @@ done echo "DONE" ################################################################################ -echo -n "4) check alive ... " +echo -n "3) check alive ... " timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" echo "failed to check_height_growth 0: ${timeout}" exit 1) echo "${timeout}s DONE" ################################################################################ -echo -n "5) Run fee back tests ... " +echo -n "4) Run fee back tests ... " cd ./scripts/txtool/txtool python3 ${SOURCE_DIR}/tests/integrate_test/test_fee_back.py --version=0 cd ../../.. echo "DONE" ################################################################################ -echo -n "6) Run charge mode tests ... " +echo -n "5) Run charge mode tests ... " echo "" NODE_0_PRIVKEY=`cat ./node/0/privkey` @@ -78,28 +73,28 @@ cd ../../.. echo "DONE" ################################################################################ -echo -n "7) Update to chainIDV1 ... " +echo -n "6) Update to chainIDV1 ... " cd ./scripts/txtool/txtool python3 ${SOURCE_DIR}/tests/integrate_test/update_version.py --version=0 cd ../../.. echo "DONE" ################################################################################ -echo -n "8) check alive ... " +echo -n "7) check alive ... " timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" echo "failed to check_height_growth 0: ${timeout}" exit 1) echo "${timeout}s DONE" ################################################################################ -echo -n "9) Run fee back tests in v1 ... " +echo -n "8) Run fee back tests in v1 ... " cd ./scripts/txtool/txtool python3 ${SOURCE_DIR}/tests/integrate_test/test_fee_back.py --version=1 cd ../../.. echo "DONE" ################################################################################ -echo -n "10) Run charge mode tests in v1 ... " +echo -n "9) Run charge mode tests in v1 ... " echo "" NODE_0_PRIVKEY=`cat ./node/0/privkey` @@ -116,15 +111,3 @@ python3 ${SOURCE_DIR}/tests/integrate_test/test_charge_mode.py \ --version 1 cd ../../.. echo "DONE" - -################################################################################ -echo -n "11) stop nodes ... " -for i in {0..3} ; do - ./bin/cita bebop stop node/$i > /dev/null -done -echo "DONE" - -################################################################################ -echo -n "11) cleanup ... " -cleanup -echo "DONE" diff --git a/tests/integrate_test/cita_discovery.sh b/tests/integrate_test/cita_discovery.sh index cbcff0cc4..73db50095 100755 --- a/tests/integrate_test/cita_discovery.sh +++ b/tests/integrate_test/cita_discovery.sh @@ -356,20 +356,16 @@ main() { set_hosts echo "DONE" - echo -n "1) cleanup ... " - cleanup - echo "DONE" - - echo -n "2) generate config ... " + echo -n "1) generate config ... " generate_config echo "DONE" - echo -n "3) pre start nodes[0..3] ... " + echo -n "2) pre start nodes[0..3] ... " pre_start_nodes echo "DONE" # Pre-check peer count, it is OK to check node0 only - echo -n "4) pre-check peer count ... " + echo -n "3) pre-check peer count ... " timeout=$(check_peer_count 0 3 90)||(echo "FAILED" echo "error msg: ${timeout}" exit 1) @@ -402,11 +398,6 @@ main() { test_repeated_address test_max_connected_limit_as_client test_max_connected_limit_as_server - - echo -n "5) cleanup ... " - clean_host - cleanup - echo "DONE" } main "$@" diff --git a/tests/integrate_test/cita_jsonrpc_schema_mock.sh b/tests/integrate_test/cita_jsonrpc_schema_mock.sh index 937416f2b..2e8f683cc 100755 --- a/tests/integrate_test/cita_jsonrpc_schema_mock.sh +++ b/tests/integrate_test/cita_jsonrpc_schema_mock.sh @@ -23,12 +23,7 @@ cd ${BINARY_DIR} echo "DONE" ################################################################################ -echo -n "1) cleanup ... " -cleanup "mock-chain" -echo "DONE" - -################################################################################ -echo -n "2) generate config ... " +echo -n "1) generate config ... " if [ ! -d "resource" ]; then mkdir resource fi @@ -46,31 +41,26 @@ ${BINARY_DIR}/scripts/create_cita_config.py create --nodes "127.0.0.1:4000,127.0 echo "DONE" ################################################################################ -echo -n "3) just start mock-chain/0 ... " +echo -n "2) just start mock-chain/0 ... " ${BINARY_DIR}/bin/cita bebop setup mock-chain/0 > /dev/null ${BINARY_DIR}/bin/cita bebop start mock-chain/0 trace echo "DONE" ################################################################################ -echo -n "4) generate mock data ... " +echo -n "3) generate mock data ... " AMQP_URL=amqp://guest:guest@localhost/mock-chain/0 \ ${BINARY_DIR}/bin/chain-executor-mock \ -m ${SOURCE_DIR}/tests/interfaces/config/blockchain.yaml echo "DONE" ################################################################################ -echo -n "5) check mock data ... " +echo -n "4) check mock data ... " python3 ${SOURCE_DIR}/tests/interfaces/rpc_test_runner.py \ --rpc-url http://127.0.0.1:1337 \ --directory ${SOURCE_DIR}/tests/jsondata/rpc/ echo "DONE" ################################################################################ -echo -n "6) stop mock-chain/0 ... " +echo -n "5) stop mock-chain/0 ... " ${BINARY_DIR}/bin/cita bebop stop mock-chain/0 echo "DONE" - -################################################################################ -echo -n "7) cleanup ... " -cleanup "mock-chain" -echo "DONE" diff --git a/tests/integrate_test/cita_snapshot_test.sh b/tests/integrate_test/cita_snapshot_test.sh index 430a8c94e..02bde39df 100755 --- a/tests/integrate_test/cita_snapshot_test.sh +++ b/tests/integrate_test/cita_snapshot_test.sh @@ -23,12 +23,7 @@ cd "${BINARY_DIR}" echo "DONE" ################################################################################ -echo "1) Clean Up ..." -cleanup "${CHAIN_NAME}" -echo "DONE" - -################################################################################ -echo "2) Generate CITA configurations ..." +echo "1) Generate CITA configurations ..." ${BINARY_DIR}/scripts/create_cita_config.py create \ --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ --super_admin "${SUPER_ADMIN}" \ @@ -37,7 +32,7 @@ ${BINARY_DIR}/scripts/create_cita_config.py create \ echo "DONE" ################################################################################ -echo "3) Run node-0, node-1, node-2" +echo "2) Run node-0, node-1, node-2" for id in {0,1,2}; do ${BINARY_DIR}/bin/cita bebop setup ${CHAIN_NAME}/${id} > /dev/null done @@ -47,7 +42,7 @@ done echo "DONE" ################################################################################ -echo "4) Check all nodes grow up ..." +echo "3) Check all nodes grow up ..." for id in {0..2}; do echo "chech_height_growth_normal $id ..." timeout=`check_height_growth_normal $id 60`||(echo "FAILED" @@ -57,7 +52,7 @@ done echo "${timeout}s DONE" ################################################################################ -echo "5) Stop node-1 and node-2, so that node-0 cannot grow up via cita-consensus and cita-sync mechanisms" +echo "4) Stop node-1 and node-2, so that node-0 cannot grow up via cita-consensus and cita-sync mechanisms" ${BINARY_DIR}/bin/cita bebop stop ${CHAIN_NAME}/1 ${BINARY_DIR}/bin/cita bebop stop ${CHAIN_NAME}/2 @@ -67,7 +62,7 @@ sleep 3 echo "DONE" ################################################################################ -echo "6) Take snapshot on node-0 at height {0, 2, 100000} ..." +echo "5) Take snapshot on node-0 at height {0, 2, 100000} ..." for height in {0,2,10000}; do cd ${BINARY_DIR}/${CHAIN_NAME}/0 ${BINARY_DIR}/bin/snapshot_tool \ @@ -83,7 +78,7 @@ cd "${BINARY_DIR}" echo "DONE" ################################################################################ -echo "7) Restore snapshot on node-0 ..." +echo "6) Restore snapshot on node-0 ..." before_height=`get_height 0` for height in {10000,2,0,10000,2,0}; do cd ${BINARY_DIR}/${CHAIN_NAME}/0 @@ -113,7 +108,7 @@ cd "${BINARY_DIR}" echo "DONE" ################################################################################ -echo "8) Start node-1 and node-2 and check all grow up ..." +echo "7) Start node-1 and node-2 and check all grow up ..." ${BINARY_DIR}/bin/cita bebop start ${CHAIN_NAME}/1 trace ${BINARY_DIR}/bin/cita bebop start ${CHAIN_NAME}/2 trace @@ -125,12 +120,3 @@ timeout=`check_height_growth_normal 0 $wait_timeout` || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "DONE" - -################################################################################ -echo "9) Clean Up ..." -for id in {0,1,2}; do - ${BINARY_DIR}/bin/cita bebop stop ${CHAIN_NAME}/${id} -done - -cleanup -echo "DONE" diff --git a/tests/integrate_test/cita_tls_basic.sh b/tests/integrate_test/cita_tls_basic.sh index ba733da2a..5b41ca226 100755 --- a/tests/integrate_test/cita_tls_basic.sh +++ b/tests/integrate_test/cita_tls_basic.sh @@ -16,12 +16,7 @@ cd ${BINARY_DIR} echo "DONE" ################################################################################ -echo -n "1) cleanup ... " -cleanup -echo "DONE" - -################################################################################ -echo -n "2) generate config ... " +echo -n "1) generate config ... " ./scripts/create_cita_config.py create \ --chain_name "node" \ --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ @@ -31,7 +26,7 @@ echo -n "2) generate config ... " echo "DONE" ################################################################################ -echo -n "3) start nodes ... " +echo -n "2) start nodes ... " for i in {0..3} ; do bin/cita bebop setup node/$i > /dev/null done @@ -41,14 +36,14 @@ done echo "DONE" ################################################################################ -echo -n "4) check height growth normal ... " +echo -n "3) check height growth normal ... " timeout=$(check_height_growth_normal 0 60)||(echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" ################################################################################ -echo -n "5) stop node3, check height growth ... " +echo -n "4) stop node3, check height growth ... " bin/cita bebop stop node/3 > /dev/null timeout=$(check_height_growth_normal 0 15) || (echo "FAILED" echo "error msg: ${timeout}" @@ -56,7 +51,7 @@ timeout=$(check_height_growth_normal 0 15) || (echo "FAILED" echo "${timeout}s DONE" ################################################################################ -echo -n "6) stop node2, check height stopped ... " +echo -n "5) stop node2, check height stopped ... " bin/cita bebop stop node/2 > /dev/null timeout=$(check_height_stopped 0 27) || (echo "FAILED" echo "error msg: ${timeout}" @@ -64,7 +59,7 @@ timeout=$(check_height_stopped 0 27) || (echo "FAILED" echo "${timeout}s DONE" ################################################################################ -echo -n "7) start node2, check height growth ... " +echo -n "6) start node2, check height growth ... " bin/cita bebop start node/2 trace > /dev/null & sleep 24 #wait for recovery from stop timeout=$(check_height_growth_normal 0 15) || (echo "FAILED" @@ -73,7 +68,7 @@ timeout=$(check_height_growth_normal 0 15) || (echo "FAILED" echo "${timeout}s DONE" ################################################################################ -echo -n "8) start node3, check synch ... " +echo -n "7) start node3, check synch ... " node0_height=$(get_height 0) if [ $? -ne 0 ] ; then @@ -87,7 +82,7 @@ timeout=$(check_height_sync 3 0) || (echo "FAILED" echo "${timeout}s DONE" ################################################################################ -echo -n "9) stop all nodes, check height changed after restart ... " +echo -n "8) stop all nodes, check height changed after restart ... " before_height=$(get_height 0) if [ $? -ne 0 ] ; then echo "failed to get_height: ${before_height}" @@ -114,7 +109,7 @@ fi echo "${timeout}s DONE" ################################################################################ -echo -n "10) stop&clean node3, check height synch after restart ... " +echo -n "9) stop&clean node3, check height synch after restart ... " bin/cita bebop stop node/3 > /dev/null bin/cita bebop clean node/3 > /dev/null bin/cita bebop start node/3 trace > /dev/null & @@ -122,8 +117,3 @@ timeout=$(check_height_sync 3 0) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" - -################################################################################ -echo -n "11) cleanup ... " -cleanup -echo "DONE" From fbb84e5640c57192d6ce712ebda466aa0d3495ea Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Thu, 30 May 2019 10:15:03 +0800 Subject: [PATCH 21/91] fix import path --- scripts/contracts/src/role_management/RoleAuth.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/contracts/src/role_management/RoleAuth.sol b/scripts/contracts/src/role_management/RoleAuth.sol index 28fa6c4b6..2a25f11aa 100644 --- a/scripts/contracts/src/role_management/RoleAuth.sol +++ b/scripts/contracts/src/role_management/RoleAuth.sol @@ -4,7 +4,7 @@ import "./RoleCreator.sol"; import "../../interaction/interface/IAuthorization.sol"; import "../lib/ContractCheck.sol"; import "../lib/AddressArray.sol"; -import "../interaction/interface/IRoleAuth.sol"; +import "../../interaction/interface/IRoleAuth.sol"; /// @title Authorization about role and account /// @author ["Cryptape Technologies "] From 445746d7de85ccbfd95767b828e45f19fae861f8 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Thu, 30 May 2019 16:11:40 +0800 Subject: [PATCH 22/91] Remove uselsee shell script. --- tests/integrate_test/blockNumber.sh | 23 -- tests/integrate_test/cita_bft.sh | 272 ------------------ tests/integrate_test/cita_datasynctest.sh | 66 ----- tests/integrate_test/cita_start.sh | 56 ---- tests/integrate_test/cita_start_with_kafka.sh | 56 ---- tests/integrate_test/cita_stop.sh | 25 -- tests/integrate_test/cita_transactiontest.sh | 26 -- tests/integrate_test/getBlockByNumber.sh | 12 - tests/integrate_test/getTransaction.sh | 12 - tests/integrate_test/getTransactionReceipt.sh | 12 - tests/integrate_test/kafka_start.sh | 27 -- tests/integrate_test/kafka_stop.sh | 28 -- tests/integrate_test/peerCount.sh | 11 - 13 files changed, 626 deletions(-) delete mode 100755 tests/integrate_test/blockNumber.sh delete mode 100755 tests/integrate_test/cita_bft.sh delete mode 100755 tests/integrate_test/cita_datasynctest.sh delete mode 100755 tests/integrate_test/cita_start.sh delete mode 100755 tests/integrate_test/cita_start_with_kafka.sh delete mode 100755 tests/integrate_test/cita_stop.sh delete mode 100755 tests/integrate_test/cita_transactiontest.sh delete mode 100755 tests/integrate_test/getBlockByNumber.sh delete mode 100755 tests/integrate_test/getTransaction.sh delete mode 100755 tests/integrate_test/getTransactionReceipt.sh delete mode 100755 tests/integrate_test/kafka_start.sh delete mode 100755 tests/integrate_test/kafka_stop.sh delete mode 100755 tests/integrate_test/peerCount.sh diff --git a/tests/integrate_test/blockNumber.sh b/tests/integrate_test/blockNumber.sh deleted file mode 100755 index ef6c9f0bf..000000000 --- a/tests/integrate_test/blockNumber.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -set -e -#echo "args: ip port" -IP=$1 -PORT=$2 -if [ ! -n "$IP" ]; then - IP="127.0.0.1" -fi -if [ ! -n "$PORT" ]; then - PORT=1337 -fi -response=$(curl -s -X POST -d '{"jsonrpc":"2.0","method":"blockNumber","params":[],"id":2}' $IP:$PORT) -if [ $? -ne 0 ]; then - exit 1 -fi - -height=$(echo ${response}|jq ".result"|sed 's/\"//g') - -if [ "$height" == null ]; then - exit 1 -fi - -echo $((height)) diff --git a/tests/integrate_test/cita_bft.sh b/tests/integrate_test/cita_bft.sh deleted file mode 100755 index e9c114a7d..000000000 --- a/tests/integrate_test/cita_bft.sh +++ /dev/null @@ -1,272 +0,0 @@ -#!/bin/bash -set +e -tx_num=0 -pid=0 -CUR_PATH=$(cd `dirname $0`; pwd) -sudo rabbitmqctl stop_app -sudo rabbitmqctl reset -sudo rabbitmqctl start_app -cd ${CUR_PATH}/../../admintool/ -./scripts/create_cita_config.py create \ - --chain_name "node" \ - --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ - --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" - -setup_node() { - id=$1 - cd ${CUR_PATH}/../../admintool/release/node/${id} - ./cita setup ${id} -} - -start_node() { - id=$1 - cd ${CUR_PATH}/../../admintool/release/node/${id} - ./cita start ${id} -} - -stop_node() { - id=$1 - cd ${CUR_PATH}/../../admintool/release/node/${id} - ./cita stop ${id} -} - -stop_all () { - stop_node 0 - stop_node 1 - stop_node 2 - stop_node 3 - stop_consensus 3 -} - -delete_pid_file() -{ - id=$1 - cd ${CUR_PATH}/../../admintool/release/node/${id} - if [ -f "consensus_cita_bft.pid" ]; then - rm -rf consensus_cita_bft.pid - fi -} - -stop_consensus_cmd() -{ - id=$1 - cd ${CUR_PATH}/../../admintool/release/node/${id} - - if [ ! -f "consensus_cita_bft.pid" ]; then - consensus_cita_bft_pid=$(tail -3 .pid | head -1) -# kill -9 $consensus_cita_bft_pid - else - consensus_cita_bft_pid=$(cat consensus_cita_bft.pid) -# kill -9 $consensus_cita_bft_pid - rm -rf consensus_cita_bft.pid - fi - - flag=$(ps -ef | grep $consensus_cita_bft_pid | grep -v grep | wc -l) - if [ $flag -gt 0 ]; then - kill -9 $consensus_cita_bft_pid - fi -} - -stop_consensus() -{ -# killall consensus_cita_bft - for((i=0; i<=$1;i++)) - do - stop_consensus_cmd $i - done -} - -start_consensus_cmd() -{ - id=$1 - cd ${CUR_PATH}/../../admintool/release/node/${id} - RUST_LOG=consensus_cita_bft bin/consensus_cita_bft -c consensus.json >log/node/${id}.consensus 2>&1 & - echo $! > consensus_cita_bft.pid -} - -start_consensus() -{ - while : - do - process=$(ps -ef | grep "bin/consensus_cita_bft" | grep -v grep | wc -l) - if [ $process -lt 4 ]; then - break - fi - done - for((i=0; i<=$1;i++)) - do - start_consensus_cmd $i - sleep 1 - done -} - -start_all () { - start_node 0 - start_node 1 - start_node 2 - start_node 3 -} - -get_height(){ - h=`${CUR_PATH}/blockNumber.sh` - h=$(echo $h | sed 's/\"//g') - echo $((h)) -} - -check_height_change () { - echo "check block height" - old_height=$(get_height) - echo "block height $old_height" - sleep 30 - new_height=$(get_height) - echo "block height $new_height" - if [ $new_height -eq $old_height ]; then - stop_all - exit 1 - fi -} - -delete_log() -{ - cd ${CUR_PATH}/../wrk_benchmark_test/ - if [ -f "result.log" ]; then - rm -rf result.log - fi -} - -delete_tc() -{ - flag=$(tc -s qdisc show dev lo | grep "qdisc prio" | wc -l) - if [ $flag -eq 1 ]; then - sudo tc qdisc del dev lo root - fi -} - -stop_trans() -{ - flag=$(ps -ef | grep benchmark.sh | grep -v grep | wc -l) - if [ $flag -eq 1 ]; then - killall benchmark.sh - fi - flag=$(ps -ef | grep make_transaction | grep -v grep | wc -l) - if [ $flag -eq 1 ]; then - killall make_transaction - fi -} - -start_send_tx() -{ - stop_trans - cd ${CUR_PATH}/../wrk_benchmark_test/ -# if [ ! -f "result.log" ]; then - if [ $1 -eq 0 ]; then - ./benchmark.sh - err=`echo $?` - if [ $err -ne 0 ]; then - echo "create account error!" - delete_tc - stop_all - #stop_consensus - stop_trans - exit 1 - fi - fi - - sleep 10 - - #./setPortDelay.sh 4000 1000 10 > /dev/null & - pid=$! - ./benchmark.sh config_call.json 2 > result.log & - while : - do - - if [ ! -f "result.log" ]; then - continue - fi - flag=$(grep "write successfully\.\[" result.log | wc -l) - err=`echo $?` - if [ $err -ne 0 ]; then - continue - fi - - if [ $flag -eq 1 ]; then - #stop_consensus - stop_consensus $2 - sleep 2 - break - fi - done -} - -send_tx_over() -{ - cd ${CUR_PATH}/../wrk_benchmark_test/ - while : - do - if [ ! -f "result.log" ]; then - continue - fi - - flag=$(grep "send tx num" result.log | wc -l) - err=`echo $?` - if [ $err -ne 0 ]; then - continue - fi - if [ $flag -eq 1 ]; then - tx_num=$(grep "write successfully\.\[" result.log | grep -o "[[:digit:]]*") - flag=$(grep "send tx num" result.log | grep "$tx_num" | wc -l) - if [ $flag -eq 0 ]; then - echo "###send_tx_over exit [$tx_num]" - delete_tc - stop_all - stop_trans - exit 1 - fi - break - fi - done -} - - -echo "###start nodes..." -(setup_node 0;start_node 0) & -(setup_node 1;start_node 1) & -(setup_node 2;start_node 2) & -(setup_node 3;start_node 3) & - -echo "###wait for start..." -sleep 80 - -check_height_change - -stop_num=0 - -echo "###start_test_consensus_cita_bft" -delete_pid_file 0 -delete_pid_file 1 -delete_pid_file 2 -delete_pid_file 3 -run=0 -while : -do - if [ $stop_num -gt 3 ]; then - break - fi - sleep 30 - echo "###start consensus_cita_bft process $stop_num" - delete_log - start_send_tx $run $stop_num & - start_consensus $stop_num & - send_tx_over - run=1 - echo "###end consensus_cita_bft process $stop_num" - stop_num=$[$stop_num+1] -done - -delete_tc -sleep 30 -check_height_change -stop_all -stop_trans -echo "###Test OK" -exit 0 diff --git a/tests/integrate_test/cita_datasynctest.sh b/tests/integrate_test/cita_datasynctest.sh deleted file mode 100755 index 6383dbb7d..000000000 --- a/tests/integrate_test/cita_datasynctest.sh +++ /dev/null @@ -1,66 +0,0 @@ -#!/bin/bash - -stop_node3() { - cd ${CUR_PATH}/../../admintool/release/node3 - ./cita stop 3 -} - -start_node3() { - cd ${CUR_PATH}/../../admintool/release/node3 - ./cita start 3 & -} - -get_height(){ - nodeid=$1 - if [ ! -n "$nodeid" ]; then - nodeid=0 - fi - h=`${CUR_PATH}/blockNumber.sh 127.0.0.1 $((1337+${nodeid}))` - h=$(echo $h | sed 's/\"//g') - echo $((h)) -} - -COUNT=$1 -if [ ! -n "$COUNT" ]; then - COUNT=100 -fi - -CUR_PATH=$(cd `dirname $0`; pwd) - -${CUR_PATH}/cita_start.sh - -stop_node3 -echo "###Stop node3" - -height=$(get_height) -hi=$[height+COUNT] - -echo "current height:$height" -echo "aim height:$hi" - -while [ $height -le $hi ] -do - height=$(get_height) - sleep 3 -done - - -echo "###start node3" -start_node3 - -start=$(date +%s) - -num_3=$(get_height 3) - -while(($num_3<$hi)) -do - num_3=$(get_height 3) -done - -end=$(date +%s) - -time=$((end - start)) - -echo "Syn $COUNT block spent time:$time" - -${CUR_PATH}/cita_stop.sh diff --git a/tests/integrate_test/cita_start.sh b/tests/integrate_test/cita_start.sh deleted file mode 100755 index c723cca75..000000000 --- a/tests/integrate_test/cita_start.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -#usage: start demo nodes -# ./cita_start.sh -# ./cita_start.sh [error,info, warn, debug, trace] [cita-bft] - -set +e - -debug=$1 -consensus=$2 - -if [[ `uname` == 'Darwin' ]] -then - SOURCE_DIR=$(realpath $(dirname $0)/../..) -else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) -fi -BINARY_DIR=${SOURCE_DIR}/target/install -. ${SOURCE_DIR}/tests/integrate_test/util.sh - -if [ ! -n "$consensus" ]; then - consensus="cita-bft" -fi - -echo "###cleanup" -cleanup - -echo "###generate config files" -cd ${BINARY_DIR} -./scripts/create_cita_config.py create \ - --chain_name "node" \ - --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ - --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" >/dev/null 2>&1 - - -echo "###start nodes" -for i in {0..3} ; do - setup_node $i -done - -for i in {0..3} ; do - start_node $i & -done - -echo -n "###check height growth" -msg=$(check_height_growth 0 60)|| (echo "FAILED" - echo "check height growth: ${msg}" - exit 1) -echo "###CITA start OK" - -cita_pid=`cat ${BINARY_DIR}/node/0/.cita-forever.pid` -pid_file="/proc/${cita_pid}/cmdline" - -while [ -e ${pid_file} ];do - sleep 3; -done - diff --git a/tests/integrate_test/cita_start_with_kafka.sh b/tests/integrate_test/cita_start_with_kafka.sh deleted file mode 100755 index 7f8b161d6..000000000 --- a/tests/integrate_test/cita_start_with_kafka.sh +++ /dev/null @@ -1,56 +0,0 @@ -#!/bin/bash -#usage: start demo nodes -# ./cita_start_with_kafka.sh -# ./cita_start_with_kafka.sh [error,info, warn, debug, trace] - -set +e - -debug=$1 -consensus=$2 - -if [[ `uname` == 'Darwin' ]] -then - SOURCE_DIR=$(realpath $(dirname $0)/../..) -else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) -fi -BINARY_DIR=${SOURCE_DIR}/target/install -. ${SOURCE_DIR}/tests/integrate_test/util.sh - -if [ ! -n "$consensus" ]; then - consensus="cita-bft" -fi - -echo "###cleanup" -cleanup - -echo "###generate config files" -cd ${BINARY_DIR} -./scripts/create_cita_config.py create \ - --chain_name "node" \ - --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ - --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" >/dev/null 2>&1 - -echo "###wait for kafka start" -$SOURCE_DIR/tests/integrate_test/kafka_start.sh ${BINARY_DIR} -if [ "$?" -ne "0" ]; then - exit 1 -fi -sleep 5 - -echo "###start nodes" -for i in {0..3} ; do - setup_node $i -done - -for i in {0..3} ; do - start_node $i & -done - -echo -n "###check height growth" -msg=$(check_height_growth 0)|| (echo "FAILED" - echo "check height growth: ${msg}" - exit 1) -echo "###CITA start OK" -exit 0 - diff --git a/tests/integrate_test/cita_stop.sh b/tests/integrate_test/cita_stop.sh deleted file mode 100755 index 14c4d24a2..000000000 --- a/tests/integrate_test/cita_stop.sh +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/bash -set -e -kafka=$1 -if [[ `uname` == 'Darwin' ]] -then - SOURCE_DIR=$(realpath $(dirname $0)/../..) -else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) -fi -BINARY_DIR=${SOURCE_DIR}/target/install - -. ${SOURCE_DIR}/tests/integrate_test/util.sh -cd ${BINARY_DIR} - -date -echo "###Stop CITA " -stop_all -if [ "$kafka" == "kafka" ]; then - echo "###Stop kafka" - $SOURCE_DIR/tests/integrate_test/kafka_stop.sh $BINARY_DIR -fi -date - -exit 0 - diff --git a/tests/integrate_test/cita_transactiontest.sh b/tests/integrate_test/cita_transactiontest.sh deleted file mode 100755 index 19fdafd77..000000000 --- a/tests/integrate_test/cita_transactiontest.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -set +e - - -if [[ `uname` == 'Darwin' ]] -then - SOURCE_DIR=$(realpath $(dirname $0)/../..) -else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) -fi -BINARY_DIR=${SOURCE_DIR}/target/install - -. ${SOURCE_DIR}/tests/integrate_test/util.sh -${SOURCE_DIR}/tests/integrate_test/cita_start.sh & - -cd ${SOURCE_DIR}/tests/wrk_benchmark_test/ -./benchmark.sh -sleep 10 -./benchmark.sh config_call.json - -check_height_growth 0 60 - -${SOURCE_DIR}/tests/integrate_test/cita_stop.sh -echo "###Test OK" -exit 0 - diff --git a/tests/integrate_test/getBlockByNumber.sh b/tests/integrate_test/getBlockByNumber.sh deleted file mode 100755 index 5e2f7dc49..000000000 --- a/tests/integrate_test/getBlockByNumber.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -if [ $# == 1 ]; then - HEIGHT=$1 - IP="127.0.0.1"; -elif [ $# == 2 ]; then - HEIGHT=$1 - IP=$2; -else - echo "args: height ip (default localhost) " - exit -fi -curl -s -X POST -d '{"jsonrpc":"2.0","method":"getBlockByNumber","params":["'$HEIGHT'",false],"id":2}' $IP:1337 diff --git a/tests/integrate_test/getTransaction.sh b/tests/integrate_test/getTransaction.sh deleted file mode 100755 index 011c3ded6..000000000 --- a/tests/integrate_test/getTransaction.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -if [ $# == 1 ]; then - HASH=$1 - IP="127.0.0.1"; -elif [ $# == 2 ]; then - HASH=$1 - IP=$2; -else - echo "args: hash ip (default localhost) " - exit -fi -curl -s -X POST -d '{"jsonrpc":"2.0","method":"getTransaction","params":['\"$HASH\"'],"id":2}' $IP:1337 diff --git a/tests/integrate_test/getTransactionReceipt.sh b/tests/integrate_test/getTransactionReceipt.sh deleted file mode 100755 index 22d370124..000000000 --- a/tests/integrate_test/getTransactionReceipt.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/bash -if [ $# == 1 ]; then - HASH=$1 - IP="127.0.0.1"; -elif [ $# == 2 ]; then - HASH=$1 - IP=$2; -else - echo "args: hash ip (default localhost) " - exit -fi -curl -s -X POST -d '{"jsonrpc":"2.0","method":"getTransactionReceipt","params":['\"$HASH\"'],"id":2}' $IP:1337 diff --git a/tests/integrate_test/kafka_start.sh b/tests/integrate_test/kafka_start.sh deleted file mode 100755 index 2408b5c6e..000000000 --- a/tests/integrate_test/kafka_start.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash - -if [ $# -ne 1 ]; then - echo "usage: $0 INSTALL_PATH" - exit 1 -fi - -if [ -z "$KAFKA_HOME" ]; then - echo "Please set KAFKA_HOME environment var first" - exit 1 -fi - -install_path=$1 -kafka_pid=.kafka_pid -for i in {0..3} ; do - node_path=$install_path/node$i - nohup $KAFKA_HOME/bin/zookeeper-server-start.sh $node_path/zookeeper.properties > /tmp/zookeeper$i.log 2>&1 & - echo $! >> $node_path/$kafka_pid -done - -sleep 5 - -for i in {0..3}; do - node_path=$install_path/node$i - nohup $KAFKA_HOME/bin/kafka-server-start.sh $node_path/kafka.properties > /tmp/kafka$i.log 2>&1 & - echo $! >> $node_path/$kafka_pid -done diff --git a/tests/integrate_test/kafka_stop.sh b/tests/integrate_test/kafka_stop.sh deleted file mode 100755 index 9ec6bf560..000000000 --- a/tests/integrate_test/kafka_stop.sh +++ /dev/null @@ -1,28 +0,0 @@ -#!/bin/bash - -if [ $# -ne 1 ]; then - echo "usage: $0 INSTALL_PATH" - exit 1 -fi - -install_path=$1 -kafka_pid=.kafka_pid - -stop_kafka() { - id=$1 - file=$install_path/node$id/$kafka_pid - if [ -e $file ]; then - for pid in $(cat $file); do - kill -9 $pid || true - done - rm -f $file - fi -} - -stop_all_kafka() { - for id in {0..3}; do - stop_kafka $id - done -} - -stop_all_kafka diff --git a/tests/integrate_test/peerCount.sh b/tests/integrate_test/peerCount.sh deleted file mode 100755 index b4c301977..000000000 --- a/tests/integrate_test/peerCount.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash - -IP=$1 -PORT=$2 -if [ ! -n "$IP" ]; then - IP="127.0.0.1" -fi -if [ ! -n "$PORT" ]; then - PORT=1337 -fi -curl -s -X POST -d '{"jsonrpc":"2.0","method":"peerCount","params":[],"id":2}' $IP:$PORT | jq ".result" \ No newline at end of file From 6020a678b654a96b6d94d0eceae65eca3273bf25 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Thu, 30 May 2019 15:56:16 +0800 Subject: [PATCH 23/91] Chore about util: shellcheck and refactor. --- tests/integrate_test/util.sh | 415 +++++++++++++++++------------------ 1 file changed, 204 insertions(+), 211 deletions(-) diff --git a/tests/integrate_test/util.sh b/tests/integrate_test/util.sh index 644206568..caf18e1fb 100644 --- a/tests/integrate_test/util.sh +++ b/tests/integrate_test/util.sh @@ -1,45 +1,27 @@ +#!/bin/bash -sudo(){ +sudo() { set -o noglob if [ "$(whoami)" == "root" ] ; then - $* + "$@" else - /usr/bin/sudo $* + /usr/bin/sudo "$@" fi set +o noglob } -# Clean up only when it successes -cleanup() { - for pid in cita-forever cita-jsonrpc cita-auth cita-chain cita-network cita-bft trans_evm cita-executor; do - ps ax | grep ${pid} | grep -v grep | awk '{print $1}' | xargs -n 1 -I % kill -9 % 2>&1 >/dev/null ||true - done - - rm -rf ${BINARY_DIR}/${1:-node}* - rm -rf ${BINARY_DIR}/*.json - sudo tc qdisc del dev lo root> /dev/null 2>&1||true +get_height() { + local id=$1 + local timeout=$2 - pid_file=/tmp/cita_basic-trans_evm.pid - if [ -e ${pid_file} ] ; then - for pid in $(cat ${pid_file}) ; do - kill -9 ${pid} 2>&1 > /dev/null || true - done + if [ ! -n "$timeout" ]; then + timeout=30 fi -} -get_height(){ - if [ $# -ne 1 ] ; then - echo "usage: $0 node_id" - return 1 - fi - id=$1 - timeout=60 # 60 seconds start=$(date +%s) - - while [ 1 ] ; do - height=$(${SOURCE_DIR}/tests/integrate_test/blockNumber.sh 127.0.0.1 $((1337+${id}))) - if [ $? -eq 0 ] ; then - echo ${height} + while true; do + if height=$(blockNumber 127.0.0.1 $((1337+"${id}"))); then + echo "${height}" return 0 fi @@ -50,25 +32,24 @@ get_height(){ fi sleep 1 done - return 1 } -get_peer_count(){ - if [ $# -ne 1 ] ; then - echo "usage: $0 node_id" - return 1 +get_peer_count() { + local id=$1 + local timeout=$2 + local peer_count + local start + local now + + if [ ! -n "$timeout" ]; then + timeout=30 fi - id=$1 - timeout=60 # 60 seconds - start=$(date +%s) - while [ 1 ] ; do - peer_count=$(${SOURCE_DIR}/tests/integrate_test/peerCount.sh 127.0.0.1 $((1337+${id}))) - if [ $? -eq 0 ] ; then - # Remove quotes - peer_count_str=`echo ${peer_count} | sed 's/\"//g'` + start=$(date +%s) - echo ${peer_count_str} + while true; do + if peer_count=$(peerCount 127.0.0.1 $((1337+"${id}"))); then + echo "${peer_count}" return 0 fi @@ -79,210 +60,188 @@ get_peer_count(){ fi sleep 1 done - return 1 } -# output information about time used if exit 0 -check_height_growth () { +check_height_growth() { if [ $# -ne 2 ] ; then - echo "usage: $0 node_id timeout" + echo "usage: $0 node_id old_height" return 1 fi - id=$1 - timeout=$2 # seconds - old=$(get_height ${id}) - if [[ $? -ne 0 ]]; then - echo "failed to get_height(old): ${old}" - return 1 - fi - start=$(date +%s) - while [ 1 ] ; do - new=$(get_height ${id}) - if [[ $? -ne 0 ]] ; then - echo "failed to get_height! old height: ${old} new height: ${new}" - return 1 - fi - - now=$(date +%s) - if [ ${new} -gt $(($old + 2)) ]; then - echo "$((now-start))" + local id=$1 + local old=$2 + local new + if new=$(get_height "${id}"); then + echo "new height: ${new}" + if [ "${new}" -gt "${old}" ]; then + echo "height growth" return 0 fi - if [ $((now-start)) -gt ${timeout} ] ; then - echo "time used: $((now-start)) old height: ${old} new height: ${new}" - return 20 - fi - sleep 1 - done + echo "height not growth" + fi return 1 } # output information about time used if exit 0 -check_peer_count () { +check_peer_count() { if [ $# -ne 3 ] ; then echo "usage: $0 node_id expected_count timeout" return 1 fi - id=$1 - expected_count=$2 - timeout=$3 # seconds + local id=$1 + local expected_count=$2 + local timeout=$3 + local start + local peer_count + local now - if [[ $? -ne 0 ]]; then - echo "failed to get_height(old): ${old}" - return 1 - fi start=$(date +%s) - while [ 1 ] ; do - peer_count=$(get_peer_count ${id}) - if [[ $? -ne 0 ]] ; then - echo "failed to get_peer_count! node id: ${id} expected count: ${expected_count}" - return 1 + while true; do + if peer_count=$(get_peer_count "${id}" "${timeout}"); then + if [ $((peer_count)) -eq $((expected_count)) ]; then + echo "$((now-start))" + return 0 + fi fi - now=$(date +%s) - if [ $((peer_count)) -eq $((expected_count)) ]; then - echo "$((now-start))" - return 0 - fi - if [ $((now-start)) -gt ${timeout} ] ; then - echo "time used: $((now-start)) get peer count: ${peer_count} expected count: ${expected_count}" + if [ $((now-start)) -gt "${timeout}" ] ; then + echo "time used: $((now-start)) \ + get peer count: ${peer_count} \ + expected count: ${expected_count}" return 1 fi sleep 1 done - return 1 } # output information about time used if exit 0 -check_peer_count_max () { +check_peer_count_max() { if [ $# -ne 3 ] ; then echo "usage: $0 node_id expected_count timeout" return 1 fi - id=$1 - max_count=$2 - timeout=$3 # seconds + local id=$1 + local max_count=$2 + local timeout=$3 + local start + local peer_count + local now - if [[ $? -ne 0 ]]; then - echo "failed to get_height(old): ${old}" - return 1 - fi start=$(date +%s) - while [ 1 ] ; do - peer_count=$(get_peer_count ${id}) - if [[ $? -ne 0 ]] ; then - echo "failed to get_peer_count! node id: ${id} expected count: ${expected_count}" - return 1 + while true; do + if peer_count=$(get_peer_count "${id}" "${timeout}"); then + if [ $((peer_count)) -le $((max_count)) ]; then + echo "$((now-start))" + return 0 + fi fi - now=$(date +%s) - if [ $((peer_count)) -le $((max_count)) ]; then - echo "$((now-start))" - return 0 - fi - if [ $((now-start)) -gt ${timeout} ] ; then - echo "time used: $((now-start)) get peer count: ${peer_count} expected count: ${expected_count}" + if [ $((now-start)) -gt "${timeout}" ] ; then + echo "time used: $((now-start)) \ + get peer count: ${peer_count} \ + expected count: ${expected_count}" return 1 fi sleep 1 done - return 1 } -check_height_growth_normal () { +check_height_growth_normal() { if [ $# -ne 2 ] ; then echo "usage: $0 id timeout" return 1 fi - id=$1 - timeout=$2 - start=$(date +%s) - for i in {0..1}; do - msg=$(check_height_growth ${id} ${timeout}) - if [ $? -ne 0 ] ; then - echo "check_height_growth_normal failed id(${id}) timeout(${timeout}) msg(${msg})" - return 1 - fi - if [[ ${msg} -lt ${timeout} ]]; then + local id=$1 + local timeout=$2 + local old + local now + + if old=$(get_height "${id}"); then + echo "old height: ${old}" + start=$(date +%s) + while true; do + if check_height_growth "${id}" "${old}"; then + echo "height gorwth normal id(${id})" + return 0 + fi now=$(date +%s) - echo "$((now-start))" - return 0 - fi - done - echo "check_height_growth_normal timeout(${timeout}) msg(${msg})" + if [ $((now-start)) -gt "${timeout}" ] ; then + echo "check_height_growth_normal failed id(${id}) timeout(${timeout})" + return 1 + fi + sleep 1 + done + fi + echo "failed to get old height" return 1 } # output information about time used if exit 0 -check_height_sync () { +check_height_sync() { if [ $# -ne 2 ] ; then echo "usage: $0 node_id refer_node_id" return 1 fi - id=$1 - refer=$2 - timeout=180 # seconds - refer_height=$(get_height ${refer}) - if [ $? -ne 0 ] ; then - echo "check_height_sync failed to get_height(refer): ${refer_height}" - return 1 + local id=$1 + local refer=$2 + local timeout=180 + local refer_height + local now + local height + + if refer_height=$(get_height "${refer}"); then + start=$(date +%s) + while true; do + now=$(date +%s) + if [ $((now-start)) -gt ${timeout} ] ; then + echo "check_height_sync timeout(${timeout}) \ + time used $((now-start)) \ + refer height ${refer_height} \ + sync height ${height}" + return 1 + fi + if height=$(get_height "${id}"); then + if [ "${height}" -gt "${refer_height}" ]; then + echo "$((now-start))" + return 0 + fi + fi + done fi - start=$(date +%s) - - while [ 1 ] ; do - height=$(get_height ${id}) - if [ $? -ne 0 ] ; then - echo "check_height_sync failed to get_height(sync): ${height}" - return 1 - fi - now=$(date +%s) - if [ ${height} -gt ${refer_height} ]; then - echo "$((now-start))" - return 0 - fi - - if [ $((now-start)) -gt ${timeout} ] ; then - echo "check_height_sync timeout(${timeout}) time used $((now-start)) refer height ${refer_height} sync height ${height}" - return 1 - fi - sleep 1 - done + echo "check_height_sync failed to get_height(refer): ${refer_height}" return 1 } -check_height_stopped () { +check_height_stopped() { if [ $# -ne 2 ] ; then echo "usage: $0 node_id timeout" return 1 fi - id=$1 - timeout=$2 - old=$(get_height ${id}) - if [ $? -ne 0 ] ; then - echo "check_height_stopped failed to get_height(old): ${old}" - return 1 + local id=$1 + local timeout=$2 + local old + local now + local new + + if old=$(get_height "${id}"); then + start=$(date +%s) + while true; do + now=$(date +%s) + if [ $((now-start)) -gt "${timeout}" ] ; then + echo "$((now-start))" + return 0 + fi + if new=$(get_height "${id}"); then + if [ "$new" -gt "$old" ]; then + echo "check_height_stopped height change from ${old} to ${new}" + return 1 + fi + sleep 1 + continue + fi + done fi - - start=$(date +%s) - while [ 1 ] ; do - now=$(date +%s) - if [ $((now-start)) -gt ${timeout} ] ; then - echo "$((now-start))" - return 0 - fi - new=$(get_height ${id}) - if [ $? -ne 0 ] ; then - echo "check_height_stopped failed to get_height(new): ${new}" - return 1 - fi - if [ $new -gt $(($old + 2)) ]; then - # if two more blocks was generated, it shows cita still reach consensus. - echo "check_height_stopped height change from ${old} to ${new}" - return 1 - fi - sleep 1 - done + echo "check_height_stopped failed to get_height(old): ${old}" return 1 } @@ -291,48 +250,82 @@ set_delay_at_port() { echo "usage: set_delay_at_port port delay" return 1 fi - port=$1 - delay=$2 + local port=$1 + local delay=$2 + # TODO: need more description sudo tc qdisc add dev lo root handle 1: prio bands 4 >/dev/null 2>&1 || true - sudo tc qdisc add dev lo parent 1:4 handle 40: netem delay ${delay}ms >/dev/null 2>&1 || true - sudo tc filter add dev lo protocol ip parent 1:0 prio 4 u32 match ip dport ${port} 0xffff flowid 1:4 >/dev/null 2>&1 || true + sudo tc qdisc add dev lo parent 1:4 handle 40: netem delay "${delay}"ms >/dev/null 2>&1 || true + sudo tc filter add dev lo protocol ip parent 1:0 prio 4 u32 match ip dport "${port}" 0xffff flowid 1:4 >/dev/null 2>&1 || true } + unset_delay_at_port() { if [ $# -ne 1 ] ; then echo "usage: $0 port" return 1 fi - port=$1 + local port=$1 #sudo tc filter del dev lo protocol ip parent 1:0 prio 4 u32 match ip dport ${port} 0xffff flowid 1:4 >/dev/null 2>&1 || true sudo tc qdisc del dev lo root> /dev/null 2>&1||true } -setup_node() { - id=$1 - ./bin/cita setup node/${id} -} +blockNumber() { + local ip=$1 + local port=$2 + local response + local height -start_node() { - id=$1 - ./bin/cita start node/${id} ${debug} + if [ ! -n "$ip" ]; then + ip="127.0.0.1" + fi + if [ ! -n "$port" ]; then + port=1337 + fi + if response=$(curl -s -X POST -d '{"jsonrpc":"2.0","method":"blockNumber","params":[],"id":2}' $ip:$port); then + height=$(echo "${response}" |jq ".result"|sed 's/\"//g') + if [ "$height" == null ]; then + exit 1 + fi + echo $((height)) + return 0 + fi + echo "failed to get glock number" + return 1 } -stop_node() { - id=$1 - ./bin/cita stop node/${id} -} +peerCount() { + local ip=$1 + local port=$2 + local response + local count -stop_all () { - stop_node 0 - stop_node 1 - stop_node 2 - stop_node 3 + if [ ! -n "$ip" ]; then + ip="127.0.0.1" + fi + if [ ! -n "$port" ]; then + port=1337 + fi + if response=$(curl -s -X POST -d '{"jsonrpc":"2.0","method":"peerCount","params":[],"id":2}' $ip:$port); then + count=$(echo "${response}" |jq ".result"|sed 's/\"//g') + if [ "$count" == null ]; then + exit 1 + fi + echo $((count)) + return 0 + fi + echo "failed to get peer count" + return 1 } -start_all () { - start_node 0 - start_node 1 - start_node 2 - start_node 3 +start_nodes() { + local num=$1 + if [ ! -n "$num" ]; then + num=4 + fi + for ((i=0; i /dev/null + done + for ((i=0; i /dev/null + done } From ac151659e78967e1d0550915e17fd3152d74f1c5 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Fri, 31 May 2019 16:45:44 +0800 Subject: [PATCH 24/91] Refactor cita basic test: tls as a param. [skip travis] --- .circleci/config.yml | 2 +- tests/integrate_test/cita_basic.sh | 186 +++++++++++-------------- tests/integrate_test/cita_tls_basic.sh | 119 ---------------- 3 files changed, 84 insertions(+), 223 deletions(-) delete mode 100755 tests/integrate_test/cita_tls_basic.sh diff --git a/.circleci/config.yml b/.circleci/config.yml index 88ad801c8..2e1fb2e5e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -238,7 +238,7 @@ jobs: - run: *after-restore-release-cache - run: name: Basic Tls Test - command: ./tests/integrate_test/cita_tls_basic.sh + command: ./tests/integrate_test/cita_basic.sh enable_tls "JSON-RPC Mock Test in Charge Mode": <<: *job-default diff --git a/tests/integrate_test/cita_basic.sh b/tests/integrate_test/cita_basic.sh index 316ecda32..b73e2e504 100755 --- a/tests/integrate_test/cita_basic.sh +++ b/tests/integrate_test/cita_basic.sh @@ -1,117 +1,97 @@ #!/bin/bash -set -e -if [[ `uname` == 'Darwin' ]] -then - SOURCE_DIR=$(realpath $(dirname $0)/../..) -else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) -fi -BINARY_DIR=${SOURCE_DIR}/target/install +main() { + set -e + if [[ $(uname) == 'Darwin' ]] + then + SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) + else + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) + fi + BINARY_DIR=${SOURCE_DIR}/target/install -################################################################################ -echo -n "0) prepare ... " -. ${SOURCE_DIR}/tests/integrate_test/util.sh -cd ${BINARY_DIR} -echo "DONE" + echo -n "0) prepare ... " + # shellcheck source=/dev/null + . "${SOURCE_DIR}"/tests/integrate_test/util.sh + cd "${BINARY_DIR}" + echo "DONE" -################################################################################ -echo -n "1) generate config ... " -./scripts/create_cita_config.py create \ - --chain_name "node" \ - --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ - --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ - > /dev/null 2>&1 -echo "DONE" + echo -n "1) generate config ... " + if [[ -n "$1" ]]; then + ./scripts/create_cita_config.py create \ + --chain_name "node" \ + --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ + --"$1"\ + --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ + > /dev/null 2>&1 + else + ./scripts/create_cita_config.py create \ + --chain_name "node" \ + --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ + --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ + > /dev/null 2>&1 + fi + echo "DONE" -################################################################################ -echo -n "2) start nodes ... " -for i in {0..3} ; do - bin/cita bebop setup node/$i > /dev/null -done -for i in {0..3} ; do - bin/cita bebop start node/$i trace > /dev/null & -done -echo "DONE" + echo -n "2) start nodes ... " + start_nodes + echo "DONE" -################################################################################ -echo -n "3) check height growth normal ... " -timeout=$(check_height_growth_normal 0 60)||(echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" + echo -n "3) check height growth normal ... " + timeout=$(check_height_growth_normal 0 60)||(echo "FAILED" + echo "error msg: ${timeout}" + exit 1) + echo "${timeout}s DONE" -################################################################################ -echo -n "4) stop node3, check height growth ... " -bin/cita bebop stop node/3 > /dev/null -timeout=$(check_height_growth_normal 0 15) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" + echo -n "4) stop node3, check height growth ... " + bin/cita bebop stop node/3 > /dev/null + timeout=$(check_height_growth_normal 0 30) || (echo "FAILED" + echo "error msg: ${timeout}" + exit 1) + echo "${timeout}s DONE" -################################################################################ -echo -n "5) stop node2, check height stopped ... " -bin/cita bebop stop node/2 > /dev/null -timeout=$(check_height_stopped 0 27) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" + echo -n "5) stop node2, check height stopped ... " + bin/cita bebop stop node/2 > /dev/null + timeout=$(check_height_stopped 0 30) || (echo "FAILED" + echo "error msg: ${timeout}" + exit 1) + echo "${timeout}s DONE" -################################################################################ -echo -n "6) start node2, check height growth ... " -bin/cita bebop start node/2 trace > /dev/null & -timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" + echo -n "6) start node2, check height growth ... " + bin/cita bebop start node/2 trace > /dev/null & + timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" + echo "error msg: ${timeout}" + exit 1) + echo "${timeout}s DONE" -################################################################################ -echo -n "7) start node3, check synch ... " -node0_height=$(get_height 0) + echo -n "7) start node3, check synch ... " + bin/cita bebop start node/3 > /dev/null & + timeout=$(check_height_sync 3 0) || (echo "FAILED" + echo "error msg: ${timeout}" + exit 1) + echo "${timeout}s DONE" -if [ $? -ne 0 ] ; then - echo "failed to get_height: ${node0_height}" - exit 1 -fi -bin/cita bebop start node/3 trace > /dev/null & -timeout=$(check_height_sync 3 0) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" + echo -n "8) stop all nodes, check height changed after restart ... " + for i in {0..3}; do + bin/cita bebop stop node/$i > /dev/null + done + for i in {0..3}; do + bin/cita bebop start node/$i > /dev/null & + done -################################################################################ -echo -n "8) stop all nodes, check height changed after restart ... " -before_height=$(get_height 0) -if [ $? -ne 0 ] ; then - echo "failed to get_height: ${before_height}" - exit 1 -fi -for i in {0..3}; do - bin/cita bebop stop node/$i > /dev/null -done -# sleep 1 # TODO: change to this value will produce very different result -for i in {0..3}; do - bin/cita bebop start node/$i trace > /dev/null & -done + timeout=$(check_height_growth_normal 0 300) || (echo "FAILED" + echo "error msg: ${timeout}" + exit 1) + echo "${timeout}s DONE" -timeout=$(check_height_growth_normal 0 300) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -after_height=$(get_height 0)|| (echo "failed to get_height: ${after_height}" - exit 1) -if [ $after_height -le $before_height ]; then - echo "FAILED" - echo "before:${before_height} after:${after_height}" - exit 1 -fi -echo "${timeout}s DONE" + echo -n "9) stop&clean node3, check height synch after restart ... " + bin/cita bebop stop node/3 > /dev/null + bin/cita bebop clean node/3 > /dev/null + bin/cita bebop start node/3 > /dev/null & + timeout=$(check_height_sync 3 0) || (echo "FAILED" + echo "error msg: ${timeout}" + exit 1) + echo "${timeout}s DONE" +} -################################################################################ -echo -n "9) stop&clean node3, check height synch after restart ... " -bin/cita bebop stop node/3 > /dev/null -bin/cita bebop clean node/3 > /dev/null -bin/cita bebop start node/3 trace > /dev/null & -timeout=$(check_height_sync 3 0) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" +main "$@" diff --git a/tests/integrate_test/cita_tls_basic.sh b/tests/integrate_test/cita_tls_basic.sh deleted file mode 100755 index 5b41ca226..000000000 --- a/tests/integrate_test/cita_tls_basic.sh +++ /dev/null @@ -1,119 +0,0 @@ -#!/bin/bash -set -e - -if [[ `uname` == 'Darwin' ]] -then - SOURCE_DIR=$(realpath $(dirname $0)/../..) -else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) -fi -BINARY_DIR=${SOURCE_DIR}/target/install - -################################################################################ -echo -n "0) prepare ... " -. ${SOURCE_DIR}/tests/integrate_test/util.sh -cd ${BINARY_DIR} -echo "DONE" - -################################################################################ -echo -n "1) generate config ... " -./scripts/create_cita_config.py create \ - --chain_name "node" \ - --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ - --enable_tls \ - --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ - > /dev/null 2>&1 -echo "DONE" - -################################################################################ -echo -n "2) start nodes ... " -for i in {0..3} ; do - bin/cita bebop setup node/$i > /dev/null -done -for i in {0..3} ; do - bin/cita bebop start node/$i trace > /dev/null & -done -echo "DONE" - -################################################################################ -echo -n "3) check height growth normal ... " -timeout=$(check_height_growth_normal 0 60)||(echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" - -################################################################################ -echo -n "4) stop node3, check height growth ... " -bin/cita bebop stop node/3 > /dev/null -timeout=$(check_height_growth_normal 0 15) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" - -################################################################################ -echo -n "5) stop node2, check height stopped ... " -bin/cita bebop stop node/2 > /dev/null -timeout=$(check_height_stopped 0 27) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" - -################################################################################ -echo -n "6) start node2, check height growth ... " -bin/cita bebop start node/2 trace > /dev/null & -sleep 24 #wait for recovery from stop -timeout=$(check_height_growth_normal 0 15) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" - -################################################################################ -echo -n "7) start node3, check synch ... " -node0_height=$(get_height 0) - -if [ $? -ne 0 ] ; then - echo "failed to get_height: ${node0_height}" - exit 1 -fi -bin/cita bebop start node/3 trace > /dev/null & -timeout=$(check_height_sync 3 0) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" - -################################################################################ -echo -n "8) stop all nodes, check height changed after restart ... " -before_height=$(get_height 0) -if [ $? -ne 0 ] ; then - echo "failed to get_height: ${before_height}" - exit 1 -fi -for i in {0..3}; do - bin/cita bebop stop node/$i > /dev/null -done -# sleep 1 # TODO: change to this value will produce very different result -for i in {0..3}; do - bin/cita bebop start node/$i trace > /dev/null & -done - -timeout=$(check_height_growth_normal 0 300) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -after_height=$(get_height 0)|| (echo "failed to get_height: ${after_height}" - exit 1) -if [ $after_height -le $before_height ]; then - echo "FAILED" - echo "before:${before_height} after:${after_height}" - exit 1 -fi -echo "${timeout}s DONE" - -################################################################################ -echo -n "9) stop&clean node3, check height synch after restart ... " -bin/cita bebop stop node/3 > /dev/null -bin/cita bebop clean node/3 > /dev/null -bin/cita bebop start node/3 trace > /dev/null & -timeout=$(check_height_sync 3 0) || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" From ff66d90a813caaa4650367cbcb6739614b045439 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Tue, 4 Jun 2019 16:12:53 +0800 Subject: [PATCH 25/91] Refactor shell script: create config. --- .circleci/config.yml | 2 +- tests/integrate_test/cita_basic.sh | 60 +++++++++++------------------- tests/integrate_test/util.sh | 18 ++++++++- 3 files changed, 39 insertions(+), 41 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 2e1fb2e5e..4538470c5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -238,7 +238,7 @@ jobs: - run: *after-restore-release-cache - run: name: Basic Tls Test - command: ./tests/integrate_test/cita_basic.sh enable_tls + command: ./tests/integrate_test/cita_basic.sh --enable_tls "JSON-RPC Mock Test in Charge Mode": <<: *job-default diff --git a/tests/integrate_test/cita_basic.sh b/tests/integrate_test/cita_basic.sh index b73e2e504..2be032abf 100755 --- a/tests/integrate_test/cita_basic.sh +++ b/tests/integrate_test/cita_basic.sh @@ -1,36 +1,23 @@ #!/bin/bash -main() { - set -e - if [[ $(uname) == 'Darwin' ]] - then - SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) - else - SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) - fi - BINARY_DIR=${SOURCE_DIR}/target/install +set -e +if [[ $(uname) == 'Darwin' ]] +then + SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) +else + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) +fi +BINARY_DIR=${SOURCE_DIR}/target/install +main() { echo -n "0) prepare ... " # shellcheck source=/dev/null . "${SOURCE_DIR}"/tests/integrate_test/util.sh cd "${BINARY_DIR}" echo "DONE" - echo -n "1) generate config ... " - if [[ -n "$1" ]]; then - ./scripts/create_cita_config.py create \ - --chain_name "node" \ - --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ - --"$1"\ - --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ - > /dev/null 2>&1 - else - ./scripts/create_cita_config.py create \ - --chain_name "node" \ - --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ - --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ - > /dev/null 2>&1 - fi + echo -n "1) generate config ... " + create_config "$1" echo "DONE" echo -n "2) start nodes ... " @@ -38,34 +25,34 @@ main() { echo "DONE" echo -n "3) check height growth normal ... " - timeout=$(check_height_growth_normal 0 60)||(echo "FAILED" - echo "error msg: ${timeout}" - exit 1) + timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" + echo "error msg: ${timeout}" + exit 1) echo "${timeout}s DONE" echo -n "4) stop node3, check height growth ... " - bin/cita bebop stop node/3 > /dev/null + bin/cita bebop stop test/3 2>&1 timeout=$(check_height_growth_normal 0 30) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" echo -n "5) stop node2, check height stopped ... " - bin/cita bebop stop node/2 > /dev/null + bin/cita bebop stop test/2 2>&1 timeout=$(check_height_stopped 0 30) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" echo -n "6) start node2, check height growth ... " - bin/cita bebop start node/2 trace > /dev/null & + bin/cita bebop start test/2 2>&1 timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" echo -n "7) start node3, check synch ... " - bin/cita bebop start node/3 > /dev/null & + bin/cita bebop start test/3 2>&1 timeout=$(check_height_sync 3 0) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) @@ -73,10 +60,7 @@ main() { echo -n "8) stop all nodes, check height changed after restart ... " for i in {0..3}; do - bin/cita bebop stop node/$i > /dev/null - done - for i in {0..3}; do - bin/cita bebop start node/$i > /dev/null & + bin/cita bebop restart test/$i 2>&1 done timeout=$(check_height_growth_normal 0 300) || (echo "FAILED" @@ -85,9 +69,9 @@ main() { echo "${timeout}s DONE" echo -n "9) stop&clean node3, check height synch after restart ... " - bin/cita bebop stop node/3 > /dev/null - bin/cita bebop clean node/3 > /dev/null - bin/cita bebop start node/3 > /dev/null & + bin/cita bebop stop test/3 2>&1 + bin/cita bebop clean test/3 2>&1 + bin/cita bebop start test/3 2>&1 timeout=$(check_height_sync 3 0) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) diff --git a/tests/integrate_test/util.sh b/tests/integrate_test/util.sh index caf18e1fb..d63ab0023 100644 --- a/tests/integrate_test/util.sh +++ b/tests/integrate_test/util.sh @@ -323,9 +323,23 @@ start_nodes() { num=4 fi for ((i=0; i /dev/null + bin/cita bebop setup test/$i 2>&1 done for ((i=0; i /dev/null + bin/cita bebop start test/$i 2>&1 done } + +config_script() { + ./scripts/create_cita_config.py "$@" > /dev/null 2>&1 +} + +create_config() { + local param="create \ + --chain_name test \ + --super_admin 0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523 \ + --nodes 127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003 \ + $*" + # shellcheck disable=SC2086 + config_script $param +} From 48f502191c2000439bd33f9c89248f0a73790501 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Tue, 4 Jun 2019 20:20:48 +0800 Subject: [PATCH 26/91] Remove useless echo. --- tests/integrate_test/util.sh | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/integrate_test/util.sh b/tests/integrate_test/util.sh index d63ab0023..2c6f93ab6 100644 --- a/tests/integrate_test/util.sh +++ b/tests/integrate_test/util.sh @@ -71,12 +71,10 @@ check_height_growth() { local old=$2 local new if new=$(get_height "${id}"); then - echo "new height: ${new}" if [ "${new}" -gt "${old}" ]; then echo "height growth" return 0 fi - echo "height not growth" fi return 1 } @@ -157,11 +155,9 @@ check_height_growth_normal() { local now if old=$(get_height "${id}"); then - echo "old height: ${old}" start=$(date +%s) while true; do if check_height_growth "${id}" "${old}"; then - echo "height gorwth normal id(${id})" return 0 fi now=$(date +%s) From 611fbdfa4675d9157d4ac525d636f231ed429ca6 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 11:20:56 +0800 Subject: [PATCH 27/91] Use chain name as global variable. --- tests/integrate_test/cita_basic.sh | 16 ++++++++-------- tests/integrate_test/util.sh | 8 +++++--- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/tests/integrate_test/cita_basic.sh b/tests/integrate_test/cita_basic.sh index 2be032abf..715fb8bf3 100755 --- a/tests/integrate_test/cita_basic.sh +++ b/tests/integrate_test/cita_basic.sh @@ -31,28 +31,28 @@ main() { echo "${timeout}s DONE" echo -n "4) stop node3, check height growth ... " - bin/cita bebop stop test/3 2>&1 + bin/cita bebop stop $CHAIN_NAME/3 2>&1 timeout=$(check_height_growth_normal 0 30) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" echo -n "5) stop node2, check height stopped ... " - bin/cita bebop stop test/2 2>&1 + bin/cita bebop stop $CHAIN_NAME/2 2>&1 timeout=$(check_height_stopped 0 30) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" echo -n "6) start node2, check height growth ... " - bin/cita bebop start test/2 2>&1 + bin/cita bebop start $CHAIN_NAME/2 2>&1 timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" echo -n "7) start node3, check synch ... " - bin/cita bebop start test/3 2>&1 + bin/cita bebop start $CHAIN_NAME/3 2>&1 timeout=$(check_height_sync 3 0) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) @@ -60,7 +60,7 @@ main() { echo -n "8) stop all nodes, check height changed after restart ... " for i in {0..3}; do - bin/cita bebop restart test/$i 2>&1 + bin/cita bebop restart $CHAIN_NAME/$i 2>&1 done timeout=$(check_height_growth_normal 0 300) || (echo "FAILED" @@ -69,9 +69,9 @@ main() { echo "${timeout}s DONE" echo -n "9) stop&clean node3, check height synch after restart ... " - bin/cita bebop stop test/3 2>&1 - bin/cita bebop clean test/3 2>&1 - bin/cita bebop start test/3 2>&1 + bin/cita bebop stop $CHAIN_NAME/3 2>&1 + bin/cita bebop clean $CHAIN_NAME/3 2>&1 + bin/cita bebop start $CHAIN_NAME/3 2>&1 timeout=$(check_height_sync 3 0) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) diff --git a/tests/integrate_test/util.sh b/tests/integrate_test/util.sh index 2c6f93ab6..7bdb96662 100644 --- a/tests/integrate_test/util.sh +++ b/tests/integrate_test/util.sh @@ -1,5 +1,7 @@ #!/bin/bash +CHAIN_NAME="test" + sudo() { set -o noglob if [ "$(whoami)" == "root" ] ; then @@ -319,10 +321,10 @@ start_nodes() { num=4 fi for ((i=0; i&1 + bin/cita bebop setup $CHAIN_NAME/$i 2>&1 done for ((i=0; i&1 + bin/cita bebop start $CHAIN_NAME/$i 2>&1 done } @@ -332,7 +334,7 @@ config_script() { create_config() { local param="create \ - --chain_name test \ + --chain_name $CHAIN_NAME \ --super_admin 0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523 \ --nodes 127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003 \ $*" From 3d4b8806233ccab8dd7adde8f4f004a9968f39c7 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 11:38:01 +0800 Subject: [PATCH 28/91] Refactor box executor test. --- tests/integrate_test/box_executor_test.sh | 95 +++++++++++------------ 1 file changed, 44 insertions(+), 51 deletions(-) diff --git a/tests/integrate_test/box_executor_test.sh b/tests/integrate_test/box_executor_test.sh index 8825c48f1..5604ed888 100755 --- a/tests/integrate_test/box_executor_test.sh +++ b/tests/integrate_test/box_executor_test.sh @@ -3,63 +3,56 @@ set -e ECONOMICAL_MODEL="0" -if [ -n $1 ] && [ "$1" = "charge" ]; then +if [[ -n "$1" ]] && [ "$1" = "charge" ]; then ECONOMICAL_MODEL="1" fi -if [[ `uname` == 'Darwin' ]] +if [[ $(uname) == 'Darwin' ]] then - SOURCE_DIR=$(realpath $(dirname $0)/../..) + SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) fi BINARY_DIR=${SOURCE_DIR}/target/install -TESTS_DIR=${SOURCE_DIR}/tests/jsondata/rpc/tests -CHAIN_NAME="mock-chain" -NODE_NAME="${CHAIN_NAME}/0" -NODE_DIR="${BINARY_DIR}/${NODE_NAME}" -TNODE=`echo ${NODE_NAME} | sed 's/\//%2f/g'` -################################################################################ -echo -n "0) prepare ... " -. ${SOURCE_DIR}/tests/integrate_test/util.sh -cd ${BINARY_DIR} -echo "DONE" -################################################################################ -echo -n "1) generate config ... " -if [ ! -d "resource" ]; then - mkdir resource -fi - -AUTHORITIES=`cat ${SOURCE_DIR}/tests/interfaces/config/authorities | xargs echo |sed "s/ /,/g"` -${BINARY_DIR}/scripts/create_cita_config.py create \ - --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ - --chain_name ${CHAIN_NAME} \ - --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ - --contract_arguments "SysConfig.economicalModel=${ECONOMICAL_MODEL}" \ - --contract_arguments "SysConfig.chainId=123" \ - --timestamp 1524000000 \ - --authorities ${AUTHORITIES} -echo -n "DONE" - -################################################################################ -echo -n "2) start cita-chain and cita-executor on ${NODE_NAME} ... " -${BINARY_DIR}/bin/cita setup ${NODE_NAME} - -curl -i -u guest:guest -H content-type:application/json -XDELETE \ - http://localhost:15672/api/queues/${TNODE}/consensus > /dev/null - -cd ${NODE_DIR} -${BINARY_DIR}/bin/cita-chain -c chain.toml & -chain_pid=$! -${BINARY_DIR}/bin/cita-executor -c executor.toml & -executor_pid=$! -echo -n "DONE" - -## ################################################################################ -echo -n "3) testing ... " -AMQP_URL=amqp://guest:guest@localhost/${NODE_NAME} \ - timeout 100s ${BINARY_DIR}/bin/box_executor \ - -m ${SOURCE_DIR}/tests/interfaces/config/blockchain.yaml -echo -n "DONE" +main() { + echo -n "0) prepare ... " + # shellcheck source=/dev/null + . ${SOURCE_DIR}/tests/integrate_test/util.sh + cd "${BINARY_DIR}" + echo "DONE" + + echo -n "1) generate config ... " + if [ ! -d "resource" ]; then + mkdir resource + fi + + autorities=$(xargs echo < "${SOURCE_DIR}"/tests/interfaces/config/authorities | sed "s/ /,/g") + create_config \ + --contract_arguments "SysConfig.economicalModel=${ECONOMICAL_MODEL}" \ + --contract_arguments "SysConfig.chainId=123" \ + --timestamp 1524000000 \ + --authorities "${autorities}" + echo -n "DONE" + + echo -n "2) start cita-chain and cita-executor on node0 ... " + bin/cita bebop setup "${CHAIN_NAME}"/0 + + tnode=$(echo "${CHAIN_NAME}"/0 | sed 's/\//%2f/g') + curl -i -u guest:guest -H content-type:application/json -XDELETE \ + http://localhost:15672/api/queues/"${tnode}"/consensus > /dev/null + + node_dir="${BINARY_DIR}/${CHAIN_NAME}/0" + bin/cita-chain -c "${node_dir}"/chain.toml & + bin/cita-executor -c "${node_dir}"/executor.toml & + echo -n "DONE" + + echo -n "3) testing ... " + AMQP_URL=amqp://guest:guest@localhost/${CHAIN_NAME}/0 \ + timeout 100s "${BINARY_DIR}"/bin/box_executor \ + -m "${SOURCE_DIR}"/tests/interfaces/config/blockchain.yaml + echo -n "DONE" +} + +main "$@" From f6412f6b3160abf0d09ac9b6057146772b65c994 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 12:05:07 +0800 Subject: [PATCH 29/91] Refactor amend test. --- tests/integrate_test/cita_amend_test.sh | 219 ++++++++++++------------ 1 file changed, 107 insertions(+), 112 deletions(-) diff --git a/tests/integrate_test/cita_amend_test.sh b/tests/integrate_test/cita_amend_test.sh index 3679c8f4e..e4ce73914 100755 --- a/tests/integrate_test/cita_amend_test.sh +++ b/tests/integrate_test/cita_amend_test.sh @@ -1,122 +1,117 @@ #!/usr/bin/env bash # Set bash environment -set -e -SOURCE_DIR=$(cd $(dirname "$0")/../..; pwd) -if [[ `uname` == 'Darwin' ]] +if [[ $(uname) == 'Darwin' ]] then - SED="gsed" + SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) else - SED="sed" + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) fi +set -e # Set CITA system environment BINARY_DIR=${SOURCE_DIR}/target/install -CHAIN_NAME="test-chain" -SUPER_ADMIN="0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" - -################################################################################ -echo "0) Prepare ..." -source "${SOURCE_DIR}/tests/integrate_test/util.sh" -cd "${BINARY_DIR}" -echo "DONE" - -################################################################################ -echo "1) Generate CITA configurations ..." -${BINARY_DIR}/scripts/create_cita_config.py create \ - --nodes "127.0.0.1:4000" \ - --super_admin "${SUPER_ADMIN}" -echo "DONE" - -################################################################################ -echo "2) Run node-0" -${BINARY_DIR}/bin/cita bebop setup ${CHAIN_NAME}/0 > /dev/null -${BINARY_DIR}/bin/cita bebop start ${CHAIN_NAME}/0 trace -echo "DONE" - -sleep 10 - -################################################################################ -echo "3) Check node grow up ..." -echo "chech_height_growth_normal 0 ..." -timeout=`check_height_growth_normal 0 15`||(echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -echo "${timeout}s DONE" - -################################################################################ -echo "4) Amend chain name ..." -cd ${BINARY_DIR}/scripts/txtool/txtool - -curl -X POST --data '{"jsonrpc":"2.0","method":"getMetaData","params":["latest"],"id":1}' 127.0.0.1:1337 \ - | grep "\"chainName\"\:\"test-chain\"" - -python3 make_tx.py \ ---code 0xffffffffffffffffffffffffffffffffff0200000000000000000000000000000000000000000000000000000000000000000027306573742d636861696e00000000000000000000000000000000000000000014 \ ---to 0xffffffffffffffffffffffffffffffffff010002 \ ---value 3 \ ---privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 - -python3 send_tx.py - -sleep 10 - -curl -X POST --data '{"jsonrpc":"2.0","method":"getMetaData","params":["latest"],"id":1}' 127.0.0.1:1337 \ - | grep "\"chainName\"\:\"0est-chain\"" - -################################################################################ -echo "5) Amend abi ..." -cd ${BINARY_DIR}/scripts/txtool/txtool - -# set abi of 0xffffffffffffffffffffffffffffffffff020000 as "amendabitest" -python3 make_tx.py \ ---code 0xffffffffffffffffffffffffffffffffff0200000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c616d656e64616269746573740000000000000000000000000000000000000000 \ ---to 0xffffffffffffffffffffffffffffffffff010002 \ ---value 1 \ ---privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 - -python3 send_tx.py - -sleep 10 - -# ascii of "amendabitest" -curl -X POST --data '{"jsonrpc":"2.0","method":"getAbi","params":["0xffffffffffffffffffffffffffffffffff020000", "latest"],"id":1}' 127.0.0.1:1337 \ - | grep "616d656e6461626974657374" - -################################################################################ -echo "6) Amend balance ..." -cd ${BINARY_DIR}/scripts/txtool/txtool - -# set balance of 0xffffffffffffffffffffffffffffffffff020000 as 1234(0x4d2) -python3 make_tx.py \ ---code 0xffffffffffffffffffffffffffffffffff02000000000000000000000000000000000000000000000000000000000000000004d2 \ ---to 0xffffffffffffffffffffffffffffffffff010002 \ ---value 5 \ ---privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 - -python3 send_tx.py - -sleep 10 - -# hex of 1234 -curl -X POST --data '{"jsonrpc":"2.0","method":"getBalance","params":["0xffffffffffffffffffffffffffffffffff020000", "latest"],"id":1}' 127.0.0.1:1337 \ - | grep "0x4d2" - -################################################################################ -echo "7) Amend code ..." -cd ${BINARY_DIR}/scripts/txtool/txtool - -# set code of 0xffffffffffffffffffffffffffffffffff020004 as "deadbeef" -python3 make_tx.py \ ---code 0xffffffffffffffffffffffffffffffffff020004deadbeef \ ---to 0xffffffffffffffffffffffffffffffffff010002 \ ---value 2 \ ---privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 - -python3 send_tx.py -sleep 10 - -# hex of 1234 -curl -X POST --data '{"jsonrpc":"2.0","method":"getCode","params":["0xffffffffffffffffffffffffffffffffff020004", "latest"],"id":1}' 127.0.0.1:1337 \ - | grep "0xdeadbeef" +amend_chain_name() { + python3 make_tx.py \ + --code 0xffffffffffffffffffffffffffffffffff0200000000000000000000000000000000000000000000000000000000000000000027306573742d636861696e00000000000000000000000000000000000000000014 \ + --to 0xffffffffffffffffffffffffffffffffff010002 \ + --value 3 \ + --privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 > /dev/null + + python3 send_tx.py > /dev/null + + sleep 10 + + curl -X POST --data '{"jsonrpc":"2.0","method":"getMetaData","params":["latest"],"id":1}' 127.0.0.1:1337 \ + | grep "\"chainName\"\:\"0est-chain\"" +} + +amend_abi() { + # set abi of 0xffffffffffffffffffffffffffffffffff020000 as "amendabitest" + python3 make_tx.py \ + --code 0xffffffffffffffffffffffffffffffffff0200000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000c616d656e64616269746573740000000000000000000000000000000000000000 \ + --to 0xffffffffffffffffffffffffffffffffff010002 \ + --value 1 \ + --privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 > /dev/null + + python3 send_tx.py > /dev/null + + sleep 10 + + # ascii of "amendabitest" + curl -X POST --data '{"jsonrpc":"2.0","method":"getAbi","params":["0xffffffffffffffffffffffffffffffffff020000", "latest"],"id":1}' 127.0.0.1:1337 \ + | grep "616d656e6461626974657374" +} + +amend_balance() { + # set balance of 0xffffffffffffffffffffffffffffffffff020000 as 1234(0x4d2) + python3 make_tx.py \ + --code 0xffffffffffffffffffffffffffffffffff02000000000000000000000000000000000000000000000000000000000000000004d2 \ + --to 0xffffffffffffffffffffffffffffffffff010002 \ + --value 5 \ + --privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 > /dev/null + + python3 send_tx.py > /dev/null + + sleep 10 + + # hex of 1234 + curl -X POST --data '{"jsonrpc":"2.0","method":"getBalance","params":["0xffffffffffffffffffffffffffffffffff020000", "latest"],"id":1}' 127.0.0.1:1337 \ + | grep "0x4d2" +} + +amend_code() { + # set code of 0xffffffffffffffffffffffffffffffffff020004 as "deadbeef" + python3 make_tx.py \ + --code 0xffffffffffffffffffffffffffffffffff020004deadbeef \ + --to 0xffffffffffffffffffffffffffffffffff010002 \ + --value 2 \ + --privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 > /dev/null + + python3 send_tx.py > /dev/null + + sleep 10 + + # hex of 1234 + curl -X POST --data '{"jsonrpc":"2.0","method":"getCode","params":["0xffffffffffffffffffffffffffffffffff020004", "latest"],"id":1}' 127.0.0.1:1337 \ + | grep "0xdeadbeef" +} + +main() { + echo "0) Prepare ..." + # shellcheck source=/dev/null + source "${SOURCE_DIR}/tests/integrate_test/util.sh" + cd "${BINARY_DIR}" + echo "DONE" + + echo "1) Generate configurations ..." + create_config + echo "DONE" + + echo "2) Run nodes" + start_nodes + echo "DONE" + + echo "3) Check node grow up ..." + timeout=$(check_height_growth_normal 0 30) || (echo "FAILED" + echo "error msg: ${timeout}" + exit 1) + echo "${timeout}s DONE" + + cd "${BINARY_DIR}"/scripts/txtool/txtool + echo "4) Amend chain name ..." + amend_chain_name + echo "DONE" + echo "5) Amend abi ..." + amend_abi + echo "DONE" + echo "6) Amend balance ..." + amend_balance + echo "DONE" + echo "7) Amend code ..." + amend_code + echo "DONE" +} + +main "$@" From 47f811c886ea8ffbb368435579b115c82cc1f513 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 14:45:50 +0800 Subject: [PATCH 30/91] Refactor bft resend test. --- tests/integrate_test/cita_bft_resend.sh | 105 ++++++++++++------------ 1 file changed, 52 insertions(+), 53 deletions(-) diff --git a/tests/integrate_test/cita_bft_resend.sh b/tests/integrate_test/cita_bft_resend.sh index 88a1b8112..30f673ade 100755 --- a/tests/integrate_test/cita_bft_resend.sh +++ b/tests/integrate_test/cita_bft_resend.sh @@ -2,70 +2,69 @@ # Set bash environment set -e -if [[ `uname` == 'Darwin' ]] +if [[ $(uname) == 'Darwin' ]] then - SOURCE_DIR=$(realpath $(dirname $0)/../..) - SED="gsed" + SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) - SED="sed" + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) fi - # Set CITA system environment BINARY_DIR=${SOURCE_DIR}/target/install -CHAIN_NAME="mock-chain" SUPER_ADMIN="0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" -################################################################################ -echo "0) Prepare ..." -source "${SOURCE_DIR}/tests/integrate_test/util.sh" -cd "${BINARY_DIR}" -echo "DONE" +main() { + echo "0) Prepare ..." + # shellcheck source=/dev/null + source "${SOURCE_DIR}/tests/integrate_test/util.sh" + cd "${BINARY_DIR}" + echo "DONE" + + echo "1) Generate CITA configurations ..." + scripts/create_cita_config.py create \ + --nodes "127.0.0.1:4000" \ + --super_admin "${SUPER_ADMIN}" \ + --chain_name "${CHAIN_NAME}" \ + --timestamp 1524000000 + echo "DONE" -################################################################################ -echo "1) Generate CITA configurations ..." -${BINARY_DIR}/scripts/create_cita_config.py create \ - --nodes "127.0.0.1:4000" \ - --super_admin "${SUPER_ADMIN}" \ - --chain_name "${CHAIN_NAME}" \ - --timestamp 1524000000 -echo "DONE" + echo "2) Start CITA components manually" + bin/cita bebop setup "${CHAIN_NAME}"/0 + bin/cita bebop start "${CHAIN_NAME}"/0 + sleep 3 + bin/cita bebop stop "${CHAIN_NAME}"/0 -################################################################################ -echo "2) Start CITA components manually" -${BINARY_DIR}/bin/cita bebop setup ${CHAIN_NAME}/0 -${BINARY_DIR}/bin/cita bebop start ${CHAIN_NAME}/0 trace -sleep 3 -${BINARY_DIR}/bin/cita bebop stop ${CHAIN_NAME}/0 + cd "${CHAIN_NAME}"/0 + "${BINARY_DIR}"/bin/cita-auth -c auth.toml & auth_pid=$! + "${BINARY_DIR}"/bin/cita-bft -c consensus.toml -p privkey & bft_pid=$! + "${BINARY_DIR}"/bin/cita-chain -c chain.toml & chain_pid=$! + "${BINARY_DIR}"/bin/cita-executor -c executor.toml & executor_pid=$! + "${BINARY_DIR}"/bin/cita-jsonrpc -c jsonrpc.toml & jsonrpc_pid=$! + "${BINARY_DIR}"/bin/cita-network -c network.toml & network_pid=$! + wait_timeout=30 + timeout=$(check_height_growth_normal 0 $wait_timeout) || (echo "FAILED" + echo "error msg: ${timeout}" + exit 1) + cd "${BINARY_DIR}" + echo "DONE" -cd ${CHAIN_NAME}/0 -${BINARY_DIR}/bin/cita-auth -c auth.toml & auth_pid=$! -${BINARY_DIR}/bin/cita-bft -c consensus.toml -p privkey & bft_pid=$! -${BINARY_DIR}/bin/cita-chain -c chain.toml & chain_pid=$i -${BINARY_DIR}/bin/cita-executor -c executor.toml & executor_pid=$! -${BINARY_DIR}/bin/cita-jsonrpc -c jsonrpc.toml & jsonrpc_pid=$! -${BINARY_DIR}/bin/cita-network -c network.toml & network_pid=$! -wait_timeout=30 -timeout=`check_height_growth_normal 0 $wait_timeout` || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) + echo "3) Kill cita-executor and cita-chain, and rm -rf data/statedb" + kill ${executor_pid} + sleep 3 + kill ${chain_pid} + rm -rf "${CHAIN_NAME}"/0/data/statedb + sleep 10 + echo "DONE" -################################################################################ -echo "3) Kill cita-executor and cita-chain, and rm -rf data/statedb" -jobs -l | grep cita-executor | awk '{print $2}' | xargs -I {} kill {} -sleep 3 -jobs -l | grep cita-chai | awk '{print $2}' | xargs -I {} kill {} -rm -rf data/statedb -sleep 10 + echo "4) Restart CITA" + kill ${auth_pid} ${bft_pid} ${jsonrpc_pid} ${network_pid} -################################################################################ -echo "4) Restart CITA" -kill ${auth_pid} ${bft_pid} ${jsonrpc_pid} ${network_pid} + bin/cita bebop start "${CHAIN_NAME}"/0 -cd ${BINARY_DIR} -${BINARY_DIR}/bin/cita bebop start ${CHAIN_NAME}/0 trace + wait_timeout=30 + timeout=$(check_height_growth_normal 0 $wait_timeout) || (echo "FAILED" + echo "error msg: ${timeout}" + exit 1) + echo "DONE" +} -wait_timeout=30 -timeout=`check_height_growth_normal 0 $wait_timeout` || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) +main "$@" From 4b72e88ffacc9700f5cf6b78c65acfd77e69f911 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 15:16:09 +0800 Subject: [PATCH 31/91] Refactor byzantine test. --- tests/integrate_test/cita_byzantinetest.sh | 187 ++++++++++----------- 1 file changed, 88 insertions(+), 99 deletions(-) diff --git a/tests/integrate_test/cita_byzantinetest.sh b/tests/integrate_test/cita_byzantinetest.sh index 14f85af70..40c9c5e82 100755 --- a/tests/integrate_test/cita_byzantinetest.sh +++ b/tests/integrate_test/cita_byzantinetest.sh @@ -2,119 +2,108 @@ set -e ECONOMICAL_MODEL="0" -if [ -n $1 ] && [ "$1" = "charge" ]; then +if [[ -n "$1" ]] && [ "$1" = "charge" ]; then ECONOMICAL_MODEL="1" fi -if [[ `uname` == 'Darwin' ]] +if [[ $(uname) == 'Darwin' ]] then - SOURCE_DIR=$(realpath $(dirname $0)/../..) + SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) fi -BINARY_DIR=${SOURCE_DIR}/target/install - -################################################################################ -echo -n "0) prepare ... " -. ${SOURCE_DIR}/tests/integrate_test/util.sh -cd ${BINARY_DIR} -echo "DONE" -################################################################################ +BINARY_DIR=${SOURCE_DIR}/target/install -echo -n "1) generate config ... " -./scripts/create_cita_config.py create \ - --chain_name "node" \ - --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ - --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ - --contract_arguments "SysConfig.economicalModel=${ECONOMICAL_MODEL}" \ - > /dev/null 2>&1 -echo "DONE" +main() { + echo -n "0) prepare ... " + # shellcheck source=/dev/null + . ${SOURCE_DIR}/tests/integrate_test/util.sh + cd "${BINARY_DIR}" + echo "DONE" -################################################################################ -echo -n "2) start nodes ... " -for i in {0..3} ; do - bin/cita bebop setup node/$i > /dev/null -done -for i in {0..3} ; do - bin/cita bebop start node/$i debug > /dev/null & -done -echo "DONE" + echo -n "1) generate config ... " + create_config --contract_arguments "SysConfig.economicalModel=${ECONOMICAL_MODEL}" + echo "DONE" -################################################################################ -echo -n "3) check alive ... " -timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" - echo "failed to check_height_growth 0: ${timeout}" - exit 1) -echo "${timeout}s DONE" + echo -n "2) start nodes ... " + start_nodes + echo "DONE" -################################################################################ -echo "4) set delay at one nodes, , output time used for produce block growth" -delay=10000 -for i in {0..3}; do - id=$(($i%4)) - echo -n "set delay at node ${id} ... " - refer=$((($i+1)%4)) - port=$((4000+${id})) - set_delay_at_port ${port} ${delay} - timeout1=$(check_height_growth_normal ${refer} 60) ||(echo "FAILED" - echo "failed to check_height_growth: ${timeout1}" - exit 1) - unset_delay_at_port ${port} - #synch for node ${id} - timeout=$(check_height_sync ${id} ${refer}) ||(echo "FAILED" - echo "failed to check_height_sync: ${timeout}" + echo -n "3) check alive ... " + timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" + echo "failed to check_height_growth 0: ${timeout}" exit 1) - echo "${timeout1}s DONE" -done + echo "${timeout}s DONE" -################################################################################ -echo "5) set delay at two nodes, output time used for produce block" -delay=3000 -for i in {0..3}; do - id1=$i - id2=$((($i+1)%4)) - refer=$((($i+2)%4)) - echo -n "set delay=${delay} at nodes ${id1},${id2} ... " - set_delay_at_port $((4000+${id1})) ${delay} - set_delay_at_port $((4000+${id2})) ${delay} + echo "4) set delay at one nodes, , output time used for produce block growth" + delay=10000 + for i in {0..3}; do + id=$((i%4)) + echo -n "set delay at node ${id} ... " + refer=$(((i+1)%4)) + port=$((4000+id)) + set_delay_at_port ${port} ${delay} + timeout1=$(check_height_growth_normal ${refer} 60) ||(echo "FAILED" + echo "failed to check_height_growth: ${timeout1}" + exit 1) + unset_delay_at_port ${port} + #synch for node ${id} + timeout=$(check_height_sync ${id} ${refer}) ||(echo "FAILED" + echo "failed to check_height_sync: ${timeout}" + exit 1) + echo "${timeout1}s DONE" + done - timeout1=$(check_height_growth_normal ${refer} 100) ||(echo "FAILED" - echo "failed to check_height_growth ${refer}: ${timeout1}" - exit 1) - unset_delay_at_port $((4000+${id1})) - unset_delay_at_port $((4000+${id2})) - sleep 3 - timeout=$(check_height_growth_normal ${refer} 100) ||(echo "FAILED" - echo "failed to check_height_growth ${refer}: ${timeout}" - exit 1) - #synch for node id1, id2 - timeout=$(check_height_sync ${id1} ${refer}) ||(echo "FAILED" - echo "failed to check_height_sync ${id1}: ${timeout}" - exit 1) - timeout=$(check_height_sync ${id2} ${refer}) ||(echo "FAILED" - echo "failed to check_height_sync ${id2}: ${timeout}" - exit 1) - echo "${timeout1}s DONE" -done + echo "5) set delay at two nodes, output time used for produce block" + delay=3000 + for i in {0..3}; do + id1=$i + id2=$(((i+1)%4)) + refer=$(((i+2)%4)) + echo -n "set delay=${delay} at nodes ${id1},${id2} ... " + set_delay_at_port $((4000+id1)) ${delay} + set_delay_at_port $((4000+id2)) ${delay} -################################################################################ -echo "6) set delay at all nodes, output time used for produce block" -for i in {0..6}; do - delay=$((i*400)) - timeout=$(check_height_growth_normal 0 60) ||(echo "FAILED" - echo "failed to check_height_growth: ${timeout}" - exit 1) - echo -n "set delay=${delay} ... " - for node in {0..3} ; do - set_delay_at_port $((4000+${node})) ${delay} + timeout1=$(check_height_growth_normal ${refer} 100) ||(echo "FAILED" + echo "failed to check_height_growth ${refer}: ${timeout1}" + exit 1) + unset_delay_at_port $((4000+id1)) + unset_delay_at_port $((4000+id2)) + sleep 3 + timeout=$(check_height_growth_normal ${refer} 100) ||(echo "FAILED" + echo "failed to check_height_growth ${refer}: ${timeout}" + exit 1) + #synch for node id1, id2 + timeout=$(check_height_sync ${id1} ${refer}) ||(echo "FAILED" + echo "failed to check_height_sync ${id1}: ${timeout}" + exit 1) + timeout=$(check_height_sync ${id2} ${refer}) ||(echo "FAILED" + echo "failed to check_height_sync ${id2}: ${timeout}" + exit 1) + echo "${timeout1}s DONE" done - timeout=$(check_height_growth_normal 0 60) ||(echo "FAILED" - echo "failed to check_height_growth: ${timeout}" - exit 1) - for node in {0..3} ; do - unset_delay_at_port $((4000+${node})) + + echo "6) set delay at all nodes, output time used for produce block" + for i in {0..6}; do + delay=$((i*400)) + timeout=$(check_height_growth_normal 0 60) ||(echo "FAILED" + echo "failed to check_height_growth: ${timeout}" + exit 1) + echo -n "set delay=${delay} ... " + for node in {0..3} ; do + set_delay_at_port $((4000+node)) ${delay} + done + timeout=$(check_height_growth_normal 0 60) ||(echo "FAILED" + echo "failed to check_height_growth: ${timeout}" + exit 1) + for node in {0..3} ; do + unset_delay_at_port $((4000+node)) + done + sleep 4 + echo "${timeout}s DONE" done - sleep 4 - echo "${timeout}s DONE" -done +} + + +main "$@" From 78070ae62a3ad8b24747ed700dd5628f1fa968e6 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 15:55:15 +0800 Subject: [PATCH 32/91] Refactor chage mode test. --- tests/integrate_test/cita_charge_mode.sh | 175 +++++++++++------------ 1 file changed, 81 insertions(+), 94 deletions(-) diff --git a/tests/integrate_test/cita_charge_mode.sh b/tests/integrate_test/cita_charge_mode.sh index 8a50b414d..804f15411 100755 --- a/tests/integrate_test/cita_charge_mode.sh +++ b/tests/integrate_test/cita_charge_mode.sh @@ -1,113 +1,100 @@ #!/bin/bash set -e -if [[ `uname` == 'Darwin' ]] +if [[ $(uname) == 'Darwin' ]] then - SOURCE_DIR=$(realpath $(dirname $0)/../..) + SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) fi BINARY_DIR=${SOURCE_DIR}/target/install -################################################################################ -echo -n "0) prepare ... " -. ${SOURCE_DIR}/tests/integrate_test/util.sh -cd ${BINARY_DIR} -echo "DONE" +test_charge_mode() { + local version=$1 + local node_0_privkey + local node_1_privkey + local node_2_privkey + local node_3_privkey + node_0_privkey=$(cat ./"$CHAIN_NAME"/0/privkey) + node_1_privkey=$(cat ./"$CHAIN_NAME"/1/privkey) + node_2_privkey=$(cat ./"$CHAIN_NAME"/2/privkey) + node_3_privkey=$(cat ./"$CHAIN_NAME"/3/privkey) + cd ./scripts/txtool/txtool + python3 "${SOURCE_DIR}"/tests/integrate_test/test_charge_mode.py \ + --miner-privkeys \ + "${node_0_privkey}" \ + "${node_1_privkey}" \ + "${node_2_privkey}" \ + "${node_3_privkey}" \ + --version="$version" + cd ../../.. +} -################################################################################ -echo -n "1) generate config ... " -./scripts/create_cita_config.py \ - create \ - --chain_name "node" \ - --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ - --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ - --contract_arguments "SysConfig.checkFeeBackPlatform=true" \ - --contract_arguments "SysConfig.economicalModel=1" \ - --contract_arguments "VersionManager.version=0" \ - --contract_arguments "PriceManager.quotaPrice=1000000" \ - --contract_arguments "SysConfig.chainOwner=0x36a60d575b0dee0423abb6a57dbc6ca60bf47545" > /dev/null 2>&1 -echo "DONE" +test_fee_back() { + local version=$1 + cd ./scripts/txtool/txtool + python3 "${SOURCE_DIR}"/tests/integrate_test/test_fee_back.py --version="$version" + cd ../../.. +} -################################################################################ -echo -n "2) start nodes ... " -for i in {0..3} ; do - ./bin/cita bebop setup node/$i > /dev/null -done -for i in {0..3} ; do - ./bin/cita bebop start node/$i trace > /dev/null & -done -echo "DONE" +update_version() { + local version=$1 + cd ./scripts/txtool/txtool + python3 "${SOURCE_DIR}"/tests/integrate_test/update_version.py --version="$version" + cd ../../.. +} -################################################################################ -echo -n "3) check alive ... " -timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" - echo "failed to check_height_growth 0: ${timeout}" - exit 1) -echo "${timeout}s DONE" +main() { + echo -n "0) prepare ... " + # shellcheck source=/dev/null + . ${SOURCE_DIR}/tests/integrate_test/util.sh + cd "${BINARY_DIR}" + echo "DONE" -################################################################################ -echo -n "4) Run fee back tests ... " -cd ./scripts/txtool/txtool -python3 ${SOURCE_DIR}/tests/integrate_test/test_fee_back.py --version=0 -cd ../../.. -echo "DONE" + echo -n "1) generate config ... " + create_config \ + --contract_arguments "SysConfig.checkFeeBackPlatform=true" \ + --contract_arguments "SysConfig.economicalModel=1" \ + --contract_arguments "VersionManager.version=0" \ + --contract_arguments "PriceManager.quotaPrice=1000000" \ + --contract_arguments "SysConfig.chainOwner=0x36a60d575b0dee0423abb6a57dbc6ca60bf47545" + echo "DONE" -################################################################################ -echo -n "5) Run charge mode tests ... " -echo "" + echo -n "2) start nodes ... " + start_nodes + echo "DONE" -NODE_0_PRIVKEY=`cat ./node/0/privkey` -NODE_1_PRIVKEY=`cat ./node/1/privkey` -NODE_2_PRIVKEY=`cat ./node/2/privkey` -NODE_3_PRIVKEY=`cat ./node/3/privkey` -cd ./scripts/txtool/txtool -python3 ${SOURCE_DIR}/tests/integrate_test/test_charge_mode.py \ - --miner-privkeys \ - ${NODE_0_PRIVKEY} \ - ${NODE_0_PRIVKEY} \ - ${NODE_0_PRIVKEY} \ - ${NODE_0_PRIVKEY} \ - --version=0 -cd ../../.. -echo "DONE" + echo -n "3) check alive ... " + timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" + echo "failed to check_height_growth 0: ${timeout}" + exit 1) + echo "${timeout}s DONE" -################################################################################ -echo -n "6) Update to chainIDV1 ... " -cd ./scripts/txtool/txtool -python3 ${SOURCE_DIR}/tests/integrate_test/update_version.py --version=0 -cd ../../.. -echo "DONE" + echo -n "4) Run fee back tests ... " + test_fee_back 0 + echo "DONE" -################################################################################ -echo -n "7) check alive ... " -timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" - echo "failed to check_height_growth 0: ${timeout}" - exit 1) -echo "${timeout}s DONE" + echo -n "5) Run charge mode tests in v0 ... " + test_charge_mode 0 + echo "DONE" -################################################################################ -echo -n "8) Run fee back tests in v1 ... " -cd ./scripts/txtool/txtool -python3 ${SOURCE_DIR}/tests/integrate_test/test_fee_back.py --version=1 -cd ../../.. -echo "DONE" + echo -n "6) Update to chainIDV1 ... " + update_version 0 + echo "DONE" -################################################################################ -echo -n "9) Run charge mode tests in v1 ... " -echo "" + echo -n "7) check alive ... " + timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" + echo "failed to check_height_growth 0: ${timeout}" + exit 1) + echo "${timeout}s DONE" -NODE_0_PRIVKEY=`cat ./node/0/privkey` -NODE_1_PRIVKEY=`cat ./node/1/privkey` -NODE_2_PRIVKEY=`cat ./node/2/privkey` -NODE_3_PRIVKEY=`cat ./node/3/privkey` -cd ./scripts/txtool/txtool -python3 ${SOURCE_DIR}/tests/integrate_test/test_charge_mode.py \ - --miner-privkeys \ - ${NODE_0_PRIVKEY} \ - ${NODE_0_PRIVKEY} \ - ${NODE_0_PRIVKEY} \ - ${NODE_0_PRIVKEY} \ - --version 1 -cd ../../.. -echo "DONE" + echo -n "8) Run fee back tests in v1 ... " + test_fee_back 1 + echo "DONE" + + echo -n "9) Run charge mode tests in v1 ... " + test_charge_mode 1 + echo "DONE" +} + +main "$@" From 242bd3996b96436621a8b2c09e254fa46cd88919 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 16:21:44 +0800 Subject: [PATCH 33/91] Refactor jsonrpc schema mock test. --- .../cita_jsonrpc_schema_mock.sh | 88 ++++++++----------- 1 file changed, 39 insertions(+), 49 deletions(-) diff --git a/tests/integrate_test/cita_jsonrpc_schema_mock.sh b/tests/integrate_test/cita_jsonrpc_schema_mock.sh index 2e8f683cc..05e8e47b4 100755 --- a/tests/integrate_test/cita_jsonrpc_schema_mock.sh +++ b/tests/integrate_test/cita_jsonrpc_schema_mock.sh @@ -3,64 +3,54 @@ set -e ECONOMICAL_MODEL="0" -if [ -n $1 ] && [ "$1" = "charge" ]; then +if [[ -n "$1" ]] && [ "$1" = "charge" ]; then ECONOMICAL_MODEL="1" fi -if [[ `uname` == 'Darwin' ]] +if [[ $(uname) == 'Darwin' ]] then - SOURCE_DIR=$(realpath $(dirname $0)/../..) + SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) fi -BINARY_DIR=${SOURCE_DIR}/target/install -TESTS_DIR=${SOURCE_DIR}/tests/interfaces/rpc/tests - -################################################################################ -echo -n "0) prepare ... " -. ${SOURCE_DIR}/tests/integrate_test/util.sh -cd ${BINARY_DIR} -echo "DONE" - -################################################################################ -echo -n "1) generate config ... " -if [ ! -d "resource" ]; then - mkdir resource -fi - -AUTHORITIES=`cat ${SOURCE_DIR}/tests/interfaces/config/authorities |xargs echo |sed "s/ /,/g"` -${BINARY_DIR}/scripts/create_cita_config.py create --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ - --chain_name "mock-chain" \ +BINARY_DIR=${SOURCE_DIR}/target/install +CHAIN_NAME="mock-chain" + +main() { + echo -n "0) prepare ... " + cd "${BINARY_DIR}" + echo "DONE" + + echo -n "1) generate config ... " + AUTHORITIES=$(xargs echo < "${SOURCE_DIR}"/tests/interfaces/config/authorities |sed "s/ /,/g") + "${BINARY_DIR}"/scripts/create_cita_config.py create \ + --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ + --chain_name "$CHAIN_NAME" \ --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ --contract_arguments "SysConfig.economicalModel=${ECONOMICAL_MODEL}" \ --contract_arguments "SysConfig.chainId=123" \ --timestamp 1524000000 \ - --authorities ${AUTHORITIES} \ + --authorities "${AUTHORITIES}" \ --enable_version -echo "DONE" - -################################################################################ -echo -n "2) just start mock-chain/0 ... " -${BINARY_DIR}/bin/cita bebop setup mock-chain/0 > /dev/null -${BINARY_DIR}/bin/cita bebop start mock-chain/0 trace -echo "DONE" - -################################################################################ -echo -n "3) generate mock data ... " -AMQP_URL=amqp://guest:guest@localhost/mock-chain/0 \ - ${BINARY_DIR}/bin/chain-executor-mock \ - -m ${SOURCE_DIR}/tests/interfaces/config/blockchain.yaml -echo "DONE" - -################################################################################ -echo -n "4) check mock data ... " -python3 ${SOURCE_DIR}/tests/interfaces/rpc_test_runner.py \ - --rpc-url http://127.0.0.1:1337 \ - --directory ${SOURCE_DIR}/tests/jsondata/rpc/ -echo "DONE" - -################################################################################ -echo -n "5) stop mock-chain/0 ... " -${BINARY_DIR}/bin/cita bebop stop mock-chain/0 -echo "DONE" + echo "DONE" + + echo -n "2) just start node0 ... " + bin/cita bebop setup "$CHAIN_NAME"/0 > /dev/null + bin/cita bebop start "$CHAIN_NAME"/0 + echo "DONE" + + echo -n "3) generate mock data ... " + AMQP_URL=amqp://guest:guest@localhost/"$CHAIN_NAME"/0 \ + "${BINARY_DIR}"/bin/chain-executor-mock \ + -m "${SOURCE_DIR}"/tests/interfaces/config/blockchain.yaml + echo "DONE" + + echo -n "4) check mock data ... " + python3 "${SOURCE_DIR}"/tests/interfaces/rpc_test_runner.py \ + --rpc-url http://127.0.0.1:1337 \ + --directory "${SOURCE_DIR}"/tests/jsondata/rpc/ + echo "DONE" +} + +main "$@" From 0b5d1607381a3881079f0e4d29fae0d719091254 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 16:48:40 +0800 Subject: [PATCH 34/91] Refactor snapshot test. [skip travis] --- tests/integrate_test/cita_snapshot_test.sh | 210 ++++++++++----------- 1 file changed, 100 insertions(+), 110 deletions(-) diff --git a/tests/integrate_test/cita_snapshot_test.sh b/tests/integrate_test/cita_snapshot_test.sh index 02bde39df..9ec526ffa 100755 --- a/tests/integrate_test/cita_snapshot_test.sh +++ b/tests/integrate_test/cita_snapshot_test.sh @@ -2,121 +2,111 @@ # Set bash environment set -e -if [[ `uname` == 'Darwin' ]] +if [[ $(uname) == 'Darwin' ]] then - SOURCE_DIR=$(realpath $(dirname $0)/../..) - SED="gsed" + SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) else - SOURCE_DIR=$(readlink -f $(dirname $0)/../..) - SED="sed" + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) fi # Set CITA system environment BINARY_DIR=${SOURCE_DIR}/target/install -CHAIN_NAME="mock-chain" -SUPER_ADMIN="0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" - -################################################################################ -echo "0) Prepare ..." -source "${SOURCE_DIR}/tests/integrate_test/util.sh" -cd "${BINARY_DIR}" -echo "DONE" - -################################################################################ -echo "1) Generate CITA configurations ..." -${BINARY_DIR}/scripts/create_cita_config.py create \ - --nodes "127.0.0.1:4000,127.0.0.1:4001,127.0.0.1:4002,127.0.0.1:4003" \ - --super_admin "${SUPER_ADMIN}" \ - --chain_name "${CHAIN_NAME}" \ - --timestamp 1524000000 -echo "DONE" - -################################################################################ -echo "2) Run node-0, node-1, node-2" -for id in {0,1,2}; do - ${BINARY_DIR}/bin/cita bebop setup ${CHAIN_NAME}/${id} > /dev/null -done -for id in {0,1,2}; do - ${BINARY_DIR}/bin/cita bebop start ${CHAIN_NAME}/${id} trace -done -echo "DONE" - -################################################################################ -echo "3) Check all nodes grow up ..." -for id in {0..2}; do - echo "chech_height_growth_normal $id ..." - timeout=`check_height_growth_normal $id 60`||(echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -done -echo "${timeout}s DONE" - -################################################################################ -echo "4) Stop node-1 and node-2, so that node-0 cannot grow up via cita-consensus and cita-sync mechanisms" -${BINARY_DIR}/bin/cita bebop stop ${CHAIN_NAME}/1 -${BINARY_DIR}/bin/cita bebop stop ${CHAIN_NAME}/2 - -# Ensure that the current round of BFT has been finished. So that node-0 will -# not continue growing up, which means its height stay the same. -sleep 3 -echo "DONE" - -################################################################################ -echo "5) Take snapshot on node-0 at height {0, 2, 100000} ..." -for height in {0,2,10000}; do - cd ${BINARY_DIR}/${CHAIN_NAME}/0 - ${BINARY_DIR}/bin/snapshot_tool \ - --cmd snapshot \ - --file snapshot-test-${height} \ - --end_height ${height} || ( - echo "FAILED" - echo "error msg: fail to take snapshot at ${height}" - exit 1) -done - -cd "${BINARY_DIR}" -echo "DONE" - -################################################################################ -echo "6) Restore snapshot on node-0 ..." -before_height=`get_height 0` -for height in {10000,2,0,10000,2,0}; do - cd ${BINARY_DIR}/${CHAIN_NAME}/0 - echo "restoring with before_height=${before_height}, height=${height} ..." - - ${BINARY_DIR}/bin/snapshot_tool \ - --cmd restore \ - --file snapshot-test-${height} || ( - echo "FAILED" - echo "error msg: fail to restore snapshot to ${height}" - exit 1) - - case $height in - 0) expect_height=${before_height};; - 2) expect_height=2;; - 10000) expect_height=${before_height};; - esac - - current_height=`get_height 0` - if [ "${current_height}" != "${expect_height}" ]; then - echo "FAILED: expect_height(${expect_height})!= current_height(${current_height})" - exit 1 - fi -done - -cd "${BINARY_DIR}" -echo "DONE" - -################################################################################ -echo "7) Start node-1 and node-2 and check all grow up ..." -${BINARY_DIR}/bin/cita bebop start ${CHAIN_NAME}/1 trace -${BINARY_DIR}/bin/cita bebop start ${CHAIN_NAME}/2 trace - -wait_timeout=30 -timeout=`check_height_growth_normal 1 $wait_timeout` || (echo "FAILED" - echo "error msg: ${timeout}" - exit 1) -timeout=`check_height_growth_normal 0 $wait_timeout` || (echo "FAILED" + +main() { + echo "0) Prepare ..." + # shellcheck source=/dev/null + source "${SOURCE_DIR}/tests/integrate_test/util.sh" + cd "${BINARY_DIR}" + echo "DONE" + + echo "1) Generate configurations ..." + create_config --timestamp 1524000000 + echo "DONE" + + echo "2) Run node-0, node-1, node-2" + for id in {0,1,2}; do + "${BINARY_DIR}"/bin/cita bebop setup "${CHAIN_NAME}"/${id} > /dev/null + done + for id in {0,1,2}; do + "${BINARY_DIR}"/bin/cita bebop start "${CHAIN_NAME}"/${id} + done + echo "DONE" + + echo "3) Check all nodes grow up ..." + for id in {0..2}; do + echo "chech_height_growth_normal $id ..." + timeout=$(check_height_growth_normal $id 60) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) -echo "DONE" + done + echo "${timeout}s DONE" + + echo "4) Stop node-1 and node-2, so that node-0 cannot grow up via cita-consensus and cita-sync mechanisms" + "${BINARY_DIR}"/bin/cita bebop stop "${CHAIN_NAME}"/1 + "${BINARY_DIR}"/bin/cita bebop stop "${CHAIN_NAME}"/2 + + # Ensure that the current round of BFT has been finished. So that node-0 will + # not continue growing up, which means its height stay the same. + sleep 3 + echo "DONE" + + echo "5) Take snapshot on node-0 at height {0, 2, 100000} ..." + for height in {0,2,10000}; do + cd "${BINARY_DIR}"/"${CHAIN_NAME}"/0 + "${BINARY_DIR}"/bin/snapshot_tool \ + --cmd snapshot \ + --file snapshot-test-${height} \ + --end_height ${height} || ( + echo "FAILED" + echo "error msg: fail to take snapshot at ${height}" + exit 1) + done + + cd "${BINARY_DIR}" + echo "DONE" + + echo "6) Restore snapshot on node-0 ..." + before_height=$(get_height 0) + for height in {10000,2,0,10000,2,0}; do + cd "${BINARY_DIR}"/"${CHAIN_NAME}"/0 + echo "restoring with before_height=${before_height}, height=${height} ..." + + "${BINARY_DIR}"/bin/snapshot_tool \ + --cmd restore \ + --file snapshot-test-${height} || ( + echo "FAILED" + echo "error msg: fail to restore snapshot to ${height}" + exit 1) + + case $height in + 0) expect_height=${before_height};; + 2) expect_height=2;; + 10000) expect_height=${before_height};; + esac + + current_height=$(get_height 0) + if [ "${current_height}" != "${expect_height}" ]; then + echo "FAILED: expect_height(${expect_height})!= current_height(${current_height})" + exit 1 + fi + done + + cd "${BINARY_DIR}" + echo "DONE" + + echo "7) Start node-1 and node-2 and check all grow up ..." + for id in {1,2}; do + "${BINARY_DIR}"/bin/cita bebop start "${CHAIN_NAME}"/${id} + done + + wait_timeout=30 + for id in {0,1}; do + timeout=$(check_height_growth_normal ${id} $wait_timeout) || (echo "FAILED" + echo "error msg: ${timeout}" + exit 1) + done + + echo "DONE" +} + +main "$@" From d05dda216f1143bc41334b0c45c8d55d6fc5c60f Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 20:12:22 +0800 Subject: [PATCH 35/91] Update cita-auth for Rust 2018 edition. --- cita-auth/Cargo.toml | 1 + cita-auth/src/block_txn.rs | 4 ++-- cita-auth/src/dispatcher.rs | 4 ++-- cita-auth/src/handler.rs | 10 +++++----- cita-auth/src/main.rs | 13 ------------- 5 files changed, 10 insertions(+), 22 deletions(-) diff --git a/cita-auth/Cargo.toml b/cita-auth/Cargo.toml index e263b2dc7..47abcd2fb 100644 --- a/cita-auth/Cargo.toml +++ b/cita-auth/Cargo.toml @@ -2,6 +2,7 @@ name = "cita-auth" version = "0.1.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] clap = "2" diff --git a/cita-auth/src/block_txn.rs b/cita-auth/src/block_txn.rs index 7ed6c85e4..5cf1c58fe 100644 --- a/cita-auth/src/block_txn.rs +++ b/cita-auth/src/block_txn.rs @@ -15,9 +15,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::handler::verify_tx_sig; +use crate::hashable::Hashable; use cita_types::H256; -use handler::verify_tx_sig; -use hashable::Hashable; use libproto::TryInto; use libproto::{BlockTxn, GetBlockTxn, Origin, SignedTransaction}; use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator}; diff --git a/cita-auth/src/dispatcher.rs b/cita-auth/src/dispatcher.rs index fcbc2acf6..fde131ac0 100644 --- a/cita-auth/src/dispatcher.rs +++ b/cita-auth/src/dispatcher.rs @@ -15,9 +15,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::handler::SysConfigInfo; +use crate::txwal::TxWal; use cita_types::traits::LowerHex; use cita_types::{Address, H256}; -use handler::SysConfigInfo; use libproto::blockchain::{AccountGasLimit, BlockBody, BlockTxs, SignedTransaction}; use libproto::router::{MsgType, RoutingKey, SubModules}; use libproto::Message; @@ -28,7 +29,6 @@ use std::collections::HashSet; use std::convert::Into; use std::thread; use tx_pool; -use txwal::TxWal; pub struct Dispatcher { txs_pool: RefCell, diff --git a/cita-auth/src/handler.rs b/cita-auth/src/handler.rs index 162605594..c1b560e38 100644 --- a/cita-auth/src/handler.rs +++ b/cita-auth/src/handler.rs @@ -15,14 +15,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use block_txn::{BlockTxnMessage, BlockTxnReq}; -use block_verify::BlockVerify; +use crate::block_txn::{BlockTxnMessage, BlockTxnReq}; +use crate::block_verify::BlockVerify; +use crate::dispatcher::Dispatcher; +use crate::history::HistoryHeights; +use crate::transaction_verify::Error; use cita_types::traits::LowerHex; use cita_types::{clean_0x, Address, H256, U256}; use crypto::{pubkey_to_address, PubKey, Sign, Signature, SIGNATURE_BYTES_LEN}; -use dispatcher::Dispatcher; use error::ErrorCode; -use history::HistoryHeights; use jsonrpc_types::rpc_types::TxResponse; use libproto::auth::{Miscellaneous, MiscellaneousReq}; use libproto::blockchain::{AccountGasLimit, SignedTransaction}; @@ -42,7 +43,6 @@ use std::collections::{HashMap, HashSet}; use std::convert::Into; use std::str::FromStr; use std::time::Duration; -use transaction_verify::Error; use util::BLOCKLIMIT; const TX_OK: &str = "OK"; diff --git a/cita-auth/src/main.rs b/cita-auth/src/main.rs index 7ae31f4ec..5de961cd1 100644 --- a/cita-auth/src/main.rs +++ b/cita-auth/src/main.rs @@ -69,35 +69,22 @@ //! extern crate cita_crypto as crypto; -extern crate cita_directories; -extern crate cita_types; -extern crate clap; extern crate core as chain_core; -extern crate cpuprofiler; -extern crate dotenv; -extern crate error; -extern crate jsonrpc_types; #[macro_use] extern crate libproto; #[macro_use] extern crate cita_logger as logger; -extern crate lru; -extern crate pubsub; #[cfg(test)] #[macro_use] extern crate quickcheck; -extern crate rayon; #[macro_use] extern crate serde_derive; -extern crate serde_json; #[cfg(test)] extern crate tempfile; -extern crate tx_pool; #[macro_use] extern crate util; extern crate db as cita_db; extern crate hashable; -extern crate uuid; use batch_forward::BatchForward; use clap::App; From 7a5aa1af809c6597848753487854bff0cf8c8ef3 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 20:15:10 +0800 Subject: [PATCH 36/91] Update create_key_addr for Rust 2018 edition. --- tools/create_key_addr/Cargo.toml | 1 + tools/create_key_addr/src/main.rs | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/create_key_addr/Cargo.toml b/tools/create_key_addr/Cargo.toml index 7dabe5146..c125f562e 100644 --- a/tools/create_key_addr/Cargo.toml +++ b/tools/create_key_addr/Cargo.toml @@ -2,6 +2,7 @@ name = "create_key_addr" version = "0.1.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] cita-crypto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/tools/create_key_addr/src/main.rs b/tools/create_key_addr/src/main.rs index 9bdd40189..c47e69f7b 100644 --- a/tools/create_key_addr/src/main.rs +++ b/tools/create_key_addr/src/main.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -16,9 +16,8 @@ // along with this program. If not, see . extern crate cita_crypto as crypto; -extern crate hashable; -use crypto::{CreateKey, KeyPair, PubKey}; +use crate::crypto::{CreateKey, KeyPair, PubKey}; use hashable::Hashable; use std::env; use std::fs::{File, OpenOptions}; From c28b96a615ec9f0549efddaf97bf7b448eeeda25 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 20:21:02 +0800 Subject: [PATCH 37/91] Update snapshot tool for Rust 2018 editon. [skip travis] --- tools/snapshot_tool/Cargo.toml | 1 + tools/snapshot_tool/src/main.rs | 7 +------ 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/tools/snapshot_tool/Cargo.toml b/tools/snapshot_tool/Cargo.toml index c5d47b18d..21ce6b57a 100644 --- a/tools/snapshot_tool/Cargo.toml +++ b/tools/snapshot_tool/Cargo.toml @@ -2,6 +2,7 @@ name = "snapshot_tool" version = "0.2.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] dotenv = "0.13.0" diff --git a/tools/snapshot_tool/src/main.rs b/tools/snapshot_tool/src/main.rs index 7cb3c3474..a27473617 100644 --- a/tools/snapshot_tool/src/main.rs +++ b/tools/snapshot_tool/src/main.rs @@ -15,22 +15,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -extern crate clap; -extern crate dotenv; -extern crate error; -extern crate fs2; #[macro_use] extern crate libproto; #[macro_use] extern crate cita_logger as logger; -extern crate pubsub; #[macro_use] extern crate util; +use crate::postman::Postman; use clap::App; use fs2::FileExt; use libproto::router::{MsgType, RoutingKey, SubModules}; -use postman::Postman; use pubsub::channel; use pubsub::start_pubsub; use std::fs::{self, File, OpenOptions}; From d667af9047f82031fff8314c107ed6bbf7030447 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 5 Jun 2019 18:30:19 +0800 Subject: [PATCH 38/91] Add naming style doc. [skip ci] --- style-guide/naming.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 style-guide/naming.md diff --git a/style-guide/naming.md b/style-guide/naming.md new file mode 100644 index 000000000..5ba614f6d --- /dev/null +++ b/style-guide/naming.md @@ -0,0 +1,17 @@ +# Naming Style Guide + +## Filenames + +1. First rule: Follow the rules of programming language community(Rust, Python, JavaScript, Shell, Solidity) +2. Second rule: Follow the [google-style] + +------------- + +# 命名风格指南 + +## 文件名称 + +1. 第一原则: 使用各个编程语言社区的规范(Rust, Python, JavaScript, Shell, Solidity) +2. 第二原则: 与 [google-style] 保持一致 + +[google-style]: https://developers.google.com/style/filenames From f365834cd5783797bd52993f8ecf2e2250cdc522 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Thu, 6 Jun 2019 10:13:40 +0800 Subject: [PATCH 39/91] Follow file naming style. [skip travis] --- Cargo.lock | 10 +++++----- Cargo.toml | 10 +++++----- release_guide.md => release-guide.md | 0 scripts/create_cita_config.py | 2 +- scripts/release.sh | 6 +++--- style-guide/{JavaScript.md => js.md} | 0 style-guide/{Python.md => python.md} | 0 style-guide/{Rust.md => rust.md} | 0 style-guide/{Shell.md => shell.md} | 0 style-guide/{Solidity.md => solidity.md} | 0 tests/{box_executor => box-executor}/Cargo.toml | 2 +- tests/{box_executor => box-executor}/README.md | 0 tests/{box_executor => box-executor}/src/config.rs | 0 .../src/generate_block.rs | 0 tests/{box_executor => box-executor}/src/main.rs | 0 tests/{box_executor => box-executor}/src/runner.rs | 0 .../Cargo.toml | 2 +- .../README.md | 0 .../Test.sol | 0 .../src/generate_block.rs | 0 .../src/main.rs | 0 tests/integrate_test/cita_crosschain.sh | 2 +- tests/integrate_test/cita_snapshot_test.sh | 4 ++-- tests/{json_test => json-test}/Cargo.toml | 2 +- tests/{json_test => json-test}/README.md | 0 tests/{json_test => json-test}/src/helper.rs | 0 tests/{json_test => json-test}/src/json/mod.rs | 0 tests/{json_test => json-test}/src/json/state.rs | 0 tests/{json_test => json-test}/src/json/vm.rs | 0 tests/{json_test => json-test}/src/lib.rs | 0 tests/{json_test => json-test}/src/state_test.rs | 0 tests/{json_test => json-test}/src/vm_test.rs | 0 tools/{create_key_addr => create-key-addr}/Cargo.toml | 2 +- tools/{create_key_addr => create-key-addr}/src/main.rs | 0 tools/{snapshot_tool => snapshot-tool}/Cargo.toml | 2 +- tools/{snapshot_tool => snapshot-tool}/src/main.rs | 0 tools/{snapshot_tool => snapshot-tool}/src/postman.rs | 0 37 files changed, 22 insertions(+), 22 deletions(-) rename release_guide.md => release-guide.md (100%) rename style-guide/{JavaScript.md => js.md} (100%) rename style-guide/{Python.md => python.md} (100%) rename style-guide/{Rust.md => rust.md} (100%) rename style-guide/{Shell.md => shell.md} (100%) rename style-guide/{Solidity.md => solidity.md} (100%) rename tests/{box_executor => box-executor}/Cargo.toml (98%) rename tests/{box_executor => box-executor}/README.md (100%) rename tests/{box_executor => box-executor}/src/config.rs (100%) rename tests/{box_executor => box-executor}/src/generate_block.rs (100%) rename tests/{box_executor => box-executor}/src/main.rs (100%) rename tests/{box_executor => box-executor}/src/runner.rs (100%) rename tests/{chain_performance_by_mq => chain-performance-by-mq}/Cargo.toml (97%) rename tests/{chain_performance_by_mq => chain-performance-by-mq}/README.md (100%) rename tests/{chain_performance_by_mq => chain-performance-by-mq}/Test.sol (100%) rename tests/{chain_performance_by_mq => chain-performance-by-mq}/src/generate_block.rs (100%) rename tests/{chain_performance_by_mq => chain-performance-by-mq}/src/main.rs (100%) rename tests/{json_test => json-test}/Cargo.toml (96%) rename tests/{json_test => json-test}/README.md (100%) rename tests/{json_test => json-test}/src/helper.rs (100%) rename tests/{json_test => json-test}/src/json/mod.rs (100%) rename tests/{json_test => json-test}/src/json/state.rs (100%) rename tests/{json_test => json-test}/src/json/vm.rs (100%) rename tests/{json_test => json-test}/src/lib.rs (100%) rename tests/{json_test => json-test}/src/state_test.rs (100%) rename tests/{json_test => json-test}/src/vm_test.rs (100%) rename tools/{create_key_addr => create-key-addr}/Cargo.toml (95%) rename tools/{create_key_addr => create-key-addr}/src/main.rs (100%) rename tools/{snapshot_tool => snapshot-tool}/Cargo.toml (97%) rename tools/{snapshot_tool => snapshot-tool}/src/main.rs (100%) rename tools/{snapshot_tool => snapshot-tool}/src/postman.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index c2c0ced71..d273222f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -310,7 +310,7 @@ dependencies = [ ] [[package]] -name = "box_executor" +name = "box-executor" version = "0.1.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -409,7 +409,7 @@ dependencies = [ ] [[package]] -name = "chain_performance_by_mq" +name = "chain-performance-by-mq" version = "0.1.0" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -953,7 +953,7 @@ dependencies = [ ] [[package]] -name = "create_key_addr" +name = "create-key-addr" version = "0.1.0" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -3165,7 +3165,7 @@ dependencies = [ ] [[package]] -name = "snapshot_tool" +name = "snapshot-tool" version = "0.2.0" dependencies = [ "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3199,7 +3199,7 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "state_test" +name = "state-test" version = "0.1.0" dependencies = [ "core-executor 0.1.0", diff --git a/Cargo.toml b/Cargo.toml index 4357df88a..6e7734f30 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,14 +6,14 @@ members = ["cita-auth" ,"cita-network" ,"cita-executor" ,"cita-forever" -,"tools/create_key_addr" -,"tools/snapshot_tool" +,"tools/create-key-addr" +,"tools/snapshot-tool" ,"tools/relayer-parser" ,"tests/chain-executor-mock" ,"tests/consensus-mock" -,"tests/chain_performance_by_mq" -,"tests/box_executor" -,"tests/json_test" +,"tests/chain-performance-by-mq" +,"tests/box-executor" +,"tests/json-test" ] [profile.bench] diff --git a/release_guide.md b/release-guide.md similarity index 100% rename from release_guide.md rename to release-guide.md diff --git a/scripts/create_cita_config.py b/scripts/create_cita_config.py index 53bf0a9e6..032634ef5 100755 --- a/scripts/create_cita_config.py +++ b/scripts/create_cita_config.py @@ -60,7 +60,7 @@ def generate_keypairs(amount): privkeys = list() _, address_path = tempfile.mkstemp() _, secret_path = tempfile.mkstemp() - cmd = 'create_key_addr "{}" "{}"'.format(secret_path, address_path) + cmd = 'create-key-addr "{}" "{}"'.format(secret_path, address_path) for _ in range(0, amount): os.system(cmd) with open(address_path, 'rt') as stream: diff --git a/scripts/release.sh b/scripts/release.sh index 713831751..f3c09758a 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -30,12 +30,12 @@ for binary in \ cita-forever \ cita-jsonrpc \ cita-network \ - create_key_addr \ + create-key-addr \ cita-relayer-parser \ - snapshot_tool \ + snapshot-tool \ consensus-mock \ chain-executor-mock \ - box_executor \ + box-executor \ ; do cp -rf "target/${type}/${binary}" target/install/bin/ done diff --git a/style-guide/JavaScript.md b/style-guide/js.md similarity index 100% rename from style-guide/JavaScript.md rename to style-guide/js.md diff --git a/style-guide/Python.md b/style-guide/python.md similarity index 100% rename from style-guide/Python.md rename to style-guide/python.md diff --git a/style-guide/Rust.md b/style-guide/rust.md similarity index 100% rename from style-guide/Rust.md rename to style-guide/rust.md diff --git a/style-guide/Shell.md b/style-guide/shell.md similarity index 100% rename from style-guide/Shell.md rename to style-guide/shell.md diff --git a/style-guide/Solidity.md b/style-guide/solidity.md similarity index 100% rename from style-guide/Solidity.md rename to style-guide/solidity.md diff --git a/tests/box_executor/Cargo.toml b/tests/box-executor/Cargo.toml similarity index 98% rename from tests/box_executor/Cargo.toml rename to tests/box-executor/Cargo.toml index 1d6b442c6..eb53dd171 100644 --- a/tests/box_executor/Cargo.toml +++ b/tests/box-executor/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "box_executor" +name = "box-executor" version = "0.1.0" authors = ["Cryptape Technologies "] diff --git a/tests/box_executor/README.md b/tests/box-executor/README.md similarity index 100% rename from tests/box_executor/README.md rename to tests/box-executor/README.md diff --git a/tests/box_executor/src/config.rs b/tests/box-executor/src/config.rs similarity index 100% rename from tests/box_executor/src/config.rs rename to tests/box-executor/src/config.rs diff --git a/tests/box_executor/src/generate_block.rs b/tests/box-executor/src/generate_block.rs similarity index 100% rename from tests/box_executor/src/generate_block.rs rename to tests/box-executor/src/generate_block.rs diff --git a/tests/box_executor/src/main.rs b/tests/box-executor/src/main.rs similarity index 100% rename from tests/box_executor/src/main.rs rename to tests/box-executor/src/main.rs diff --git a/tests/box_executor/src/runner.rs b/tests/box-executor/src/runner.rs similarity index 100% rename from tests/box_executor/src/runner.rs rename to tests/box-executor/src/runner.rs diff --git a/tests/chain_performance_by_mq/Cargo.toml b/tests/chain-performance-by-mq/Cargo.toml similarity index 97% rename from tests/chain_performance_by_mq/Cargo.toml rename to tests/chain-performance-by-mq/Cargo.toml index fdc7be9d1..65ff1b600 100644 --- a/tests/chain_performance_by_mq/Cargo.toml +++ b/tests/chain-performance-by-mq/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "chain_performance_by_mq" +name = "chain-performance-by-mq" version = "0.1.0" authors = ["Cryptape Technologies "] diff --git a/tests/chain_performance_by_mq/README.md b/tests/chain-performance-by-mq/README.md similarity index 100% rename from tests/chain_performance_by_mq/README.md rename to tests/chain-performance-by-mq/README.md diff --git a/tests/chain_performance_by_mq/Test.sol b/tests/chain-performance-by-mq/Test.sol similarity index 100% rename from tests/chain_performance_by_mq/Test.sol rename to tests/chain-performance-by-mq/Test.sol diff --git a/tests/chain_performance_by_mq/src/generate_block.rs b/tests/chain-performance-by-mq/src/generate_block.rs similarity index 100% rename from tests/chain_performance_by_mq/src/generate_block.rs rename to tests/chain-performance-by-mq/src/generate_block.rs diff --git a/tests/chain_performance_by_mq/src/main.rs b/tests/chain-performance-by-mq/src/main.rs similarity index 100% rename from tests/chain_performance_by_mq/src/main.rs rename to tests/chain-performance-by-mq/src/main.rs diff --git a/tests/integrate_test/cita_crosschain.sh b/tests/integrate_test/cita_crosschain.sh index 5e303e569..b9da053cf 100755 --- a/tests/integrate_test/cita_crosschain.sh +++ b/tests/integrate_test/cita_crosschain.sh @@ -494,7 +494,7 @@ function main () { title "Create side chain keys ..." for ((id=0;id<4;id++)); do - bin/create_key_addr secret${id} address${id} + bin/create-key-addr secret${id} address${id} done local side_auths=$(ls address[0-4] | sort | xargs -I {} cat {} \ | tr '\n' ',' | rev | cut -c 2- | rev) diff --git a/tests/integrate_test/cita_snapshot_test.sh b/tests/integrate_test/cita_snapshot_test.sh index 9ec526ffa..d46e91457 100755 --- a/tests/integrate_test/cita_snapshot_test.sh +++ b/tests/integrate_test/cita_snapshot_test.sh @@ -53,7 +53,7 @@ main() { echo "5) Take snapshot on node-0 at height {0, 2, 100000} ..." for height in {0,2,10000}; do cd "${BINARY_DIR}"/"${CHAIN_NAME}"/0 - "${BINARY_DIR}"/bin/snapshot_tool \ + "${BINARY_DIR}"/bin/snapshot-tool \ --cmd snapshot \ --file snapshot-test-${height} \ --end_height ${height} || ( @@ -71,7 +71,7 @@ main() { cd "${BINARY_DIR}"/"${CHAIN_NAME}"/0 echo "restoring with before_height=${before_height}, height=${height} ..." - "${BINARY_DIR}"/bin/snapshot_tool \ + "${BINARY_DIR}"/bin/snapshot-tool \ --cmd restore \ --file snapshot-test-${height} || ( echo "FAILED" diff --git a/tests/json_test/Cargo.toml b/tests/json-test/Cargo.toml similarity index 96% rename from tests/json_test/Cargo.toml rename to tests/json-test/Cargo.toml index 41a4e879f..98d687ba1 100644 --- a/tests/json_test/Cargo.toml +++ b/tests/json-test/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "state_test" +name = "state-test" version = "0.1.0" authors = ["Cryptape Technologies "] edition = "2018" diff --git a/tests/json_test/README.md b/tests/json-test/README.md similarity index 100% rename from tests/json_test/README.md rename to tests/json-test/README.md diff --git a/tests/json_test/src/helper.rs b/tests/json-test/src/helper.rs similarity index 100% rename from tests/json_test/src/helper.rs rename to tests/json-test/src/helper.rs diff --git a/tests/json_test/src/json/mod.rs b/tests/json-test/src/json/mod.rs similarity index 100% rename from tests/json_test/src/json/mod.rs rename to tests/json-test/src/json/mod.rs diff --git a/tests/json_test/src/json/state.rs b/tests/json-test/src/json/state.rs similarity index 100% rename from tests/json_test/src/json/state.rs rename to tests/json-test/src/json/state.rs diff --git a/tests/json_test/src/json/vm.rs b/tests/json-test/src/json/vm.rs similarity index 100% rename from tests/json_test/src/json/vm.rs rename to tests/json-test/src/json/vm.rs diff --git a/tests/json_test/src/lib.rs b/tests/json-test/src/lib.rs similarity index 100% rename from tests/json_test/src/lib.rs rename to tests/json-test/src/lib.rs diff --git a/tests/json_test/src/state_test.rs b/tests/json-test/src/state_test.rs similarity index 100% rename from tests/json_test/src/state_test.rs rename to tests/json-test/src/state_test.rs diff --git a/tests/json_test/src/vm_test.rs b/tests/json-test/src/vm_test.rs similarity index 100% rename from tests/json_test/src/vm_test.rs rename to tests/json-test/src/vm_test.rs diff --git a/tools/create_key_addr/Cargo.toml b/tools/create-key-addr/Cargo.toml similarity index 95% rename from tools/create_key_addr/Cargo.toml rename to tools/create-key-addr/Cargo.toml index c125f562e..b7eae4c06 100644 --- a/tools/create_key_addr/Cargo.toml +++ b/tools/create-key-addr/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "create_key_addr" +name = "create-key-addr" version = "0.1.0" authors = ["Cryptape Technologies "] edition = "2018" diff --git a/tools/create_key_addr/src/main.rs b/tools/create-key-addr/src/main.rs similarity index 100% rename from tools/create_key_addr/src/main.rs rename to tools/create-key-addr/src/main.rs diff --git a/tools/snapshot_tool/Cargo.toml b/tools/snapshot-tool/Cargo.toml similarity index 97% rename from tools/snapshot_tool/Cargo.toml rename to tools/snapshot-tool/Cargo.toml index 21ce6b57a..3743ba7a3 100644 --- a/tools/snapshot_tool/Cargo.toml +++ b/tools/snapshot-tool/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "snapshot_tool" +name = "snapshot-tool" version = "0.2.0" authors = ["Cryptape Technologies "] edition = "2018" diff --git a/tools/snapshot_tool/src/main.rs b/tools/snapshot-tool/src/main.rs similarity index 100% rename from tools/snapshot_tool/src/main.rs rename to tools/snapshot-tool/src/main.rs diff --git a/tools/snapshot_tool/src/postman.rs b/tools/snapshot-tool/src/postman.rs similarity index 100% rename from tools/snapshot_tool/src/postman.rs rename to tools/snapshot-tool/src/postman.rs From a32498684ccbb0630441940670a2aa8515d8b211 Mon Sep 17 00:00:00 2001 From: RainChen Date: Mon, 10 Jun 2019 12:15:49 +0800 Subject: [PATCH 40/91] fix: fix cita.sh for NODE_PATH should not consider CITA_BIN path --- scripts/cita.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/cita.sh b/scripts/cita.sh index feb72cb52..05bcbadc0 100755 --- a/scripts/cita.sh +++ b/scripts/cita.sh @@ -32,7 +32,7 @@ SERVICES=( forever auth bft chain executor jsonrpc network ) SCRIPT=$(basename "$0") COMMAND=$1 NODE_NAME=$2 -NODE_PATH="$(dirname "$CITA_BIN")/${NODE_NAME}" +NODE_PATH=$(realpath "${NODE_NAME}") NODE_LOGS_DIR="${NODE_PATH}/logs" NODE_DATA_DIR="${NODE_PATH}/data" TNODE=$(echo "${NODE_NAME}" | sed 's/\//%2f/g') From d678f50e89d1916f4ed2c85b7857526da98e6fda Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 10 Jun 2019 10:57:23 +0800 Subject: [PATCH 41/91] Refactor the cita shell script. * Add main funtion * Add parse command funtion * Chore --- scripts/cita.sh | 326 +++++++++++++++++++++++++----------------------- 1 file changed, 167 insertions(+), 159 deletions(-) diff --git a/scripts/cita.sh b/scripts/cita.sh index 05bcbadc0..efa22f645 100755 --- a/scripts/cita.sh +++ b/scripts/cita.sh @@ -2,42 +2,25 @@ # -*- tab-width:4;indent-tabs-mode:nil -*- # ex: ts=4 sw=4 et +# Exit immediately if a command exits with a non-zero status +set -e + # Commands Paths if [[ $(uname) == 'Darwin' ]]; then CITA_BIN=$(dirname "$(realpath "$0")") else CITA_BIN=$(dirname "$(readlink -f "$0")") fi -CITA_SCRIPTS=$(dirname "$CITA_BIN")/scripts - -if [ "$1" != "bebop" ]; then - if stat "$CITA_BIN"/cita-env > /dev/null 2>&1; then - "$CITA_BIN"/cita-env bin/cita bebop "$@" - else - echo -e "\033[0;31mPlease run this command after build 🎨" - echo -e "\033[0;32mRun \`cita bebop\` to preview help! 🎸 \033[0m\n" - fi - exit 0 -fi - -# Delete the verbose parameters -set -- "${@:2}" - -# Exit immediately if a command exits with a non-zero status -set -e # Add cita scripts into system executable paths export PATH=$CITA_BIN:$PATH +CITA_SCRIPTS=$(dirname "$CITA_BIN")/scripts SERVICES=( forever auth bft chain executor jsonrpc network ) SCRIPT=$(basename "$0") -COMMAND=$1 -NODE_NAME=$2 -NODE_PATH=$(realpath "${NODE_NAME}") -NODE_LOGS_DIR="${NODE_PATH}/logs" -NODE_DATA_DIR="${NODE_PATH}/data" -TNODE=$(echo "${NODE_NAME}" | sed 's/\//%2f/g') - -sudo(){ +# DIAGNOSTIC COMMANDS +PING_STATUS="" + +sudo() { set -o noglob if [ "$(whoami)" == "root" ] ; then @@ -58,7 +41,6 @@ Run \`$SCRIPT help\` for more detailed information. EOF } - # INFORMATIONAL COMMANDS help() { cat < /dev/null 2>&1 @@ -340,16 +316,17 @@ do_logrotate() { } clear_rabbit_mq() { - MQ_COMMAND="curl -i -u guest:guest -H content-type:application/json -XDELETE http://localhost:15672/api/queues/${TNODE}" - - "$MQ_COMMAND"/auth > /dev/null 2>&1 || true - "$MQ_COMMAND"/chain > /dev/null 2>&1 || true - "$MQ_COMMAND"/consensus > /dev/null 2>&1 || true - "$MQ_COMMAND"/jsonrpc > /dev/null 2>&1 || true - "$MQ_COMMAND"/network > /dev/null 2>&1 || true - "$MQ_COMMAND"/network_tx > /dev/null 2>&1 || true - "$MQ_COMMAND"/network_consensus > /dev/null 2>&1 || true - "$MQ_COMMAND"/executor > /dev/null 2>&1 || true + local mq_command + local mq_command="curl -i -u guest:guest -H content-type:application/json -XDELETE http://localhost:15672/api/queues/${TNODE}" + + "$mq_command"/auth > /dev/null 2>&1 || true + "$mq_command"/chain > /dev/null 2>&1 || true + "$mq_command"/consensus > /dev/null 2>&1 || true + "$mq_command"/jsonrpc > /dev/null 2>&1 || true + "$mq_command"/network > /dev/null 2>&1 || true + "$mq_command"/network_tx > /dev/null 2>&1 || true + "$mq_command"/network_consensus > /dev/null 2>&1 || true + "$mq_command"/executor > /dev/null 2>&1 || true } node_down_check() { @@ -368,128 +345,159 @@ node_up_check() { fi } -# Commands not depend on $NODE_PATH -case "${COMMAND}" in - help) - help - exit 0 - ;; - - usage) - usage - exit 0 - ;; - - create) - create "$@" - exit 0 - ;; - - append) - append "$@" - exit 0 - ;; - -esac - -if [ $# -lt 2 ]; then - usage - exit 1 -fi - -# Make sure the node directory exists -if [ ! -d "${NODE_PATH}" ]; then - echo "No such node directory: ${NODE_NAME}" - exit 1 -elif [[ ! -e "${NODE_PATH}/forever.toml" && ! -e "${NODE_PATH}/forever_mock.toml" ]]; then - echo "'${NODE_NAME}' is not a ${SCRIPT} node directory" - exit 1 -fi - -# Enter the node directory -pushd . > /dev/null -cd "${NODE_PATH}" - -case "${COMMAND}" in - setup) - do_setup - ;; - - start) - do_stop # TODO: should not do so, but present tests need this - node_down_check - - # Make sure the RabbitMQ fresh - clear_rabbit_mq - - do_start "$3" "$4" - ;; - - stop) - node_up_check - do_stop - ;; +parse_command() { + local command="$1" + case "${command}" in + help) + help + exit 0 + ;; - restart) - node_up_check - do_stop + usage) + usage + exit 0 + ;; - # Make sure the RabbitMQ fresh - clear_rabbit_mq + create) + config "$@" + exit 0 + ;; - do_start "$3" "$4" - ;; + append) + config "$@" + exit 0 + ;; + + setup) + do_setup + ;; + + start) + # TODO: should not do so, but present tests need this + do_stop + node_down_check + + # Make sure the RabbitMQ fresh + clear_rabbit_mq + + do_start "$3" "$4" + ;; + + stop) + node_up_check + do_stop + ;; + + restart) + node_up_check + do_stop + + # Make sure the RabbitMQ fresh + clear_rabbit_mq + + do_start "$3" "$4" + ;; + + ping) + do_ping + if [ "${PING_STATUS}" == "pong" ]; then + echo "pong" + else + echo "Node '${NODE_NAME}' not responding to pings." + exit 1 + fi + ;; + + top) + node_up_check + do_top + ;; + # deprecated, use 'top' instead + stat) + node_up_check + do_top + ;; + # similar to 'top', but ... ? + status) + do_status + ;; + + logrotate) + do_logrotate + ;; + + logs) + do_logs "$3" + ;; + + backup) + node_down_check + do_backup + ;; + + clean) + node_down_check + do_clean + ;; + + *) + usage + ;; + + esac +} - ping) - do_ping - if [ "${PING_STATUS}" == "pong" ]; then - echo "pong" +main() { + if [ "$1" != "bebop" ]; then + if stat "$CITA_BIN"/cita-env > /dev/null 2>&1; then + "$CITA_BIN"/cita-env bin/cita bebop "$@" else - echo "Node '${NODE_NAME}' not responding to pings." - exit 1 + echo -e "\033[0;31mPlease run this command after build 🎨" + echo -e "\033[0;32mRun \`cita bebop\` to preview help! 🎸 \033[0m\n" fi - ;; + exit 0 + fi - top) - node_up_check - do_top - ;; + # Delete the verbose parameters + set -- "${@:2}" + local command=$1 - stat) # deprecated, use 'top' instead - node_up_check - do_top - ;; + # Commands not depend on $NODE_PATH + local indie=( help usage create append ) + if [[ "${indie[*]}" =~ $command ]]; then + parse_command "$@" + fi - status) # similar to 'top', but ... ? - do_status - ;; + # Commands depend on $NODE_PATH + if [ $# -lt 2 ]; then + usage + exit 1 + fi - logrotate) - do_logrotate - ;; + NODE_NAME=$2 + NODE_PATH=$(realpath "${NODE_NAME}") + NODE_LOGS_DIR="${NODE_PATH}/logs" + NODE_DATA_DIR="${NODE_PATH}/data" + TNODE=$(echo "${NODE_NAME}" | sed 's/\//%2f/g') - logs) - do_logs "$3" - ;; + # Make sure the node directory exists + if [ ! -d "${NODE_PATH}" ]; then + echo "No such node directory: ${NODE_NAME}" + exit 1 + elif [[ ! -e "${NODE_PATH}/forever.toml" && ! -e "${NODE_PATH}/forever_mock.toml" ]]; then + echo "'${NODE_NAME}' is not a ${SCRIPT} node directory" + exit 1 + fi - backup) - node_down_check - do_backup - ;; + # Enter the node directory + pushd . > /dev/null + cd "${NODE_PATH}" - clean) - node_down_check - do_clean - ;; + parse_command "$@" - help) - help - ;; + popd > /dev/null - *) - usage - ;; -esac -popd > /dev/null + exit 0 +} -exit 0 +main "$@" From 16d5c2a83767584f4aa063c22afa1564a562b88c Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 10 Jun 2019 15:11:50 +0800 Subject: [PATCH 42/91] Add test of checking cors of jsonrpc. [skip travis] --- tests/integrate_test/cita_basic.sh | 19 ++++-- tests/integrate_test/cita_jsonrpcTest.sh | 74 ------------------------ 2 files changed, 13 insertions(+), 80 deletions(-) delete mode 100755 tests/integrate_test/cita_jsonrpcTest.sh diff --git a/tests/integrate_test/cita_basic.sh b/tests/integrate_test/cita_basic.sh index 715fb8bf3..b40b5c24f 100755 --- a/tests/integrate_test/cita_basic.sh +++ b/tests/integrate_test/cita_basic.sh @@ -8,6 +8,8 @@ else SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) fi BINARY_DIR=${SOURCE_DIR}/target/install +IP="127.0.0.1" +PORT="1337" main() { echo -n "0) prepare ... " @@ -30,35 +32,40 @@ main() { exit 1) echo "${timeout}s DONE" - echo -n "4) stop node3, check height growth ... " + echo -n "4) check JSON-RPC CORS ... " + # Check JSON-RPC CORS: Access-Control-Allow-Origin should be existed. + curl -i -X POST -d '{"jsonrpc":"2.0","method":"peerCount","params":[],"id":2}' "$IP":"$PORT" 2>/dev/null | grep -ic "^access-control-allow-origin: " + echo "DONE" + + echo -n "5) stop node3, check height growth ... " bin/cita bebop stop $CHAIN_NAME/3 2>&1 timeout=$(check_height_growth_normal 0 30) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" - echo -n "5) stop node2, check height stopped ... " + echo -n "6) stop node2, check height stopped ... " bin/cita bebop stop $CHAIN_NAME/2 2>&1 timeout=$(check_height_stopped 0 30) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" - echo -n "6) start node2, check height growth ... " + echo -n "7) start node2, check height growth ... " bin/cita bebop start $CHAIN_NAME/2 2>&1 timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" - echo -n "7) start node3, check synch ... " + echo -n "8) start node3, check synch ... " bin/cita bebop start $CHAIN_NAME/3 2>&1 timeout=$(check_height_sync 3 0) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" - echo -n "8) stop all nodes, check height changed after restart ... " + echo -n "9) stop all nodes, check height changed after restart ... " for i in {0..3}; do bin/cita bebop restart $CHAIN_NAME/$i 2>&1 done @@ -68,7 +75,7 @@ main() { exit 1) echo "${timeout}s DONE" - echo -n "9) stop&clean node3, check height synch after restart ... " + echo -n "10) stop&clean node3, check height synch after restart ... " bin/cita bebop stop $CHAIN_NAME/3 2>&1 bin/cita bebop clean $CHAIN_NAME/3 2>&1 bin/cita bebop start $CHAIN_NAME/3 2>&1 diff --git a/tests/integrate_test/cita_jsonrpcTest.sh b/tests/integrate_test/cita_jsonrpcTest.sh deleted file mode 100755 index ab833f909..000000000 --- a/tests/integrate_test/cita_jsonrpcTest.sh +++ /dev/null @@ -1,74 +0,0 @@ -#!/bin/bash - -#echo "args: ip port" -IP=$1 -PORT=$2 -if [ ! -n "$IP" ]; then - IP="127.0.0.1" -fi -if [ ! -n "$PORT" ]; then - PORT=1337 -fi - -assert() { - if [ $1 -ne $2 ]; then - echo "$3 test failed" - ./cita_stop.sh - exit 1 - fi - echo "$3 test ok" -} - -assert_null() { - if [ "$1" != "null" ]; then - echo "$2 test failed" - ./cita_stop.sh - exit 1 - fi - echo "$2 test ok" -} - -invalid_http_method=-32600 -invalid_params=-32605 -invalid_data=-32600 -invalid_jsonrpc_method=-32601 - -./cita_start.sh - -# Check JSON-RPC CORS: Access-Control-Allow-Origin should be existed. -has_cors=$(curl -i -X POST -d '{"jsonrpc":"2.0","method":"peerCount","params":[],"id":2}' $IP:$PORT 2>/dev/null | grep -ic "^access-control-allow-origin: ") -assert ${has_cors} 1 "Check JSON-RPC CORS" - -## request of invalid http method -err_code=`curl -s -X GET -d '{"jsonrpc":"2.0","method":"peerCount","params":[],"id":2}' $IP:$PORT | jq ".error.code"` -assert $err_code $invalid_http_method "request of invalid http method" - -## invalid request of missing id -err_code=`curl -s -X POST -d '{"jsonrpc":"2.0","method":"peerCount","params":[]}' $IP:$PORT | jq ".error.code"` -assert $err_code $invalid_params "invalid request of missing id" - -## request of invalid json -err_code=`curl -s -X POST -d 'abc' $IP:$PORT | jq ".error.code"` -assert $err_code $invalid_params "request of invalid json" - -## invalid jsonrpc method -err_code=`curl -s -X POST -d '{"jsonrpc":"2.0","method":"invalid_method","params":[],"id":2}' $IP:$PORT | jq ".error.code"` -assert $err_code $invalid_jsonrpc_method "invalid jsonrpc method" - -## invalid request of missing params -err_code=`curl -s -X POST -d '{"jsonrpc":"2.0","method":"getTransaction","params":[],"id":2}' $IP:$PORT | jq ".error.code"` -assert $err_code $invalid_params "invalid request params" - -## get null block -result=`curl -s -X POST -d '{"jsonrpc":"2.0","method":"cita_getBlockByHeight","params":[9999999999999999,true],"id":2}' $IP:$PORT | jq ".error.code"` -assert_null $result "get null block" - -## get null transaction -result=`curl -s -X POST -d '{"jsonrpc":"2.0","method":"getTransaction","params":["0000000000000000000000000000000000000000000000000000000000000000"],"id":2}' $IP:$PORT | jq ".error.code"` -assert_null $result "get null transaction" - -## null block hash -result=`curl -s -X POST -d '{"jsonrpc":"2.0","method":"getBlockByHash","params":["0000000000000000000000000000000000000000000000000000000000000000",true],"id":2}' $IP:$PORT | jq ".error.code"` -assert_null $result "null block hash" - -./cita_stop.sh From cb863b5b2b457920cd661fe461e95caa41c88e96 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 10 Jun 2019 17:53:49 +0800 Subject: [PATCH 43/91] Fix the amend test failed occasionally. [skip travis] --- tests/integrate_test/cita_amend_test.sh | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/tests/integrate_test/cita_amend_test.sh b/tests/integrate_test/cita_amend_test.sh index e4ce73914..d3a5246fa 100755 --- a/tests/integrate_test/cita_amend_test.sh +++ b/tests/integrate_test/cita_amend_test.sh @@ -20,10 +20,9 @@ amend_chain_name() { --privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 > /dev/null python3 send_tx.py > /dev/null + python3 get_receipt.py --forever true - sleep 10 - - curl -X POST --data '{"jsonrpc":"2.0","method":"getMetaData","params":["latest"],"id":1}' 127.0.0.1:1337 \ + curl -X POST --data '{"jsonrpc":"2.0","method":"getMetaData","params":["pending"],"id":1}' 127.0.0.1:1337 \ | grep "\"chainName\"\:\"0est-chain\"" } @@ -36,11 +35,10 @@ amend_abi() { --privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 > /dev/null python3 send_tx.py > /dev/null - - sleep 10 + python3 get_receipt.py --forever true # ascii of "amendabitest" - curl -X POST --data '{"jsonrpc":"2.0","method":"getAbi","params":["0xffffffffffffffffffffffffffffffffff020000", "latest"],"id":1}' 127.0.0.1:1337 \ + curl -X POST --data '{"jsonrpc":"2.0","method":"getAbi","params":["0xffffffffffffffffffffffffffffffffff020000", "pending"],"id":1}' 127.0.0.1:1337 \ | grep "616d656e6461626974657374" } @@ -53,11 +51,10 @@ amend_balance() { --privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 > /dev/null python3 send_tx.py > /dev/null - - sleep 10 + python3 get_receipt.py --forever true # hex of 1234 - curl -X POST --data '{"jsonrpc":"2.0","method":"getBalance","params":["0xffffffffffffffffffffffffffffffffff020000", "latest"],"id":1}' 127.0.0.1:1337 \ + curl -X POST --data '{"jsonrpc":"2.0","method":"getBalance","params":["0xffffffffffffffffffffffffffffffffff020000", "pending"],"id":1}' 127.0.0.1:1337 \ | grep "0x4d2" } @@ -70,11 +67,10 @@ amend_code() { --privkey 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 > /dev/null python3 send_tx.py > /dev/null - - sleep 10 + python3 get_receipt.py --forever true # hex of 1234 - curl -X POST --data '{"jsonrpc":"2.0","method":"getCode","params":["0xffffffffffffffffffffffffffffffffff020004", "latest"],"id":1}' 127.0.0.1:1337 \ + curl -X POST --data '{"jsonrpc":"2.0","method":"getCode","params":["0xffffffffffffffffffffffffffffffffff020004", "pending"],"id":1}' 127.0.0.1:1337 \ | grep "0xdeadbeef" } From f728bcf8b64e8076d0b1ed0814f2c8b611b41c5e Mon Sep 17 00:00:00 2001 From: leeyr Date: Mon, 10 Jun 2019 22:03:36 +0800 Subject: [PATCH 44/91] Fix: add more test case for memory leak. --- cita-executor/src/postman.rs | 167 ++++++++++++++++++++++++++++------- 1 file changed, 136 insertions(+), 31 deletions(-) diff --git a/cita-executor/src/postman.rs b/cita-executor/src/postman.rs index c2b62774f..8b8316e2b 100644 --- a/cita-executor/src/postman.rs +++ b/cita-executor/src/postman.rs @@ -1114,48 +1114,160 @@ mod tests { } #[test] - fn test_update_rich_status_with_prune() { - let mut postman = helpers::generate_postman(6, Default::default()); + fn test_update_rich_status_0() { + let mut postman = helpers::generate_postman(5, Default::default()); - let execute_result_1 = generate_executed_result(1); - let execute_result_2 = generate_executed_result(2); - let execute_result_3 = generate_executed_result(3); - let execute_result_4 = generate_executed_result(4); + backlogs_prepare(&mut postman); - postman - .backlogs - .insert_completed_result(1, execute_result_1); - postman - .backlogs - .insert_completed_result(2, execute_result_2); - postman - .backlogs - .insert_completed_result(3, execute_result_3); - postman - .backlogs - .insert_completed_result(4, execute_result_4); + let mut rich_status = RichStatus::new(); + + rich_status.set_height(0); + + postman.update_by_rich_status(&rich_status); + + // block height in rich_status is from Chain, that means database's block height. + // block height in postman, that means executed block height which cache in Executor. + // Testcase 0: block_height[chain] = 0, block_height[executor] = 5. + // Expected: remove the block 0 from cache, but not other block. + assert!(postman.backlogs.get_completed_result(0).is_none()); + assert!(postman.backlogs.get_completed_result(1).is_some()); + assert!(postman.backlogs.get_completed_result(2).is_some()); + assert!(postman.backlogs.get_completed_result(3).is_some()); + assert!(postman.backlogs.get_completed_result(4).is_some()); + assert!(postman.backlogs.get_completed_result(5).is_some()); + } + + #[test] + fn test_update_rich_status_1() { + let mut postman = helpers::generate_postman(5, Default::default()); + + backlogs_prepare(&mut postman); let mut rich_status = RichStatus::new(); + + rich_status.set_height(1); + + postman.update_by_rich_status(&rich_status); + + // block height in rich_status is from Chain, that means database's block height. + // block height in postman, that means executed block height which cache in Executor. + // Testcase 0: block_height[chain] = 1, block_height[executor] = 5. + // Expected: remove the block 0, 1 from cache, but not other block. + assert!(postman.backlogs.get_completed_result(0).is_none()); + assert!(postman.backlogs.get_completed_result(1).is_none()); + assert!(postman.backlogs.get_completed_result(2).is_some()); + assert!(postman.backlogs.get_completed_result(3).is_some()); + assert!(postman.backlogs.get_completed_result(4).is_some()); + assert!(postman.backlogs.get_completed_result(5).is_some()); + } + + #[test] + fn test_update_rich_status_2() { + let mut postman = helpers::generate_postman(5, Default::default()); + + backlogs_prepare(&mut postman); + + let mut rich_status = RichStatus::new(); + rich_status.set_height(2); - // chain height = 2, executor height = 6 - // 3 + 2 < 6, executor backlogs will prune executed result which height <= 2 + + postman.update_by_rich_status(&rich_status); + + // block height in rich_status is from Chain, that means database's block height. + // block height in postman, that means executed block height which cache in Executor. + // Testcase 0: block_height[chain] = 2, block_height[executor] = 5. + // Expected: remove the block 0, 1, 2 from cache, but not other block. + assert!(postman.backlogs.get_completed_result(0).is_none()); + assert!(postman.backlogs.get_completed_result(1).is_none()); + assert!(postman.backlogs.get_completed_result(2).is_none()); + assert!(postman.backlogs.get_completed_result(3).is_some()); + assert!(postman.backlogs.get_completed_result(4).is_some()); + assert!(postman.backlogs.get_completed_result(5).is_some()); + } + + #[test] + fn test_update_rich_status_3() { + let mut postman = helpers::generate_postman(5, Default::default()); + + backlogs_prepare(&mut postman); + + let mut rich_status = RichStatus::new(); + + rich_status.set_height(3); + + postman.update_by_rich_status(&rich_status); + + // block height in rich_status is from Chain, that means database's block height. + // block height in postman, that means executed block height which cache in Executor. + // Testcase 0: block_height[chain] = 3, block_height[executor] = 5. + // Expected: postman needs to keep at least 3 block in cache, so remove the block 0, 1, 2 from cache, but not other block. + assert!(postman.backlogs.get_completed_result(0).is_none()); + assert!(postman.backlogs.get_completed_result(1).is_none()); + assert!(postman.backlogs.get_completed_result(2).is_none()); + assert!(postman.backlogs.get_completed_result(3).is_some()); + assert!(postman.backlogs.get_completed_result(4).is_some()); + assert!(postman.backlogs.get_completed_result(5).is_some()); + } + + #[test] + fn test_update_rich_status_4() { + let mut postman = helpers::generate_postman(5, Default::default()); + + backlogs_prepare(&mut postman); + + let mut rich_status = RichStatus::new(); + + rich_status.set_height(4); + postman.update_by_rich_status(&rich_status); + // block height in rich_status is from Chain, that means database's block height. + // block height in postman, that means executed block height which cache in Executor. + // Testcase 0: block_height[chain] = 3, block_height[executor] = 5. + // Expected: postman needs to keep at least 3 block in cache, so remove the block 0, 1, 2 from cache, but not other block. + assert!(postman.backlogs.get_completed_result(0).is_none()); assert!(postman.backlogs.get_completed_result(1).is_none()); assert!(postman.backlogs.get_completed_result(2).is_none()); assert!(postman.backlogs.get_completed_result(3).is_some()); assert!(postman.backlogs.get_completed_result(4).is_some()); + assert!(postman.backlogs.get_completed_result(5).is_some()); } #[test] - fn test_update_rich_status_without_prune() { + fn test_update_rich_status_5() { let mut postman = helpers::generate_postman(5, Default::default()); + backlogs_prepare(&mut postman); + + let mut rich_status = RichStatus::new(); + + rich_status.set_height(5); + + postman.update_by_rich_status(&rich_status); + + // block height in rich_status is from Chain, that means database's block height. + // block height in postman, that means executed block height which cache in Executor. + // Testcase 0: block_height[chain] = 3, block_height[executor] = 5. + // Expected: postman needs to keep at least 3 block in cache, so remove the block 0, 1, 2 from cache, but not other block. + assert!(postman.backlogs.get_completed_result(0).is_none()); + assert!(postman.backlogs.get_completed_result(1).is_none()); + assert!(postman.backlogs.get_completed_result(2).is_none()); + assert!(postman.backlogs.get_completed_result(3).is_some()); + assert!(postman.backlogs.get_completed_result(4).is_some()); + assert!(postman.backlogs.get_completed_result(5).is_some()); + } + + fn backlogs_prepare(postman: &mut Postman) { + let execute_result_0 = generate_executed_result(0); let execute_result_1 = generate_executed_result(1); let execute_result_2 = generate_executed_result(2); let execute_result_3 = generate_executed_result(3); let execute_result_4 = generate_executed_result(4); + let execute_result_5 = generate_executed_result(5); + postman + .backlogs + .insert_completed_result(0, execute_result_0); postman .backlogs .insert_completed_result(1, execute_result_1); @@ -1168,15 +1280,8 @@ mod tests { postman .backlogs .insert_completed_result(4, execute_result_4); - - let mut rich_status = RichStatus::new(); - rich_status.set_height(2); - // chain height = 2, executor height = 5 - // 3 + 2 = 5, not < 5, so executor backlogs will not prune - postman.update_by_rich_status(&rich_status); - - assert!(postman.backlogs.get_completed_result(1).is_some()); - assert!(postman.backlogs.get_completed_result(2).is_some()); - assert!(postman.backlogs.get_completed_result(3).is_some()); + postman + .backlogs + .insert_completed_result(5, execute_result_5); } } From d9b7861d1ac4273b2b6740cc9f0a39a415e0dba7 Mon Sep 17 00:00:00 2001 From: leeyr Date: Mon, 10 Jun 2019 22:04:24 +0800 Subject: [PATCH 45/91] Fix: memory lead in executor. --- cita-executor/src/backlogs.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/cita-executor/src/backlogs.rs b/cita-executor/src/backlogs.rs index efa6916c1..e4680e0e5 100644 --- a/cita-executor/src/backlogs.rs +++ b/cita-executor/src/backlogs.rs @@ -19,6 +19,7 @@ use super::core::libexecutor::block::{ClosedBlock, OpenBlock}; use cita_db::Itertools; use cita_types::Address; use libproto::{ExecutedResult, Proof}; +use std::cmp::min; use std::collections::BTreeMap; #[derive(Debug, Copy, Clone)] @@ -392,10 +393,11 @@ impl Backlogs { pub fn prune(&mut self, height: u64) { // Importance guard: we must keep the executed result of the recent - // 2 height(current_height - 1, current_height - 2), which used when - // postman check arrived proof via `Postman::check_proof` - if height + 2 < self.get_current_height() { - self.completed = self.completed.split_off(&height); + // 3 height(current_height, current_height - 1, current_height - 2), + // which used when postman check arrived proof via `Postman::check_proof` + if self.get_current_height() > 2 { + let split_height = min(height, self.get_current_height() - 2); + self.completed = self.completed.split_off(&split_height); } } } From 4f16f13dd8e94ec312cb00549db14cdac3bdddd4 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 10 Jun 2019 17:35:58 +0800 Subject: [PATCH 46/91] Update contract test submodule. [skip travis] --- .gitmodules | 4 +- scripts/contracts/tests/contracts | 1 - tests/contracts | 1 + tests/integrate_test/cita_crosschain.sh | 17 ++- tests/interfaces/config/blockchain.yaml | 28 ++--- .../contracts/AccountGasLimitReached.sol | 11 -- .../contracts/ERC20-Token/BasicToken.sol | 51 --------- .../config/contracts/ERC20-Token/ERC20.sol | 15 --- .../contracts/ERC20-Token/ERC20Basic.sol | 14 --- .../config/contracts/ERC20-Token/SafeMath.sol | 48 --------- .../contracts/ERC20-Token/StandardToken.sol | 100 ------------------ .../config/contracts/HelloWorld.sol | 10 -- .../interfaces/config/contracts/Reverted.sol | 7 -- .../config/contracts/SimpleStorage.sol | 23 ---- 14 files changed, 29 insertions(+), 301 deletions(-) delete mode 160000 scripts/contracts/tests/contracts create mode 160000 tests/contracts delete mode 100644 tests/interfaces/config/contracts/AccountGasLimitReached.sol delete mode 100644 tests/interfaces/config/contracts/ERC20-Token/BasicToken.sol delete mode 100644 tests/interfaces/config/contracts/ERC20-Token/ERC20.sol delete mode 100644 tests/interfaces/config/contracts/ERC20-Token/ERC20Basic.sol delete mode 100644 tests/interfaces/config/contracts/ERC20-Token/SafeMath.sol delete mode 100644 tests/interfaces/config/contracts/ERC20-Token/StandardToken.sol delete mode 100644 tests/interfaces/config/contracts/HelloWorld.sol delete mode 100644 tests/interfaces/config/contracts/Reverted.sol delete mode 100644 tests/interfaces/config/contracts/SimpleStorage.sol diff --git a/.gitmodules b/.gitmodules index d1f45a686..6b3480962 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,8 +10,8 @@ path = scripts/txtool/txtool/proto url = https://github.com/cryptape/cita-proto.git branch = master -[submodule "scripts/contracts/tests/contracts"] - path = scripts/contracts/tests/contracts +[submodule "tests/contracts"] + path = tests/contracts url = https://github.com/cryptape/test-contracts.git branch = master [submodule "scripts/contracts/interaction"] diff --git a/scripts/contracts/tests/contracts b/scripts/contracts/tests/contracts deleted file mode 160000 index a7a2ff2f9..000000000 --- a/scripts/contracts/tests/contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit a7a2ff2f9d11da4f9f944e268d70c8d274678de6 diff --git a/tests/contracts b/tests/contracts new file mode 160000 index 000000000..3ed3e5ede --- /dev/null +++ b/tests/contracts @@ -0,0 +1 @@ +Subproject commit 3ed3e5ede13bba04bc8c91853584bafd2b230b02 diff --git a/tests/integrate_test/cita_crosschain.sh b/tests/integrate_test/cita_crosschain.sh index b9da053cf..0bfd1a8b2 100755 --- a/tests/integrate_test/cita_crosschain.sh +++ b/tests/integrate_test/cita_crosschain.sh @@ -2,6 +2,13 @@ set -e -o pipefail +if [[ $(uname) == 'Darwin' ]] +then + SOURCE_DIR=$(realpath "$(dirname "$0")"/../..) +else + SOURCE_DIR=$(readlink -f "$(dirname "$0")"/../..) +fi + # Test private key & address PKEY="1234567890123456789012345678901234567890123456789012345678901234" PADDR="2e988a386a799f506693793c6a5af6b54dfaabfb" @@ -12,7 +19,7 @@ CMC="scripts/contracts/src/system/ChainManager.sol" CMC_ABI= # Base dir for import contract files -CONTRACT_LIBS_DIR="scripts/contracts" +CONTRACT_LIBS_DIR="$SOURCE_DIR" # Templates for some shell commands JSONRPC_CALL='{"jsonrpc":"2.0","method":"call", "params":[{"to":"%s", "data":"%s"}, "pending"],"id":2}' @@ -20,7 +27,7 @@ JSONRPC_BLOCKHEADER='{"jsonrpc":"2.0","method":"getBlockHeader","params":["0x%x" JSONRPC_STATEPROOF='{"jsonrpc":"2.0","method":"getStateProof","params":["0x%s","0x%s","0x%x"],"id":1}' # Test contract file -CONTRACT_DEMO="scripts/contracts/tests/contracts/MyToken.sol" +CONTRACT_DEMO="${SOURCE_DIR}/tests/contracts/MyToken.sol" DEMO_ABI= # Global variables which are set in functions @@ -147,7 +154,7 @@ function deploy_contract () { local chain="$1" local solfile="$2" local extra="$3" - local code="$(solc --allow-paths "$(pwd)/${CONTRACT_LIBS_DIR}" \ + local code="$(solc --allow-paths "${CONTRACT_LIBS_DIR}" \ --bin "${solfile}" 2>/dev/null | tail -1)${extra}" txtool_run ${chain} make_tx.py --privkey "${PKEY}" --code "${code}" txtool_run ${chain} send_tx.py @@ -347,7 +354,7 @@ function test_demo_contract () { "The tokens is not right for side chain." title "Send tokens from main chain." - DEMO_ABI=$(solc --allow-paths "$(pwd)/${CONTRACT_LIBS_DIR}" \ + DEMO_ABI=$(solc --allow-paths "${CONTRACT_LIBS_DIR}" \ --combined-json abi ${CONTRACT_DEMO} \ | sed "s@${CONTRACT_DEMO}:@@g" \ | json_get '.contracts.MyToken.abi') @@ -512,7 +519,7 @@ function main () { wait_chain_for_height main 3 title "Register side chain ..." - CMC_ABI=$(solc --allow-paths "$(pwd)/${CONTRACT_LIBS_DIR}" \ + CMC_ABI=$(solc --allow-paths "${CONTRACT_LIBS_DIR}" \ --combined-json abi ${CMC} 2>/dev/null \ | sed "s@${CMC}:@@g" \ | json_get '.contracts.ChainManager.abi') diff --git a/tests/interfaces/config/blockchain.yaml b/tests/interfaces/config/blockchain.yaml index 32f568c7c..2ba792abc 100644 --- a/tests/interfaces/config/blockchain.yaml +++ b/tests/interfaces/config/blockchain.yaml @@ -17,7 +17,7 @@ blocks: - number: 2 transactions: # Create a SimpleStorage contract - # [Source Code]: contracts/HelloWorld.sol + # [Source Code]: tests/contracts/HelloWorld.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' # Sender's private key nonce: 0 quota: 200000 @@ -41,7 +41,7 @@ blocks: - number: 4 transactions: # Create a Token contract - # [Source Code]: contracts/ERC20-Token/StandardToken.sol + # [Source Code]: tests/contracts/ERC20-Token/StandardToken.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 2 quota: 100000 @@ -52,7 +52,7 @@ blocks: - number: 5 transactions: # Create a Token contract - # [Source Code]: contracts/ERC20-Token/StandardToken.sol + # [Source Code]: tests/contracts/ERC20-Token/StandardToken.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 3 quota: 100000 @@ -65,7 +65,7 @@ blocks: - number: 6 transactions: # Create a Token contract - # [Source Code]: contracts/ERC20-Token/StandardToken.sol + # [Source Code]: tests/contracts/ERC20-Token/StandardToken.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 4 quota: 100000 @@ -77,7 +77,7 @@ blocks: - number: 7 transactions: - # [Source Code]: contracts/AccountGasLimitReached.sol + # [Source Code]: tests/contracts/AccountGasLimitReached.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 5 # Should be NotEnoughBaseGas Receipt @@ -88,7 +88,7 @@ blocks: - number: 8 transactions: - # [Source Code]: contracts/AccountGasLimitReached.sol + # [Source Code]: tests/contracts/AccountGasLimitReached.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 6 # Should be OutOfGas Receipt (1073741824 + 1) @@ -102,7 +102,7 @@ blocks: - number: 10 transactions: - # [Source Code]: contracts/AccountGasLimitReached.sol + # [Source Code]: tests/contracts/AccountGasLimitReached.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 8 quota: 100000 @@ -114,7 +114,7 @@ blocks: - number: 11 transactions: - # [Source Code]: contracts/Reverted.sol + # [Source Code]: tests/contracts/Reverted.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 9 # Should be Reverted Receipt @@ -126,7 +126,7 @@ blocks: - number: 12 transactions: # Create a contract - # [Source Code]: contracts/SimpleStorage.sol + # [Source Code]: tests/contracts/SimpleStorage.sol - privkey: 'ef98e68db428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' nonce: 10 quota: 1000000 @@ -134,7 +134,7 @@ blocks: to: '' data: '608060405234801561001057600080fd5b5060646000819055507f8fb1356be6b2a4e49ee94447eb9dcb8783f51c41dcddfe7919f945017d163bf3336064604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a161018a806100946000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b1146100515780636d4ce63c1461007e575b600080fd5b34801561005d57600080fd5b5061007c600480360381019080803590602001909291905050506100a9565b005b34801561008a57600080fd5b50610093610155565b6040518082815260200191505060405180910390f35b7fc6d8c0af6d21f291e7c359603aa97e0ed500f04db6e983b9fce75a91c6b8da6b816040518082815260200191505060405180910390a1806000819055507ffd28ec3ec2555238d8ad6f9faf3e4cd10e574ce7e7ef28b73caa53f9512f65b93382604051808373ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff1681526020018281526020019250505060405180910390a150565b600080549050905600a165627a7a723058200b008257b7c6ae78c1c2bde97f3c72005d0f7063ad98e02a3399ee94642fe7810029' # Create a HelloWorld contract - # [Source Code]: contracts/HelloWorld.sol + # [Source Code]: tests/contracts/HelloWorld.sol - privkey: '00000000b428906d626cd37782cdfb052ac282132beee53a99948738ea553b4a' # Fake Sender's private key nonce: 0 quota: 100000 @@ -149,7 +149,7 @@ blocks: nonce: 11 quota: 200000 valid_until_block: 100 - # In contracts/SimpleStorage.sol + # In tests/contracts/SimpleStorage.sol # Call set(11228899) to: 'a31af83ee35e753a2bb19c2a82468080c2e92eee' data: '60fe47b10000000000000000000000000000000000000000000000000000000011228899' @@ -160,7 +160,7 @@ blocks: nonce: 11 quota: 200000 valid_until_block: 100 - # In contracts/SimpleStorage.sol + # In tests/contracts/SimpleStorage.sol # Call set(11228899) to: 'a31af83ee35e753a2bb19c2a82468080c2e92eee' data: '60fe47b10000000000000000000000000000000000000000000000000000000011228899' @@ -170,8 +170,8 @@ blocks: valid_until_block: 100 # A special address to store contract ABI data to: 'ffffffffffffffffffffffffffffffffff010001' - # Store contracts/SimpleStorage.sol ABI to blockchain + # Store tests/contracts/SimpleStorage.sol ABI to blockchain # Data generated by commands: - # $ solc --abi contracts/SimpleStorage.sol + # $ solc --abi tests/contracts/SimpleStorage.sol # $ ethabi params -v string "[data generated by above command]" data: 'a31af83ee35e753a2bb19c2a82468080c2e92eee0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000030f5b7b22636f6e7374616e74223a66616c73652c22696e70757473223a5b7b226e616d65223a2278222c2274797065223a2275696e74323536227d5d2c226e616d65223a22736574222c226f757470757473223a5b5d2c2270617961626c65223a66616c73652c2273746174654d75746162696c697479223a226e6f6e70617961626c65222c2274797065223a2266756e6374696f6e227d2c7b22636f6e7374616e74223a747275652c22696e70757473223a5b5d2c226e616d65223a22676574222c226f757470757473223a5b7b226e616d65223a22222c2274797065223a2275696e74323536227d5d2c2270617961626c65223a66616c73652c2273746174654d75746162696c697479223a2276696577222c2274797065223a2266756e6374696f6e227d2c7b22696e70757473223a5b5d2c2270617961626c65223a66616c73652c2273746174654d75746162696c697479223a226e6f6e70617961626c65222c2274797065223a22636f6e7374727563746f72227d2c7b22616e6f6e796d6f7573223a66616c73652c22696e70757473223a5b7b22696e6465786564223a66616c73652c226e616d65223a22222c2274797065223a2261646472657373227d2c7b22696e6465786564223a66616c73652c226e616d65223a22222c2274797065223a2275696e74323536227d5d2c226e616d65223a22496e6974222c2274797065223a226576656e74227d2c7b22616e6f6e796d6f7573223a66616c73652c22696e70757473223a5b7b22696e6465786564223a66616c73652c226e616d65223a22222c2274797065223a2261646472657373227d2c7b22696e6465786564223a66616c73652c226e616d65223a22222c2274797065223a2275696e74323536227d5d2c226e616d65223a22536574222c2274797065223a226576656e74227d2c7b22616e6f6e796d6f7573223a66616c73652c22696e70757473223a5b7b22696e6465786564223a66616c73652c226e616d65223a22222c2274797065223a2275696e74323536227d5d2c226e616d65223a2253746f726564222c2274797065223a226576656e74227d5d0000000000000000000000000000000000' diff --git a/tests/interfaces/config/contracts/AccountGasLimitReached.sol b/tests/interfaces/config/contracts/AccountGasLimitReached.sol deleted file mode 100644 index 1fa06461c..000000000 --- a/tests/interfaces/config/contracts/AccountGasLimitReached.sol +++ /dev/null @@ -1,11 +0,0 @@ -pragma solidity ^0.4.24; - -contract AccountGasLimitReached { - bytes32[] balance; - - constructor() public { - for (uint i = 0; i < 99999999999; i++) { - balance.push(keccak256(abi.encodePacked(i))); - } - } -} diff --git a/tests/interfaces/config/contracts/ERC20-Token/BasicToken.sol b/tests/interfaces/config/contracts/ERC20-Token/BasicToken.sol deleted file mode 100644 index 6a748a2a4..000000000 --- a/tests/interfaces/config/contracts/ERC20-Token/BasicToken.sol +++ /dev/null @@ -1,51 +0,0 @@ -pragma solidity ^0.4.24; - - -import "./ERC20Basic.sol"; -import "./SafeMath.sol"; - - -/** - * @title Basic token - * @dev Basic version of StandardToken, with no allowances. - */ -contract BasicToken is ERC20Basic { - using SafeMath for uint256; - - mapping(address => uint256) balances; - - uint256 totalSupply_; - - /** - * @dev total number of tokens in existence - */ - function totalSupply() public view returns (uint256) { - return totalSupply_; - } - - /** - * @dev transfer token for a specified address - * @param _to The address to transfer to. - * @param _value The amount to be transferred. - */ - function transfer(address _to, uint256 _value) public returns (bool) { - require(_to != address(0)); - require(_value <= balances[msg.sender]); - - // SafeMath.sub will throw if there is not enough balance. - balances[msg.sender] = balances[msg.sender].sub(_value); - balances[_to] = balances[_to].add(_value); - emit Transfer(msg.sender, _to, _value); - return true; - } - - /** - * @dev Gets the balance of the specified address. - * @param _owner The address to query the the balance of. - * @return An uint256 representing the amount owned by the passed address. - */ - function balanceOf(address _owner) public view returns (uint256 balance) { - return balances[_owner]; - } - -} diff --git a/tests/interfaces/config/contracts/ERC20-Token/ERC20.sol b/tests/interfaces/config/contracts/ERC20-Token/ERC20.sol deleted file mode 100644 index 533e53ea5..000000000 --- a/tests/interfaces/config/contracts/ERC20-Token/ERC20.sol +++ /dev/null @@ -1,15 +0,0 @@ -pragma solidity ^0.4.24; - -import "./ERC20Basic.sol"; - - -/** - * @title ERC20 interface - * @dev see https://github.com/ethereum/EIPs/issues/20 - */ -contract ERC20 is ERC20Basic { - function allowance(address owner, address spender) public view returns (uint256); - function transferFrom(address from, address to, uint256 value) public returns (bool); - function approve(address spender, uint256 value) public returns (bool); - event Approval(address indexed owner, address indexed spender, uint256 value); -} diff --git a/tests/interfaces/config/contracts/ERC20-Token/ERC20Basic.sol b/tests/interfaces/config/contracts/ERC20-Token/ERC20Basic.sol deleted file mode 100644 index c326601de..000000000 --- a/tests/interfaces/config/contracts/ERC20-Token/ERC20Basic.sol +++ /dev/null @@ -1,14 +0,0 @@ -pragma solidity ^0.4.24; - - -/** - * @title ERC20Basic - * @dev Simpler version of ERC20 interface - * @dev see https://github.com/ethereum/EIPs/issues/179 - */ -contract ERC20Basic { - function totalSupply() public view returns (uint256); - function balanceOf(address who) public view returns (uint256); - function transfer(address to, uint256 value) public returns (bool); - event Transfer(address indexed from, address indexed to, uint256 value); -} diff --git a/tests/interfaces/config/contracts/ERC20-Token/SafeMath.sol b/tests/interfaces/config/contracts/ERC20-Token/SafeMath.sol deleted file mode 100644 index c347da189..000000000 --- a/tests/interfaces/config/contracts/ERC20-Token/SafeMath.sol +++ /dev/null @@ -1,48 +0,0 @@ -pragma solidity ^0.4.24; - - -/** - * @title SafeMath - * @dev Math operations with safety checks that throw on error - */ -library SafeMath { - - /** - * @dev Multiplies two numbers, throws on overflow. - */ - function mul(uint256 a, uint256 b) internal pure returns (uint256) { - if (a == 0) { - return 0; - } - uint256 c = a * b; - assert(c / a == b); - return c; - } - - /** - * @dev Integer division of two numbers, truncating the quotient. - */ - function div(uint256 a, uint256 b) internal pure returns (uint256) { - // assert(b > 0); // Solidity automatically throws when dividing by 0 - uint256 c = a / b; - // assert(a == b * c + a % b); // There is no case in which this doesn't hold - return c; - } - - /** - * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend). - */ - function sub(uint256 a, uint256 b) internal pure returns (uint256) { - assert(b <= a); - return a - b; - } - - /** - * @dev Adds two numbers, throws on overflow. - */ - function add(uint256 a, uint256 b) internal pure returns (uint256) { - uint256 c = a + b; - assert(c >= a); - return c; - } -} diff --git a/tests/interfaces/config/contracts/ERC20-Token/StandardToken.sol b/tests/interfaces/config/contracts/ERC20-Token/StandardToken.sol deleted file mode 100644 index 6c816aba4..000000000 --- a/tests/interfaces/config/contracts/ERC20-Token/StandardToken.sol +++ /dev/null @@ -1,100 +0,0 @@ -pragma solidity ^0.4.24; - -import "./BasicToken.sol"; -import "./ERC20.sol"; - - -/** - * @title Standard ERC20 token - * - * @dev Implementation of the basic standard token. - * @dev https://github.com/ethereum/EIPs/issues/20 - * @dev Based on code by FirstBlood: https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol - */ -contract StandardToken is ERC20, BasicToken { - - mapping (address => mapping (address => uint256)) internal allowed; - - - /** - * @dev Transfer tokens from one address to another - * @param _from address The address which you want to send tokens from - * @param _to address The address which you want to transfer to - * @param _value uint256 the amount of tokens to be transferred - */ - function transferFrom(address _from, address _to, uint256 _value) public returns (bool) { - require(_to != address(0)); - require(_value <= balances[_from]); - require(_value <= allowed[_from][msg.sender]); - - balances[_from] = balances[_from].sub(_value); - balances[_to] = balances[_to].add(_value); - allowed[_from][msg.sender] = allowed[_from][msg.sender].sub(_value); - emit Transfer(_from, _to, _value); - return true; - } - - /** - * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender. - * - * Beware that changing an allowance with this method brings the risk that someone may use both the old - * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this - * race condition is to first reduce the spender's allowance to 0 and set the desired value afterwards: - * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 - * @param _spender The address which will spend the funds. - * @param _value The amount of tokens to be spent. - */ - function approve(address _spender, uint256 _value) public returns (bool) { - allowed[msg.sender][_spender] = _value; - emit Approval(msg.sender, _spender, _value); - return true; - } - - /** - * @dev Function to check the amount of tokens that an owner allowed to a spender. - * @param _owner address The address which owns the funds. - * @param _spender address The address which will spend the funds. - * @return A uint256 specifying the amount of tokens still available for the spender. - */ - function allowance(address _owner, address _spender) public view returns (uint256) { - return allowed[_owner][_spender]; - } - - /** - * @dev Increase the amount of tokens that an owner allowed to a spender. - * - * approve should be called when allowed[_spender] == 0. To increment - * allowed value is better to use this function to avoid 2 calls (and wait until - * the first transaction is mined) - * From MonolithDAO Token.sol - * @param _spender The address which will spend the funds. - * @param _addedValue The amount of tokens to increase the allowance by. - */ - function increaseApproval(address _spender, uint _addedValue) public returns (bool) { - allowed[msg.sender][_spender] = allowed[msg.sender][_spender].add(_addedValue); - emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); - return true; - } - - /** - * @dev Decrease the amount of tokens that an owner allowed to a spender. - * - * approve should be called when allowed[_spender] == 0. To decrement - * allowed value is better to use this function to avoid 2 calls (and wait until - * the first transaction is mined) - * From MonolithDAO Token.sol - * @param _spender The address which will spend the funds. - * @param _subtractedValue The amount of tokens to decrease the allowance by. - */ - function decreaseApproval(address _spender, uint _subtractedValue) public returns (bool) { - uint oldValue = allowed[msg.sender][_spender]; - if (_subtractedValue > oldValue) { - allowed[msg.sender][_spender] = 0; - } else { - allowed[msg.sender][_spender] = oldValue.sub(_subtractedValue); - } - emit Approval(msg.sender, _spender, allowed[msg.sender][_spender]); - return true; - } - -} diff --git a/tests/interfaces/config/contracts/HelloWorld.sol b/tests/interfaces/config/contracts/HelloWorld.sol deleted file mode 100644 index 1fad1cdcc..000000000 --- a/tests/interfaces/config/contracts/HelloWorld.sol +++ /dev/null @@ -1,10 +0,0 @@ -pragma solidity ^0.4.24; - -contract HelloWorld { - uint balance; - - function update(uint amount) public returns (address, uint) { - balance += amount; - return (msg.sender, balance); - } -} diff --git a/tests/interfaces/config/contracts/Reverted.sol b/tests/interfaces/config/contracts/Reverted.sol deleted file mode 100644 index 1b5b0fd1a..000000000 --- a/tests/interfaces/config/contracts/Reverted.sol +++ /dev/null @@ -1,7 +0,0 @@ -pragma solidity ^0.4.24; - -contract RevertedDemo { - constructor() public { - assert(false); - } -} diff --git a/tests/interfaces/config/contracts/SimpleStorage.sol b/tests/interfaces/config/contracts/SimpleStorage.sol deleted file mode 100644 index 06e292837..000000000 --- a/tests/interfaces/config/contracts/SimpleStorage.sol +++ /dev/null @@ -1,23 +0,0 @@ -pragma solidity ^0.4.24; - -contract SimpleStorage { - uint storedData; - event Init(address, uint); - event Set(address, uint); - event Stored(uint); - - constructor() public { - storedData = 100; - emit Init(msg.sender, 100); - } - - function set(uint x) public { - emit Stored(x); - storedData = x; - emit Set(msg.sender, x); - } - - function get() public constant returns (uint) { - return storedData; - } -} From 0c81319b8f5c09313a57e64d67558182f8e74ad1 Mon Sep 17 00:00:00 2001 From: leeyr Date: Tue, 11 Jun 2019 17:55:21 +0800 Subject: [PATCH 47/91] Add images for wiki. [skip ci] --- docs/wiki/images/rocksdb-db-impl.png | Bin 0 -> 264548 bytes docs/wiki/images/rocksdb-lsm-tree.png | Bin 0 -> 442562 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/wiki/images/rocksdb-db-impl.png create mode 100644 docs/wiki/images/rocksdb-lsm-tree.png diff --git a/docs/wiki/images/rocksdb-db-impl.png b/docs/wiki/images/rocksdb-db-impl.png new file mode 100644 index 0000000000000000000000000000000000000000..f374d86cd9ffc7ba05815c5ebdd49766243301fb GIT binary patch literal 264548 zcmeFZg&WGD896*@Bsa2tzklz96Q-B&_8bm1t{tCdeY5{AK2FI^cHL+) zoFv+X4>L0+N^3av3$lt-IM;Y;GWfDMYMS}PWy~)!&6C|F!{Li)r~85T?fRegwyBg_ z;YZY=MR+_=oOR{55+Y`nJoS`U6Fx==5WO(wtDk8eZ+Lj5+x9mv+R}O9QsneC+I$x1 zm-yy{6Q9T_A0>?+u8!pQh11PyzbQWK$hD5R>>ztRnsnVv#$HRf-kb_LqSo&PmNg))N#bn1aa&9AN#EvkVJZt^oor^XjWHU3wh;e?J zFuMbdR+j$o++#_WQiJBF&1xOj+?Ep8nF{vr2CupZOxC*m42vA#ToUf{k8jF;o|Y$C zUEg7d(&BQK_iqyYlTmn4Ui1AI`&M7O-DJU{-XgD}L?5kKZYcCAuNseyLH6I5Yw_U{ z(4Q(#T8-W7Mx&d~)7e_yyt8bztcUw?X*nN0#eKiblr1E4+)?BMP6?fi@q!T3FtM+C zC(buYukOp0e#=N^U;bsrygMpC!Y!M8ac)Up_NLX5ro4pf5FI9Ai?`xSa9Be_Me$t* zFPeZWfiRzSw)FW`EkaV6yIPb*zD&=B28cLo3~kT%_;pW+m*8jnIopzn`+9Ye8TjMg z!GCiB|LWCyuR~v5-G58+B5;6>=PmnW*z0Sb6!AX4PPvBnAmsLgNVbNb@`d{KXEA%*;CHT?|&5f$xd@WBV82s{_FRPYV11E7P{7)yxPaM-_v-??6cyAt4YBJCu0oQ&J~w_5i{f+nGhB_PQc=9oc7ulc z5it=lI|=ImULX_r{59ii)fG*vz#&NlnYn~xi1mY=REN3N`Ga}-`O1X{PW-6n zC`Z%_RNaEr!nrHvSHkbT5STIhVjkBu_u~0^b@@AN;d!BUA$GCrW^pURt9BK3nN7VR zi;O!44iz_*!qc=<+#YO3&aiX;h^*3h(?DaG-ZaluykIA z-a8)HJrGR~O;t|mz>D`1g^LE1xtIBs4VDc%@y=~8-rdr2pLdT%bu6IfyHOITz5Q5J z=ln@c&vSQv{+QwD_BPyeOaZLt@@fnM1Op83^VeOf!>eO^6Bcqyo=2WTKK8@c5W*1D zhqNoa_p$|%Hs7C5zW8jC-<#6#w=yHfEN=c$w`e!L$ybvalRcAO6Uuh88G{*-nduoJ z?zeP2beHMMZx3;+DJitxYkk_fsF5BKPCITM1!=;s#qTHaCz-yuqNNV6gl}eL!pp5L z2_^{=2s#Po+`OXlIIhI-MQeRdQD{+2(Sa4qK*r#cJg!`eT#uJFW}SJwh^l#M2Vz^T zN!8Ug_s_l8$5Qeix-iX$sxxVd3W|8!**jB<_6nm!7{u5`RvnR3-&d&rkqS5wl1}98acKvcJ8#5nmc}xKWH@e_bA*${Jg{fvxh{Pcuc~>1P}4@it`l% z2Ga&ATJpDf7I79!ivwNCcCM~!N)}1VCWcF{dX0M0?+NZ3di#0Hd0QQuAKyI|J7gic zM3_SOjOaYRC?OBA<@sy)f%sO$Wf!v;+DNiVnWHDgjk~_gP?;+}`x*L?Jt;D&_Sc(? zxgHL6p(kFKOsH=XXOa>9sreII%OV#o_xHh};0Iyu7drEWrk|WYk+JE1pHnMHrjRF> zJ9v=u-ka(rGh3)xFeEhof-dcWWCySHOFhlQ`dzv8e(J)DyCkT0DfI*O=iUW$AEnvE zjEU9R$^Qu%=5IIYh;=iL+|Fv#HZ|euH0hK~c%T@pBpSUH!_>iJN_mrref2T(#IAjj zy@9>5%kSBmP4l(nhZtAU571fOb}bgScB>;DrB%}0I;7cEcS?Gil)KjPXeXjv z^H1h(=8%S1));c%;zIG9d7hQs!}VE#H~~$cq64?#PBshmz9P7Tj%HCpi9zo1Hen8V z1Or59#%5{oo|F2r$;{06_SK@cG5b`br_C$yFYrmY{;+IuuZ_?c()(bR$xO^TV*d;C zU`Bxhs$-|Tq+GOB%UGb?$%TIPxG<<{c4e%(5;6T_`o_WAgN<#8VV3f$Y5FKAjN%o` zEy=Z1S=BDcW$i(|X+4OO>g+_Bd7+NpsLQLyr0qKIphb%;i*05@Mh;2R(BQD+b&KCQ z#bJSr7NRTm6*I4!-^H`fv%fe0G_;2}=Va!jk0L=arTvIAH@CGB-ivLwp-m%Kj!Nhf zE?Buey%b!)HoMVDE@&dOov0!)-hHopz9w*&Oei)@pjiKWsq5a;>QplBG45F&4?Rh* zhUJ!wOdid}Y!UrTDQ5l*dj(Wt&IN>g*_sckb5JKZadw5ehfLoS36d>Lytf%Hqm891om| zCEvMkd<*K{+{l=lpB6LOp^7%MT z^7cXD=hn|v<^<*_jAglHqKYO*Q(T?|TnGpY%761_oZjo#zUp4r^vl+?5|z%NS?`-( zW7`drN_G7ob0`(^<>m7SWsA0M`PTUTNWoeAfrq1mCoWcaPFn5rXl083&z1L2@sBS? zj&`O@;!6{d`9`PWysqVcbeZucmHHoD`>jwD+@2ak%b#*zCZF@ZmkSiSR2%f^Q*jy2 z$16Cy*BCEf9uwf(FqXRRLFwDbI2f;T?SU(D{N+^{D>%(s^5MnD)0V_iI=87ooj_u% zsO^A*Lw5uH2lwIA>uWeTxQS-Zv>dgbJQjUvW5r`=Wb?w9$JNRfd>RKw+*K6()5_S< zkk!@7(%M1PRpQ!zJ|PPJjs7<8HP-)p#L+_Hn${Cl*84X0#;gK7_jvAHlO$zjWfiwK zG7)|HK>nY{!T(8Id*$e8E6U63;^M;N!p~!4Z_0aDL_~!54j(TcA2;{}w}YFtqoFIe zwFBFK7dc($fw99&dox={GaGAG^ty&GY@8e=u3bZKg!%8kavHmuVRy22_~%&QfV}9R z@ZROQ!;4uPJSvXF=pMS$B1L+unE1& zK9@re{*{9Q{^No`nnRZnfg=ez5nc(2Q9eGt$DL+oW@P#;RW4I*`(ph3-F(0K4|lS? z5qF=WjlJ>jWzP5BI{SW5|L0F`^J=MfUrWMygD*2vyyWpDqx zv8l<*$f#aw(I!4~r}od$iGkA1qWdBnE8Wlcd0a+^>Ov zIF5ejk2>Z%xcJoa(%f7$ORy`Y#l`)EgoKu^t^;r0yg6K~sgYs0!kC}*C&^-UaW!u( z`iaVu*is%knSq4>D1G0L)U-V+K_T{jw1$&A112=^a$1k=IrbGWyub(Dr&qB-h*@Z1j}-B zZF#E(W_6;FV`ToOkQ=;?b7e{*Dzv>QITQ9DY8u(8ds5vV5}eiP{%`XN1))%Khh6df@qS=IX{v>onHnXC@z zQiXQ$-Z#pxIT}LcgjdP3)pE5BRS6`f1g}3^q?F)F={sh#s!&MIBwDRZ2_mA?IQ|ia zhu@J=w$a9baS7IAd_5$L?gH#Lq$F!Xefcg;=t2@~`q=LnTG(U@=i4gPF-g~d19L&e z-|i1DDa`756s+W#Ner2V8Nb$faEpdqM-IOeHUSCDmYsekOe0KWLME{&fw*${660Fm zzHY|?r9>6#&5#W~x3JMXONVGxb>NZaIj=#^Uz&0VSr?28unqzb2=@w%VL6r7SGtxM zpB5Q#KcH`H%o+}dJJ0{VVPS2(9d?ZLh9WZ8p8ol<(fBIXR{V&4WVt?C+pBc94c%lRKYbKpFGr{|MxCsA4hI2lFhnp<0F&=IX z1Z;uRBHbqUO(UUhseNj1U!RV)c1(`9G68hv?LV1C#8%~=b^ zP{<;uS%9i~>@fkHuSYUDt-NXHCdKq?&w(sD3J3(^5Z1yuJ|ttsOk)X)C#-zUR-9|z zkc9k28YLzwIx`fLp4xndc08SZmlwQ6x=16nxp%L4vhko_6UE3cJdn-b=(EcL&A z@3^l1H+M>V0#|El61_u;^*$OJRkHICzRcjgt@&=}KeYrFX4dNrCmEgjoRLbvTXQBj z={dOyZ*w|xGh`Q46AQvyN%Ti6I<1V-s`>fZ9I_Mb&1r5c97QDyvdcgUVevMeb1dXN zWI7S^`$7KSa*B>?q;s5*eW?{$BO2K{W{dqf#c+7A+S>SsSHN-J&(YJff0;Ci#a?`~mfxdp!r z%gprZd`{3_>~QNI1mfi5Q)Sbi6g;{YT9W zWZM}Cy=6F7oyfWal_|yBc%G~v!8M>cmqo|;^*w9|rDMS{`y^IyFqBE`&_+6zYHUU7 z*2taf#}7_ZVx*jJwVU=pDF@cYIEnFNaVW?s^)pSZ%X45( zMSnJ8wA^KQc>LH|7h&Fe*vhkqdfHU_mu&3s1AvWOk8^l1vGM3pF#c&hA4fUz*7%bmwX`Mv66N4mt88a zJ571Gdcv2In&HY7&+2qjtK&2(NH5$xld6S6&XHe)AeJ;1>V<+Fbhsd=0y>H-m#vCS z+OPPi5R{5ObIV*X{V>hOviCNpqB8zQN!|b*>(J}L3uQeFb0fwljyp$^fITVI z+mF)1jN1{Vq!)bF0$6qp+F^Pct*^^h%36zkRexr!X&ZhY(z&G?(wDSN4ztuyB7&&r z=oWVrC#$YWNTrkOJbuN9yjD7~AN)5p)FwkFdtdux$y92S7RmQ9Ovf#qwprG1GkBjC zsj@-FTQPCY6hXRoG=AbWT;+4(RO6P?RNAx1jS@$BXoy`nQuaUYkSV_ian20ZWgxR2 zE$by(HoweQg=&7fTIY63g{tjAz~&7S-NCpcm7=nrHhQ>!Ib@lGh82cr?6cDK zihW(aiX0AlmzSjl;rdW@P+qmU%qV&Ihw>oTEs2g^NcYP(qC(Ekz56m&R~>KR_x^Zu zqv3|+H|0*n9mwd{&8nl}Ds8Au;_^UgouJLw(tT?by9PlHGWov5*WPk%EB>Czmj^}5 z$f!KL{suf#RN`@qCUUZFR)N{A-o`#1M{`@WkR%zF5zxLvv%qQDFY>im*10kbwvZaq z4ZRn9LZXusC*sj~d{A{VtehyhoEc9mYH?A4pz}(xyCIf3t@B7vFs^dd?_#S2YI)Xy z>ubBQP0PU3i*hVAR7a>>lQ2 zSiNKO4sRjA zQIP#bLzd|qy0}&Do|!(V%AK)AsDj-ky(_0w>+M^R6CYeECB_6_9K4xxPaw0LKMxy) zkbk)RXl>2a#SnS7xVUubZdz&W&iWkB9*_BKoBEhgO74F1k&u*JIk?R=@GK%v5Ye6V zXlQ6i2N+sj{>}JfRmks!bMQO&h@BxES!L`ettnkVNV@GQGqs>cIOk|uJ2a%6-(d!`oX*uqTlk{{pz7G`F50}G@8s<}a}LKNt-jBE`m85|sJ<%^0X=m5iO zBs`Ea3X$|}$aqdw`1p9IYMiKfK>|+t2k6D8sH;oO1At*x2+{4fAeObdFp&2$XthS~ z*|Wdrx*K#Lpy*tlY|#UX<-+4%(J!2C*;45E-n!MlYqZbqv%!vB zR?KRw@j8XJ-!Lt!EmB_u8FYGXR^MuJJlLUx)4~_CZgGMVFuU3w2A(MyQu(JR`Z$Ag ztZMgtRqp(}nfi@&5L#Dt&2RmLSiEDkMbit)PntOfR_Ne4FC_eIBFmsjMFRCDXTp2; zPmooAw!Zfv;KRtkH-c5_YngqN`;TR|g{ttmz_qkN>5baUspcU zpnA@Mw@~ac({|ZoYJdS5=J3$$-BF{>;hW_FWZe!2h^x>R<7?g>i#b&*9*;72)*C-C zcs1nt8(QrOov0dbAAZw{=zwMS?o@3fas~mDvy?j`9iKEj-sxG@X264$X+t`Owrq}_ z{7FqAY${Kl?2)e7crEH4qX6SGlw$UxD`X_Wo1KX?@riAGBhT`Rh_-ce72aR7_ay4; zp@7rzIZE;8qR<_WKY{d~l%`f!c7L*k?Y5IlmDXx=D{N8X1{nzd_0Y@AKX}KUutq4< z5npwhD*aq9f_7Xnt)cj79>T#R;rd4U0wR*Rla1F4Iuz<;q=Dt;>=#-{xLZeh%4C-> z7d}jYMKdrkEUPE(f1!LgOF7qAtz8+{`}F?!UYgH7du&{EA=G28-&5)R-ne?sOM()Z zaG$tJqGaXsiLA}SjPEO(O9h?#3q~kw4OaN0>8-6&X-VRb$>o{Dnm?;H7P!1eIk~u&cf413mR8DF6FNIAPAeT& z9#AVz*=t{-!NgMOYozHcd9tPif%o9 z7L(ib+oK60skP#Ssy*l(Iz*eQ5_w=1Ok4wzk2mWu+c8*ma!@rqFc7`UmbFd48OETi zmu}oxb-Y;hl@ms5ok<>4yLfo$$%4a$qZvy<(8IF#Q^8Z|!(P8frk}&FmIp`aDAm+0 zq}M^#j~|UaP#xSI{!Z~JA?r96VQ7h~VT~PZqr9SGPL}4C1GFHt9>*Q~XjXD*Aof$@U*kJp9X!-ao)sH6 z8!om1ov@0=4OQcO|Fym%4XGc1Uqv$y{k1*5D=xkyME>m8;lRtVL3DNk@kUtEb2pdL zx-(H~HDGIRyxi`hlojdj6wAo~(JE3L?0_@lZz!=)7UV)d+6pghc=~0`51*TrBF9W}kJ}9;v zoaAz&W$f$ijd7=&eQke8=oLv9%facWf#bb3rv|72a+WKKzO2CgZYJ&91Sfpj-wIGE z^G=DKIQ=rm`LdkROTrcxWg%AeJQaN-y(UJ068(_uT5ys$A?A#v ztzJlnWpDKM)%@_=?2JFr**VznuUc8n+=0wzd1S!!f*RKnb}E{R@w*O$Le+cgV+E}? zHbdnmvV6X&LMjBI&jdWx)x&cRk*@3CPjqDt55`ZtrFQl<*TVluow}lQ94V;b=WFlW zK1DW;Up=j=ZN^v)?7YUwOUT8{_Sbl-kWQFsp6n2;g%c_h7s(u3uie`~T18uEP-@?> zBW9qe4d>}0yx%G6Pdb0>=e@YFu+jT_v&!WqfOR@>OfQ-gSgkNOcl*u_4GS{Fyej3q z$IkfTu%(f)X?s;1OENNt?xJYV!O%`M@(Lr=WurpMQ7W*=y)P-@7c7Os{XRVn%`U0K z2hBe_AEut+WIfje=Tstx2YRz#DbNXdRrm17L;zg{?)Q2Q+K8yGuD zGD3u7A1hE*XX0u56>x^mYO1n#>(R%yZfzB=HfIH!5G;6Adi4$V&JTN~L*8*VqrxZ` z1`k7BD(VEY#wQLGO-+n>oV6t}Yl$}a#pNB{VU|>afIsk zN-gl8tNkw9J>v*-)F>yHC~S_0edFij`~0rvnMl@xIfOYgD*wOI^cvB}gm6}RczAdz zQA3c4QZ8dUI=Yt5&V46z8gR#0u59S6hpwikrmmWy+GDN>`pcp$|Fm#$@RaCSZ4LNn z*)h5zX0`ReTV7s98rQb+RxJq?sfWElJW(Bf1E?N!J}XzPGMJWchW_t?#zk|9q$jJg zgIE2VhLfR@HUtrEe{2VKOf}>jRC}``ubZ2GpU{sLgyj^$Mi6Sr$6YcfI7#iakm&@= zh?Um-OCvP@q{A0zn(kn4ecI+CX8mZ6$IZ7AP&Z@|Y>mw!EN+#iqK~a*ox3?cBjr$5(KI0-sD4T(1jzyM} zhH<&9DJqmgkm$Ol@;3t0^nYByHXiioofr=>bdl9p`Y!>GUdeN*{jRXX8C!F9H7L}^ zW!$ScM@Q0mDcYtWX+j&4OUj6N7zfisrQgcQ{rsDHd`d)0YCI@{H0!7iBDtu|(2_x} zkR`|xQla`nUyZhH$X2y71F;TW1BeN1A0k$by|KNuwaaM&;Uns8Gw1#8G>Y^pw;Ijw z1?`Nv6O$wAMWO0f|K!k#89;i3ivL{1I4LgvwQIHuJscj}gQkFowFkAMJ7N0e&U?Wc zkP1Rd)DEPTATXTtHmaC2v3>dKrPse;Zy?VzoEal%9g+$G<5?sZjC%jmestp+X=DJ3 zMAjG{%lQ@2sG}12TPHj?n6yemr)na}+@wm|NNpWO+un@O{L9TGg8PrnKC1&1i}Xim zV~|8#|H&5?o#?%9wz#se9nn7QV!2c4PAk8l+MCH~g2+hF;Z3iyS$kz+RnV2E1|8H> zRehd%BUR&>o{>A;eD2$9!Rk(2xW!XqwHO@2xWiv3y8rCpp~ z&TD@6kPP%ee`WPuHh=#e=8RD4lA=pj5R&*hyR^sqPXfQ52(sJ;oP!^m<=*o9u_=TO zXjbh*pnLm%l%CbwOM_GQ6(KhlqvPXIln4`5B|=0Wae{(^yp`>%UqM~4I3~tRg?=(S zOR~z)%cD{g0cr$ofdtlUwZZl*j{BTC^va9Or0HJ5`uBFSY;|TcKb#BNQ`L^$nZGN( zR$${?q&_S0XQ=18+`&dv)zbaHK`h<_+snhV_YDzxT1&)8 zDbT#swQ_WJ+W#=ygRGGfEze3Ws0&Id;4g@bh@U>E3Xxj;lo(~>w&&nyYG9o}spzC) zrIR+HPWubFFVYQ>D(8F!k>+}>fhu5jmpI8AILONyAm{uHiMX8{Gha$-e6-BM-;Fds z96DH8wMYap0`|h0woQFS8`s{o4F#nL)BY8tEmOrALwn5iRs%XSkyJ`ox@OQjL%Ive z$ZnZlSTN6o!%;p&u_xR`NKZ^R?K+y3@MUv4oUs>~-#17jD8X%1B==G%WmtR;?ZiNy zr}U&<8(UEQCMqGYER;qT7Iah~2-^(HC3`gLK`J*}?5cVPM*1r7hs;~im5yEuh_Z#A zIXsD~EcaD5cTfU?!;ngG(Se}5#=|>YHn1m~Z@+N|mC&Kd%Jlxe6%P$wYjtsjtrgF` zoQbO!t3D;pWbNd1i0zIL{mc&5j+la(Bt*yMhHRZ@8L+T+Prsr~+a}|hgCpYl)5x1F zyjs3<<2^#*c3UZ?!pVIG8i%Qm?3gjk5(m#lO*$z}=N_Y|51rDg%Vf{sw0lxsE zYeRLKHJP#|&oj?nC12# z`=6Dw`?6fBeS7Y6UeK#v0n${}xL6-Z!IE80YD6$8AV@bfPyj zB_*ZaW;^Z4l>l-aTJctChZ#&`o2taXw|dW=@)&D7Y1S8bq;A8*!^^2r2KhEV2g8zW zhsjd=Y~`~F9@bYn#yZ*q9+?Mbk|ugNt@bWJ5g}`Ewi&Cpv$~3}>-vWj@M|*twY)U@ z)yPO$2Fl3SXeJh%ax)BUkHDBYXOoti*U`wtXkWTNXfWF=sCG7xV)XvYE+_hO1Jw^% zRN}4rD)0w~h@4}lLZYtO%>cV2_@*bp=Ha)aH>&#m=LL1nBQNSHbdnB0+Pw;Vy^>1T zG1mFWiJoZX|8Bd8El6kZDl03US4Kp{_J`CC20OiHxQtoc{$3b%>d%f2Gd?D#mE{^> zVzy)Wt8Z16WQq#zJCH%ys*+@xBL1qX!tZDug(}F;cJv-dx;g`fh@=;#>EJ9O=S;Hc zbH9JJAUhRDEZyE<&b>_e*ZzIneA(yFRQQuUd)ar!8-JB7ib4MY-ZF=~fmJV8p9@0a>?I39h?A)IjU z^T-?7vc1ZNou7XO!vYa)jn8garc@s&3=BE5W!HfF9L3f#HzPc~L`1`cZk zHJmx4UrRjm)b%$0&VdLnP0RML0?3F)&^<6lAP}vBH?2dkYL~tTYL4WLR>Wz!jEnzN zNBStX>KK)yYon6GBy3ylyfTCybnV0v{kV5N9MeUhQq%z(r|9e4!~{jw+&DaQw)Krx z-eGkWiRl9&sjXl4i(FO>prat&=EmKh8pCRV_`wsPU-Lq}OBgkGPCpWPs2OKEQIFWDqj*zY?w7!Klhou1WJd4s^j9lK^8eRRUtqV;tD%5GHZgU-<=l`iU~Oi`<98;UNVAdvEr#2w#ZY5{X7vW?c?t?03yVx9 z5&Qb%O{tUa;NajT%Hs)2%gzLeRSsyAk%`7guffHjJU8S-(n4O9vMg7M3)9P?}bo zGwpdL5Kn3Bru$r@nuSbx=mtd#KHOa&@J}s*L(n?q4Mz~Yuy5qC;7@T zZdlI6IsxR~yNY!XRw_e3e$$Qtm#PDO3oA3k#)iFam0{)bc-8pA;v$)!y}JfinFNplSYuY> z;qmkH3ra{>1yL~NvnP7~uJYdMQdq9`I~SRlXrryIP3HN&7|W5U6q$h|{nb`7@y9HZ z+lCh&9xlkoH+gOrJ6^D$tn=_8w=H@tq5lG5XMKEUZ4t z;w2|1_l=HP1wq9v$9EfrJjp&ZvG|N^FONsbl0K%zI$i{@qq-X^MhpXB=?4V+2M6$s zjOIeKi7@XiHZBg1yz!&aaa1g!{Fc1ldCbE&e!`&l8`>RcsD%aPJN93LgJw-(ELGd- zFjzji_grK(TvQ)>o=qOp$B~{81n{#t_aWyDf^t7fqrFDbbD$$m@}<7Mz6Pj&SoVJf zS=Kd@lf`#Z3`;c-|+kCoUZgYjfPaG=j_Lv7?|j%)# zGi6(KJPD(ib6diHE07}e0IO(qz&cjQrU-bxSoxjtGY4mt0SCWmlyvDPR^f+aj387X z_j_}Os;hmyCeE?sf@!4I{rds5^z=<96PK@IJ_{}xQUR6YT#Lf`vX<6!SI2>DN0)(# zwU1AfRR-JI+G^Q(Hp|T-XWV(xw7snpAYU}J)V%!y^JODHeacJu)ZWqYm6;d0``v4= z6{mT^~n!X&4w-gUF#&M!|l@*+0&KL%&1%hp?O~;_XYng7(>EkIs`{p^0L~ z_jx>-6XV{tcA2E4>S~z$fE(ofUMW8?7_M*+fJ8>>8Yqu_Zp>u$0(amNe2(2bHk#SJ za*ubX!iH-Ch`4D;wSSZgVu&c{o@9VVbsTAC8{?^W`WaKZPS>j)EL3^7j|qE>Y;4+d zi}72;$mj1`Db&5}>mIj>Fpk)sNC+r0ZRHvMD?9r&7 z(1?^+ufOO#QH`slq=P~#cRd)5r!>tojeJ`f%1TP{> zE3Z1f4@T?5309>>Cr)#weO<#AT$~nGvyE2U9Ud#i@I^u1jNjUZ4jvxmm50Auw?R7A z@|HnL?9U~mQ)2B*!~7mLlCU-dK!jV$#88|XnMwtZx8nHo5lZSvg)As&*+p{W<0!&R zNt}FjNXtOXsrLAfR6<@jeTS}@OcGo>uVrNnIqYmbP?Yj$)`0$5qL@oZD6_;uW?XAa ziznqQD9-iEiFmPKr&1&UVdt5aG3I^`@$GQw?*tw6x;mCl#__bJzua1!YP1G(%^!m1 zzO}}HC!l6xKF1ZkfSlc@lrYjQsyD4hK9(Y~#=6xbB>smN&qdOm{|Ezf`D!oEWNGqW^Et8cuC45Q^fCICVuAdJm+Pd z@kjTMVtaK0Fe7;o{GU++29nxql6@MIq(ca(1#GjqGjiu+E;BGuq7m?4G8HRGDQ-LA z%VDV@MsCIY^Z&pNWWluG=KPwcaAR%6dv`@R=N5eHX?S<{dri?OO>Jk5qRRb+%YMGM$13oT?S%fr^Ub5vEfED4P2{po}v$F{Ot)j^#TS zKxm?dEOL-0(8Ec3^mSCpqj{ABPSe14FnWAgiF{0P`XD$V1Bj6}G=I*puD2xD-6t5O zN3`bSpjt*QHp5n8f|dyGOu>QDaMS-#uGG}DK~t#%?d~^zAlCuD#H{CUdU`ex`=81J z-ghH1<{`$$t!y7}`)z)R=(rzl7@MoDt6$YJR=gT7I3n>J3i#J;cJ?M_kEOfd?m<;* zYU*Co#!m-~vcQ6o3gA|c+ej(bsTMv`<26$Y6TPQ>CJLQj%?n?S%7Rr4F}qJ_-gX#S z0#qg&3?m2ABvBm01*R%%v}f;CC~^R=_@ZNd6NBk`4c0-t*>Au1?4ePW?(-qEGxUQ* z+sN*XZrSY?t{g2nxj?VUi;1~RV$St+U(3$~Oe%JOT)TX#^BB-5%KI6S#RUkMJNRuX z(JO12nEYfO$?t5DmFw&4GjVcq+Wtf7GazU+L=)G-e|j8XRF3~Q$MYK?z3wp~E*5U$ zaiv)MiCXFtW#u6lBy&lB)jbNXU2wDL*T~s?C5*n59v=Ao5(cV#|5<=Jq43FcCOogA zqouXgs_qSWk1P2g8F>my=Ew(eShuk)$7^O5rX&y5@=E{R*PES> zz6b|${9!T-w&2{niz!jTBP8gXgTGpvCQjYZZhAN3x5MZ_i zVrDS;9hWo2lC=W_=qXE?OPB!t@iAWW72)FTlIpz?I}3|aOMZRB;VOq5uNnTtymLep zTHsznYFZk5Hy<8$AH^2JbpES8+Jf=%%|nhU?S5uAD{XcHQd$LW@dE;R^2g{-b1V(e$+azVr*Oi>zy2}HZ!@(|@L;|ZnxED7v2wM>WzdVqcC5fOthcu}Z|y813ekw* zmBQAt-?`9;P|B3psWoivG*zkR<9~R% z^m8}-&)l{N@$rb5`OD=4J(itEe?MlL81(_)z{@x)(ZxB48oOFF~SToT$wa*9Nd zFH*rgj~5cWiKQ81Kr;j#7pKAn?}=M3{PFyY=(jp5Bi{~`I`Z+NG$rU@JZqUUU>Vp6 zUbNI{?4y!H2h1k@m_Uwl3~G36nw`tV%@NTGaWTHSQZA!@XyvSZ3}^ zuUJ&=_RZ%PPpR{j_9$Lm2h;N9fxPbH#3m`zon^7=U<{DKS$xs-!W0`P0lfex@bK7Q z8W|+(8}V)seRHs!UA~epbu`7kG$FAg-~N&8%mN=3frq~<)Cs|qXNq^wD-aP9!uOuW zBFYwK`jV`NS2*LOb~2ilClZcGiulgcpE1H5(1AizL?$M`5(}djV83}2{o09+hv@R| z^!p<3Q9_T&Pf~dvtL_YoXHHSK4^o zbh4-5yxQUM-Q;KB83ig{2j1~Ohr1Djuj|oh3`}ayjr8>!^Xd!#!JF;H?;zQZH7dax zzYASNX7g%d8ca`hSTCP5<$gsaEF?%RoVG<7*Nj!u;b+i7Jm%}!YC zQ7N7WqSR}#%VUDab#yk6><&2=i>Q0*nwZKp%qf zqKP%O1K=w?f_BOFr+26@`|W}K!fl?!TsX7edmt6>k2+JVBL7!=@ihRYa>LeYQm@j=m!>1-o4vXAdJx1G>~Y-7`DC?$PmX%Rfn07Q%SSd z0vEhMIBkEbEgZZmP;Vax66Bm+>wnZwKwEq@4!Wn3f@4KK1mrYkqLlm8W*1~eo_q>h*>l6E>?xCR1!d6bA$HArzc{a21}_Qv*Vn} z9l_`VX273cAM>F|AXZ+_jKP`xZdU=_Y~x^<+#-_tp|tE7=cr}`bsYVpr)-1@jIM~%DMpbpvFE!h?Ri2J_6`nkDDj} z!!186f&EJR!UxanXUhfl(1`*l7z~}!os<{WXgDomEG?L!ipLtvF-(9@_$*6$yG{u)=zy=0bdO+6J z8=YRKY0r-a#0OJ#&->sj~I9(e=fO%x;yq9euYa8a_B+Ja zlYm^*Je=y7>@$fT<{4=CV_zQujUNWE)_|}BraEK2fp%*9!5EA``AU-lw@X`_SbV_@odKN zvr+yo+Nm8zFJU6fM=G!*N#5i0XPx>j+Nnc6lVPDW0?g`}OzeZ@8LS^iz?03D$Tmz* zM@s|9U_3oLb5?piAnVNE5vo%pDKdc%^=Mm|U>F>rwIJv2F=0>h;9t`_9KRBD&Tlm~ zR6Si>8vV)#dy^<1*{Sx>84*;V70)<2K7Q$DI{jS$*z>!#0+DTELU^%Tv3~r8RzRia zdFE3I-`W5PcMVwNF%=jfCMiI1Y}_rV)7XTIpAD1*O`agYC>(TB0LO`=Zf(1caouU) zGzQErXUm~#G}q&e65qiTzE7orjtJ;tI56lWX1${VQadvt@99c_K%r+a+A7(Y;u=U* z0RYr=Kzdj5R0XVlXal>hUlKhdRxuFEli`&ormUBKZUzpmc78i~F(2&DKwBWXLd zF9*G^{fIp@)!Xj?jWl+p7!-d*=b?;avggOAh5@~G^xISBTpgaL()(RPhYG4#T`Zzl zsffUXcDcmoPw!n(DWdUXq^~^_h$R5kXu3pJzQ%(&k2F3&3!CrH8)u|aWCc&+>)d{W z0o8R7!5qHBFHK>z47fPD&9d4SW`jlXZNQByh$*m_2Ehfr*I>toCFzebwdY%Uu)3=@ zNh6lK`bt}ZwO&rO>7PpB_XPk{x!KtCH&zcEpdAxe`@XXWqlZ_(U<$g?i&zO*si0uL zbp&$=;VA$WIl+D@I?6ZC4*s}-VQn7Plbo(Dy+L+9^t`ri6DpYG{=pii`%&)+|e{=2fa3n_!XS7CT zm6bJ0ZYMwyV6JfTd(Uho{&2)IlQT2-yT2@%ao}w>wyCI&sk0>MGa#NKF&g2e7)L7R zu-&M=d{BIH99rqN^5u#0lcBApHY?LLu~Rnb+rXYLGukUL_z|XkwOH|jm&vEsKzuu&Nz{En zXGqt}f;_MRK^q}?%V50Zw|NVfegyg#HyHDn-6Z`%t3&^HTG#kt24!~CR>P&ldwini zOqCLXe`}|-qY4-E2JZfmo$p$UCYvo^)@!{{-s9acR4xjJ7R&xK6-$g<&D?7m+NB~z z*1e)0vl2T8eGJb;d2hC!Dfiw1x*s>k^>Y^kU}EC)AI`_h&b~AqFHEf1sIY+B{TB5o zyA9q4S>Vj{oT$h~c4<6=Xg@T}qot?OGW14Hmqk)*$HX9ELU?s=hn3n&f@hmEIG_#U z;)3Sq>hAZ6-FY6R|1)c0u2o;ZZ}m9A9xiCFmosyynoT?V_n_~(L^iMUJF?-`|4yLf zQyoUK`OaZu`rFsQ(XZ2#Vk#2!tEfDWnH-KHbHKcE{zrlH-+GJf@F>bsR#Y%;iSreh zc}Fve_PgQ3Y*^L^(Juy#YcW%xYxc~;qyE5lmvp(}#?|#%$$Rt?T zl@Ka*?FM1oiWP5a?Z?z5(hpOKEYL}oI_S&i;=hmh{kBCcz>)wT)BKY3ujXb>tBvGYPf_P`_M#pbqvR0ODoRBt_P{$5HX!~^DNm0Rp+^Z9Uvj+>9yRi|IRxwG@Dv07POa^2p}zAAddiJpO}dO6?LbP$rFXCvIP z&>R&e!ierdth!1szmSMg3n{kt9xyy=C<2DCm(#jhNdL-NS^igg0JQoiuR8m=P3!#h zoa`p~xc)9)aecr(ym+c=?9<)5d+UPjysy*MQ>)NLb>Gm`CB~0~Nisxhqb{x%+7%Vm zj=RC!C=J!hf^yEyZjY6f)}MwE=#^i7 zhv_utTVy^v7H=5$Ya4Dc4ts#X`s$;qzzUYn?mmQ|i6&8N_>^A24fuC>o zCv5RvMpbqOUrh7li#x9#nGEITL8|s@S5>4bnP83r3PsK?1A0O=?w_aXa2%^E>s3m6 z+iB*@iJ9q=dV>%xr%>^Oye#PxU1GeN!h>AAnwj_S5p+2gTfqOuL%EWFPkd7N1krP+ z$E3?RDMq(gAWIg$M8qkNX}xdN+0Q%3GB97+`h}Qcac)&GF8yvWW_5>?^LYnhX!ZMw zNs$smD{lMMqWYrtYmi@Sdo1qB_@8VTRwve0&oPeqp?4ytgVUoEw!t5ex2`t~___7C z304$O?-uc*yJ7yxI)iBoM?%*15jdffO_6Z5T-cAm50JkqFf7f$Qs?cZL1cf5nj(pS zL`TBfq}ZL;%^!}3WJ0TwKrkI7V}Uml0( z^pj)uhvT1{0EnvpcgE{_+r=^$zgjYMupk<(Upl2sd-jja0GI8NvDBk$Bk&%HdyfccJ$ zw-4-ro<@#J12=@C#TUJBb}2T$!l0>ShOM|L z2d!Id^VxB=W)k<6-obdDu4dW7mf)BUbmz~*0(3iCfH?ZNm!t8oc-Vy`h*+<#$fT>7 zF=_qRLA;E2GXTg5Y6}n?dw++UXXYp5Wojz*&zRW47Z?osbJ`a8gl@sE=Ztvo&X*+^IVXoT72yF$v3_n*IT)&gn<%@+jkmx3)C3 zG}O1I3hEW625K>cnAGCz7onM6)s=tg2PjqDIM3Hyzk+@@|Q6Y zrx0<_=6$Kw4)RNcakRzElGb;vRbm;i*Fn*-}3*PEwKR51`OP` z8^3kQRxbB+yXfBHm^x#nVBg{lhrb>`#?>VNMOPRXM);Youf33J$kOAvUjZqTz`mf} zuancI?msE{?lbNPFbK~<#yab&3woZdH&#?*fC#y0oUo$6d(?Vmli``renVN^u%pQ* zwTn7mr~T^s^n|P%$Vl(mhNP8a$u8bBvPlRIPdDC>N@FBi%_1XyA znz}5JVfs{HIJ+cDAsR3+cY(?6L&-5if3+y*V%NIL;a%HiheadEnT=P=n>R|8$p$33 z4OtVrHoO>~Egr#}QrvU8Dlu^SdpWGO#Su_|vS*uHYSZJv;g7WhE9>y0Nk@3CPoIL( zOxfg$@f^gU;6hUuAecJO+bgVnf6s9R&MPd)djdp%>JI=av;#awvjZ=Mjh(8;G@8t< zjd=Bay~3mFO?r}f5q+AwYRO_lO z90fKaQzh~Kx1uQuuqfYbkFkF9iw@HvO>_c^a?u^>)F zj?^G5_0r$riQPc$B@JHKllE7BNCk3z*JJF&+Ct)}=DCJWZT_m@Wf~JzXNUW|Yyd<~ zw({Z!B`f0YRV}bEt32zJSF1O4R2m`{G1)S+n?7HF;r@nEYQaiD-Go$UZf?8cyiaIl zNaXe1aKL)aA3{|d0KaR#_X zzX66mSJ(fD5dK#QROx5mSL1N7Dacy>9n_Wb&e+zUs1X%2H zL4o3k^`wrF7diR(Ymzi;;~O5KtKE&=yEZ2CFN8!#O3GF$?s4R#&d=+h1^><8J6q>+m_pdPn_fdYtm%&^GO6VAWR|@W7+Vl32!$S_0S zp7=I#134QoX7Qo8w0BpXNkB)VFc7~|Ai)h=TuFNZSe%W?4^C;p*c*B}($A44NuS#n zzkkx-JS#YEI${=GJ65N9I??$_~xy^3b5>)Je{d6#=^LSjt7vbfN$q`0V@vPRr2+kXCSW?=;Gemm~w8JXZ; zE-*;^yo2?-j(35;l{M>{rSxIgm9?P-sO0*+jF@zv;YkVJBe@r&gu@ewPIbu>GVZ$U zZZU;!8?e-0WDUyCb>vD5K2=4uQ_h}=uii@Ctuv~V85q+OvbSvCPOgi9!e;wj%-z(i zsvKd|eW|*RTS2fo`}_y;u<2t5(C?J#rQH8I2Ny2lfl%7s94wF*vG`z>eyOIqgxfQF z;r;4%QKt{R=eq&B^0!Iv<{#o5^xjFCuV0deouuKf6%7$$s+;AZxPU42=k&KMM$(tYiZV$+@SOF1{ zw&!xP*q@4{I3sBOSYZzv9GGDbmrfscp1DrjI(;YJ-mUbKmQ;Oj6drdZPN!bBAJb!RarQR9Wpyg72<0 zq~tNt05m>pmweZ#(7xQYemSkw+sUrs`K1!V@H-1iHG{LSR|(VS4ef;zbPUy8>qyd7 z?(<3ha2600T^6%_>HMKSlg=ma|3K7?>tf@r! znpOW+ReJdnfP>(||3U-B@)JDhfLS}&qyuGObrY%i!VF2@dWRt$De_vmLpP0&Y7HW^ z3neG=9lg8R1g%4WrjndGlK-*_t}Iyt;%mS_UY!i)q@<$GI;-FLp7-96kEF+T z5uIZvyp&j)TOc>&f?S2t92P9jg$FcGulgv2ZYMu}OWUscV> zyn0H103eI&aH|(N(xx!hg09kyjbEV=aW<$NwBs(|=?oo6rcHJgc@*|LJ_Xt=7UzYL z(HCIDKfT3;ARmGP&kWbp6Wig|wzuZz=L87S8@%f#)YD|GXbkx#-(fs!qOuIqS9=?) z&8r*@8oKH1>5HaAF@J1+5zw=7blyw6na|(QFRhN}9Xk#N)4x?WWrMiJL|B3HvR?h< zy4u+M!CEfNbI|dgn6#kf?pJPzJl=4s&OFuESWzB!%)`w3yD3TWgaFvBZ2FJ${@Nh? zoD>fCKuqKfWS7GofPoGLl!DskBJPKwxk=Ewo3|Rq#GeV_|LQXWp6DD;qA9l!_m_(Q z<0rX$z=}V9FA)4Y2K<-8F8|HlWElcibrL1)f(0)G>#09BE{f6og+cdzCo=hmGq zpOwp4+!E`@U6sI08mUe@9GEzbTBKjKfAYtVgs5;% zM>mU}PwvrQDPh0sdjGljCxk&+72@2I!wptCH4Rrpf z-elXs-jN8*yg|6p4*wy;zmymRA`U^C(=RcXsijs=vXY;b%;3)|_wycj8ZR7d4oQ8^ zOB^Y#WB0Ikh^l@*5$B+!3ZA35@~AcBwj2cVx)#wb{B zf(Wit5G3&UBskpejT7$Iw$BK6Qktn>-S=!+pW#$29$t}|IdYKZ_Gmm(T`fA9QuzT4 zRPQw;-Y2$tL?k~eJWp&bnr7;U4c!WCK6zfN70BgxJkLxHj9RX8>>SeGpt$(2udZ7` z09$D&^XXQ&`9N#MmZ+)s{rfFvr;@!cCY4Z+U%2?$*KapYvD=-@K5CnG^B3Ot(1oG$?knEv*=K!#msy$k!2;g!}71Mp;~N&`*~4eli!1Px~LW&0MMKKbZtxf1>&(suUdYkNZ?^l(@@_>nbGhENqUwCb@suymp`pqxugigknD;lq%F?etAQ&azx^;5i}i zlt{7VXzf2AiaB-QeAUSz5A2XSg6sSa=aj98DBW~nrWIDm3hN$=& zw;t-Z1o)5Fd)S|kYJY9RN#<-W_GdE7{Cpep2LWx5=9VFs5U%sw4vh~XT4H2RYaQ1K zPZa;fUSuf}*9Hzh4HWh}C@&2I7>&a!vZoiAn<`|Q8g|u>OhhfXMWS#+AhkhI^DSQE zTFTLzHe$X}SQ-<*+kQt=vrcOIaq7lpWP_NHeTyc%PPw}O&DYucd}db0LagQZXK!L7 zR5f9uRX-0ZO7nmTpxjV-i#MjlJk_E4M+c#%F%MEZ!Lw z#|h7T3|?M3JxNLS&~voVnmFg?>?6lrn64Y=H*dcz=$*d|U+#C!ItBRN799gfmt1qe^~qPHi$qM`t(5f% zIc6=qX)R{+oSLdDjed`PQnwE`Y3x(&#Vk+b^l=uKXlS1_z}jAwTTnPpRCM4v-^_EO zv(k+vC8YpL4(MgetJ+@Twqh}K!uJ|ijW@3WY!5N-&~vp~ifMIwg{CJxhhJ>Mdy`s@ z7hL+k`=S#9{O4D(owBFp#w^(*L|is@o|dYDG@Vh5)-;s79rJzTVyB-g+WI1|S&YNd zFd5?Zu!PxMbs>D5r5e7j_gn#--D)3Z_YN0DsK~9{1}Q0k%Z*Gir;Y;Dg+|dJm0_ z)1#6?iD*R??hxyeK2d%gyOu6y{+>1l)GDOa)LaV6-7&vnxd}xkpN!YRKIS5oEG+dG z3$YNd9E|sU{n}PiW4L}?Gomi%HP{oZ!zFvs>sx-47mjGRTrq~u zvGbbtt>zH|P9N24$>n&Ty`+BpTvZMh{wDIa|JliYxDOtetfU&3@#U~T@D$cC(01JF za!wyn{QSz1nr-xRS?xU4auVj_D}k2qVX=*KCV596%xX@4vVCJ`EjTe*V{8U z*lGDN!S1ggGXbLD^1f72BimPg?85v@Pd=V*#{`l(H*SX|V{&3)Dt2ZYeQDyuJzP(( znD_kPa#S{&E?_2o)MI4Usx?dVNHP`i8xTPo0|q`*tZ2x@8DB>IPhsY&b`A?TxLSv>@{mXL8P>*pyUc-Y&qdY$9mS)mz~@ zj}kdCqm2K&==Ey~Q0I|XGoDdW#w>`I=JrxjsEyv636-Q(ZOM%}gUduIBt=;1a(*a2!}RJ~U3wLuYe$hxwnA17I|N-}$-NY#tVV z@z+6r;5WDdX(cdU95Q>lS7Y9rYIOgG1au7~sBR!eap^iMHSDH#Qc6dT^1<~heBDon z(m-tHY-I~=v#Vn zkXfTT?!b;YN=yB%ir?9R#B8$GsoqQyG5hhunMGw{Z2}J7B_V+Wcv7~#8wK6EPAAoc zQd_=6suP!gjG6J8aYWt4@wL=pcgb`ogHDx1MMZ=~II}+ZywQXwcgvVI4nRzvuhrtd z@CjFd<@Y;o^2|@wcxAHZD<;J7Uq__+(cH?h;WKW0KA-itLs9lnQ{~v=RZ>zC%`WqF zF{w5B=s7E~MtgGLOExU6=sX*-hNB&NKL@K?Y#rApJe;!n5T>fc7k`VB7QLPOBdk1z zgRkGVZoWPlyLR@dHBr|<({{H!{5riI9uY~hweYJobsp&l&2SwI2Ajpjzk+^qL-V(S zL(X+8V5(q%N98E zXT$uL!Ng$WnOdtfL=2oHp0bkskyqy)W1>ZIy0*Q7&{5bMzbb42k5morKv=gO+l6J_ zJ8V3_J4_$n;<(FYt?EH4PwKAfJygoqykqgJTO)w7+Ih+;Gue=_7yjkMss&tdKuWxt zF6n95<1_usbuXX<3m5Ny^>RzU-aS7#5m8vyS=+JHIZ*Pch=1ewO6I&6b>#wGLmj*D zx!oh~HaorOhQ*E#T0$u;#b6hM*<6QQ@@|Q-tMr5=OoU!Wm}A_sUy_ir)z|UMy$9u) zn2LKrLg_Fgo*XmLt}!>%e=;hH;Cz<3(iLRr%g&I>#Vt07Qm_U3?XBDd0uq#FsptO2 z4D?C-OO$>d{343$3O(x16-E@pN$e+7*_Q#-oX9+w10EkH*b@Ap`;Hr^7aly@k(ML% ziar8?LVRUQjh`3yU-_II)L$HcQ4ZVk-=hzvdX!#4#18_}tz47*T-B9>@oh`3M}u=K=Sq$XyY%}RZ>YmqBAPUy9>m6&COpn5bj4HJLX z!S(qLmoTe}7T^=NU5ohBXiJl7TiG%Mt<|$ai1Kz(qSv_d+r;9+_)nTn)}6`O=9c3R z+P;UNjg?<+O);=Wvnu^u9?qLOHf(Szj`Cd{Ef(S3TjVx9h%okkveyr`jNaZ1CQ|Yy zwLV;IzucL8@?9|SWGs*|@mtLZ?=zP+)(P^HUKgmyr#JtcK}uY$?Po*QMUq-8vp(JT zoZPX69$VyTUb`p=g2jgLUSXXBGc@h-MmCvG$F2N;A)MLd&q;td?pt0?8LN1fZ<@JpDEAoDX_AO@E?Bq zpyHOgU1o~NDI6=h4v?##S$KT(*Ly46YICt`e4;}xgs~wFE@u63MRH*p+=H6BhC;hTZd?C8A}e) zlek|U3DC3nsD8JiPoi+2b1g0N*;35*xS-6`>9!#ht*zFLBl>ylN4-4xZAUu~l*mv@ z;v@*m3$j1ESg|FcUK881$2gqG$rk;Aofyn7PGRE}Aqjjlf|?u78YUBIF2Jk=6*R3C zYj@otA<9|G48$I6MLGK+l{?H*DrL_ZH;NuVsR*R(4cw*)H19-+cS`-Zb0G|0({kc? zM7EL)^8=^pNtLy0O(nQ1?L7jLs$?>|e=&pC2{r_~&&^2Ve85DciG0y%VGC4A+ z+c$v$A>s||@i?WWN^4BYMb&OXxC9zP zYIvAUdNJPyt?;cz{?t%ad-eV)(WP6J?=Cro;ZH9?IV`VfHD{ftHLpNXpg7Q*1l24B zzNjG(TflPgtZ_>~6YU64&8azgA3_)=n9Imd40Z$;a=m-YVC@z-VLfZQ7t{}y8EOZ` z9*|nAZsxpIJxugm`N74#C`WK~?v%zGtV?Ojwpz=+jOR@w?N?1JJ4m>A;vC?tb>p`; zJ$~Sc$Qd0h*S?`$^8BtT+#}vQzuo~l7xyfjZ_Vr#wjU38te=x8nhA>~SR*)1)M4C= zc;8sk%RuY6q+#TT`gnTK0E1~Xa|^PCOZD)%Y$Gp{w*J59 zhx`xyOwf?Ak*W4jU!q{W5lj;duehENpzpqaM^J8meRd4>(#ll^Z44K*6N=x$&&>Apb=IT>ogBFLLZ{$^wVy`2j5^fv@!?n>hN2TzV%qdAOS^(O!&M#(muGO1u__ zwEy;yd|_qpX1spK+HU>u&b$Jb5(KUvKoyUm8wO?iG2`hjF>!z*5-w!J72VQCSn{0r zl8CO{jUwFQkC-skngh)Mnj!UHf#8kpjx1t_qnRb0{LRE3Xk+JPI&3|g}#dT)V!}Fq9&j^>uEPuqo^xJw?N0iPdEIj#~ zPCgln9*<^{wCfC;52i)?b%{Fr$Y$Oq?fn#{Rk3BMr5G zu7oHDzdU**kmfw>f?{Daf72b2uR=hD9Hwf`am~N2YD<6~#4q;OBqFkIqN4KX6Tj!& zyb>k|y%%+vmx$<5T)+9&+r1zA{2{j8Lku}kF4vdcD&O64@MK-j;QqG?>>g?bd$~!b z6(O*hw-QD>&h8yHf?l+GL$#=5Hcb^rlcA5Yl2JPJgGlTn{#TRnayS zHjpXli$VL6T2nT`>=uRSSHZba#3r*($x}uZjBT`5M#!p9qBapXOy?G1DtfUSd5^CV zdqtDbFpGtaJcJg3FbuN425ZgQTpI#?DznqM5)t4 z3@;9cQGN#DL0eI3QI4m(K-s8MRRe9`^KL-m=fQNx0e`Vl4boyLM@d8>ASpy7a>IN8 z200)b8ej`ZW@f{RI~mnDI>xK+#nHL2hGN8)SEEF~l^rPfJK^Y{Lfy`GVwT^vv@Vsn zY-{nMb#N5qye_fPiy-!>X$yJ`zxjiQydy4y7jU}m09gon04gKs#Xqj}Nsx&b`gC4W zTpgFJZ1*|2=f$0WZf8g<%Z0%pmp4;20$53xfYf?h9zS$F;fk52EGYyofL65Qvy`#C zV0qKxvPH#PzYg~=stmy86uZG#)E#dJ+l-gSFJ`q?FCl4$|!Jkp~<|u+a zz`TxaE&3m5gX2bcI6l&1%1wK?&3wcAwZ1u8P9X1(T<6z2SNt6#3ToR~NRG zz-_13+6I2(11OkbI6XuV%E8X^PEWfb=_X7D zN&6_%AA7`>JE4I#?lCpn0(LgHk}0VpS|@<$QUfB2Y0yQRJ!>F*?14pdfXknxj^Yz9i%ad$ax zppOur5J7Ab`Bo~(+67-w2q?~v{860Ym+Dy4`>t(XcdgA&zR)#;JQw-WYWBhAO0^d5 zL!4K5!bJRmT$NNB?h=qXBCMpx@P+g(Sz%`GAO0=-Gx`9|Bw@62^ z7?4am@2#i9sU+7S&$Fhl1|o@>5qm1Zs2v;>p--=aHSvb|M_NbcB=W)Qc? zqsMWPX;Xfn{E+fR01DgV z)^@U%*Dde=G!~8FqHnXth7$J##8c)uYmLAodHTWX2mWwnQb)Kl!oot^jo?Ev-H7m4 zVN~2>Z!rBD|0%W;l+1lV2L&sLLuJCGay9rf6r-5F;^ss5h=`)WX$WQry0vIwAKT%* z#O?L=G42ixrP%4#bD8)79RBn4{(;Qqwi#v!xauV{{Ns#|>;(BHkbzhx2t^!7;on+n zXr*ooFwY^u&t+>{+Y^1h$P77+%C>yq_-EsCX8;d0H)(9dEW^xQEYdWqgF*zz;uD_n zO+81-AxS+2Z(gFMde?8Br5Q{+{FQlRjD12yAQ7hkUWN=cCm>s2lYP>b zDTDpeJj{7TpoN?d^~khLT|`E4g%PzCGT&Ug#G3hWp}BwGr=Qs`Z1WJg$iB&WggxQf zo+VN^&+wfplMuHj(0&V|h*Abw90UH9>$p_J(US&)v*YNLf9WvG_5a_U3@Li#@nJbE z_XU_xY0sp7dK4(_s?s@$(i3%?kxCxkj*7Ub0-LWN2yhy0Y1wFL+uT~3DV%W03k)c9 zZh;Dp%VsuM0lnDGAsS*EQoH6DS3?_0@gyVvM@_EpGoRlP+27x7w7&Z5Y@jUHr~A5c z$FB|s+$GrSNJ0ih;eW2jQ3MUK&dEG|bn$?;A``?)=r`WWBFXZgN8ya*FF{pZ& zaFe@xc8|`VElQHq#!&Idc2m^5KQMUvXBG$ejWNpLwfP!KY&MsVav(u-?x;FueG_Md z?8T0bkJzLweWVCJEsoyN^P<=~%kCCV%NJee@=PUn{T82y6D#=V?D^%@1g4AoLC?j= z*O-|CkGIPJZnYuF2)gpCIcYD?$kj@)=oZl)b8n^Sgw3!p&VM-qE+hmSm%3dNv3`;H z?`!1e_J{#l0<|vxu*1B6R&4^oA5ZOd;SD_~04LtPc#F($CI6$twwz~nb+w4paZuTf z@ISc#wvgu7_E6o@WP!W?8hYhw03JqT%!T(vJV%-$$cR$Rch6zG#@W<9L7N_P@vj_`j!z ze?T61PYjBr{|n*+sOz3X9<;$Xgs=X~P6HZ+K|`E>Jaf6ihmXn&b|^aU_stCHB$cjvd8+k?pw_foBe7c1&LSFXDJcagI6>r>4>j{x7n<>;K0y zlTPoCGW{2E2R<{y*Mo zOIie?PSaP_)YP)e%gcA$@TpCxRliQ7pGS>j$)i9ad7wdWbD+?x^c*A83Ul5w+5EOA zvAMm(n2DDN++Uxn*%da~-#4lBqTH*JO*HK);+4F_KEJKpu7%J#}0Tc8U@MPrc0e$21)~40HDeR!MDrg z5Bfd?o}FeF72PML6YBc5=+hE#(hl_Qk+HWQt$CQ>iM|{DXG(pIeQt8pgO6?>xBxTH z<3zZ+B>rGZShyvKNkPN3;RO$*A)xOeL+GhzbN`J3xuf^agVi<`bb$>xt6uA$%jWI^ zhspi5d6<347iyO!9?jJ)W{_w|Z9lg8)I!&MJg$cXYH5!q1|Don6`Q6N_65Di?99I1 z+>1D4nT=5N_>s!^>%LwB9ewKeGYSYv5-)@p$ojorX2{$FEJeg+UXy0fiaHa?BA?0C zF}hMO!?~N04?dGy5>)Bkr56%|^D;Ary(1&ObV$aJeO5G!c57kdrl^rBF>Xlo@;x#1 zG5vAM7n5(jP`dn> zMdh+5(>P-QzJ0SDXFSy&Y9k{GX-MgrS*7ab*om}&u7q@BgXDYL*YX7)${&2Xn?m%_ ztPKPv%G(znq9O${*EzY9SL%CG6yZ9e z#cAqYJo>4ylLbiTxqdbIQ=)wgnQ0s#ld+ED^pW0@nErHG8sLibu@np3;=rqtw}T=6 zhkIb@HLtnspux_ZaB&VL?d1LjPZ4Qa*{S3(CWX!S!4slqJg1&BYm*Z~uE$cD*i8V% zGL=|Hz99XJLBXwrmxH#CH9s<(oSrF+oS7+%l+l9Nc27y|vXjCeHafMBtcjQ4PV5bW z)tW}8X8iCOpTlIGc!KVl^whl=jXuVg~CZ2*T?i3mN1?oc@_|Xx0`0>Ga$`YK{ z5hT#dtPkUf!nnx;H@KcZ_E2PgtqHdfjcXDjw4e(@`?9fnr?>d9i1@@PG%fsCloEeC z9(w&``Dpd%&D}h(Iu&N{NwfQbR-+F0w>;4B8<{PgGr>RsTr`v9vEv$DtqzT%8ruGJ z3l@UeaJJT8Zje@-6Mr|N&)9tML-f0B-fv{+O5KNS)AQ^w=njRq)v!IboB6l}`z6^D ztFd9kWXGX?uf5d0xi_6?Km06U`@m&wXPH0S0;10kbMo$tqc+EUo&dD8b?2s%X<8KS zc)4o@xCR0H2I3wEq?}dVW)Ag$8oUZ8IX409$mlBjB_wNOgK-ty`k?-2M^i@zEg4A z%KUMovB$`gruoPx&FscTDL9j`#ItA5Lf(E*n1qGYmTOT?lE+v7PyF!I?Xt3(>{z-K z?e5Pde#fB^m;E(D^HaDuR0?mHXawsXQQ&rV<)GXAsF5yW?Dze7rHBIOhsgd6NqYtE z$s6;ChW&w#U?OsnV1y%mIs@5QP;d&8dP#!GB!f)N=CCIBS?a3ASPP=JG1H+j={Ri_ z_rqG^XU(Q){n(C6Blla>Y+mSK3lF(qj*(2~?9$xmX4QR**Ge-AG>XXdxZ92<$Sh~@ zsyH)t;{iqxLKDLvE&ykemUyPCn$Db*SiG33hK^P)S0D>ZeXQokem80hxEuwlK|zCpUyhS&@aIa(XV} zNf_t!abnMO@vPP|yW*2TmPBz{TDnC}oFD;Rvq=EbNg7_&sT8oqL{4hc{D@#uL#P6+ zcl4)`GGKZ7;?PGAB;#!Zk}MEV&CsWY>h;4>`1YsLuF4?sMk&$=+YwAknzRoD`~<90 z7fDWaQ*dOr+;OlqDMh8bF7FYQX(NScWIbZjtl<3u{{t>Eb9OchF5!%Z#NHW;$G$J> zIQLt|Th@baStm90eeEb)z&yY`)1uK1u>A7+hHemm3eYhGg3=Y3{yfda8?}T%T2yFXawbx3ZdADW;79{gFQsaR&_cAbgpu-XI?UCE z4~j8ikHW8q0(W+X0oOB!18m(Pf*Y{5b({4h`x1=T-I@OMvgh%cBosRxRgQ_>t|#tgmN;1vztz5$pmirZA}JT zbz@3fa|ybD18|naz&*62=LlDw_=5HjVygQWqguo2erLjR^~4D&0pDnLzkdc(Ic~2< zmZyD*{Y3mxBma%kVx76t{VH&|TO+M+uH8oV*8xK|1Ua(|!*vEJv%_CzQqG?W3oD0g za}uSmn!NxCiqrKj0j3o!F=)|j^Z8^Zns={EF5iuN$CNhgv~Q=ZC1a#xn(N7dM6{BO zFfSrCY3l)M$qEbC+? z_=M$GJCo(T&X9}#TM>(*e$%=W9u0?O!9`jZx6VqNhjWNo;><%UFBkt z9}&$3iqWgK(Y;+iac=aiJ@YHu+dqirlZi4vRKI`Y@YRoZvRu3Ke@w)HCP8jqW(*< zeE{qpp_(;v89!**iG0sh`Ov44XKN=HkNv(IrplRK$4=I!`pO4DnwxKCAfPg3v!phU zY4X@=4sWATa9T?R4kc)hNNk?f1M(iTSa0ZRN7Pb;x<7;K z5j%oGWN|BY|Cu@lc>>4BOoplBN8HNfQ*npqwQf~1Y4zSR+Dg`{Dnsb2JX&Z(yyA6c zVh_dD``u_*2q?<^%6pRdxFJ%|y9E2P=MFaqYlfdZVA9N-OiY; zz8tk-lcOz`%mNN7R~Mi+SFZ0^-C*y0poOTQPBZ&ql*WEAvGHqa=MCk#{moxXN z_tt*fC8FX{mdFtoBTgD}u@VODXwFFT7bkLBjB5?NH{Clmhn@c?OO*>C$Suh1i~%vK zgbT|f4=lv|_MX>LRJp&7oKnkpO1;tIo6m#l`#z1d^lrP=)@v}$D;xE_DZ=&5-n_cN zXO>A2kH>wEYOd4=cP|;MPF%6OVtG$H@nSqBV^?)SLC@!B)*EY&?B7cccG_rs79dko zXjxL*5j(7uOj-4iHI<{WD8Wk{QtEc2KwLEK-$$2h;L}1vwUo_sPHMwnmcIX*t9478 z;NxX*!60ja3!Rub)Da*By)Qd3(rFiy?^aKT%4F#tb^cL{m@cRNpb-gFnHYk!sL}Hj zXw8=<(YtLG3GNC{v?G&8PXOy{M+o5fAft8Yzqs2zZVGUWvPsID2fj>DD#{(AL z=@FD#K4v|QcLc6T#bU#mt6eQxzP zJvw-piKyiYu7AOiChcnH@uDj&hNd^qj(!Os+>2UU7Yndt?gw<5yC11F7n>NuRt9)Oc_9>-Po6+BZI&*nel0KtBvb!wYh0+}6pc z%jLarj=I_HN7!{Oami1vre#ABcXs$;^)f>Ao#Wjh>? zF?F=CtOjt36ycsHYe!FJ11-PBiqO$OZzhFRyCvQNlj^da5QM`e!{6ChQf_`a?A|p- zvD|{Z$fk=Jc^)x4iB%f>l>7;b8~*Rq+|z}YgQly!dU^GsWUe7OQ=igTvvVD6qO5v2 zGq@xGW`MZ>jPqewJ^B{q)gSPi+50f;06qb|W+`Mw;YrZV#}R)_K>|Rol=_jNGrbwA zy1{LmXWJCRe@k!^tFR!a<}T7F54;bXm8jAx5Xy9lL;6a6JSlrZ|*7M5`=B= zD3>HgWb2;o&YR|&RItHV!}<+U1|b}MqJ)(C!7%a8`tQ#O@$W`V`JDGqN*hlh4_Rww zu~cGVw%8{vX5Jea!H7Q+g;87(oU?0x{_bGgJUWf;4o6UN1LOy)ssY*iN2`6-MQ|?R zGk{G;MlI(_Z!eFN{B1BFiVL4`9|W-Clj#;peY)@p_cpls+9)nGgl>0eek49Xzw$Wh zkgnHnbMw!c$`XWm0)dVnnKEa#Y?P0K+-3dtJ^nWLyIe*90Bf>83Fo7&<$jHq<=K?8 z29<2QGEVb4)c_H*Cb8n?$(eH!)H;PyL=oF41-x`34mS`Z8eyJv%gM|>7u^}PQ9V~PQ^(p$ndYaGA8c+CK zGOb5S)C=l zK(8P*pYQ$D`&RJ#+)38_D!#lf-eA=;aA^r4HNwY*n?0A@v0B-P@6VBiS-8y2TxCQL z$jnXs2*K-vm31SegudH4iVQ|6RS9Ae#D*vnbE!a=Y$wMQ(oMb#4MfW9G&-F&+d6C?{>hhlv7Zta^mm`_ zJp!DLiF&QWheTCSu`Ci#59{WB$sfRXYUuTES|G`Oji`a$Un{--UERZGWUjt_z8pUw z5VRinEsI{Ib6)(}%jY5y8Fe=Ey!1IA4`oF0Swk}V76=+p%y379o@6d823F$0pr?>`*xZujqODzAZ(he6Sz*pZ(D<=jy>>XVn(@TrFaA4|csVS9{5>-bI=Nai zeb|F$+TIhkUi5B0WJw+?qpt2p^rWqgH^}quYN5Il8`#*p$rFx+^Pv@kUZJV`WDwEzolk{{`h|kuu|}$X!k$srnesyo%mT@h~}J6+f(-QXI#?&$}~2 zaD05O9Q3vsfJ@#w{;j`y#I&EQiz?!$$=ELU!t5 ziNlsg!(%98l*puk)asO~n}AkwZ;26~`=7z*g|OObQ9QE!eo-9QF!{6CyJ!E`RsGvn z30e=++|~#|%Rn&K|FO$#^|aSB2$XNTb!|Vp0w`5MxVL)eZTLkM5>57VTa}_+ZiU{w zmx46Unm$r4r^Zduxhz*UCZUa^X|wqF=0K%g3jZk`Ib!-2ZJ6eD&ii2;+7zOxF(q$$ zUR+KLk5{`S@);>qZ<(=^WFR=wt?#E>VAUD{A z^X8TgGTL(^@>CT$KtCdmlkK~`8i(!Iyi4g*jd(p!g=Mg*yV@Q;NsaNO!Fuy#zHi8> z)3z{b`My|C%MFrkggeL};Ys9j8tC?5>JzP~J41mgMAU6qd463n4EDZC`;3&J4oSC6C5bSqV=E&w5|EJXONtVL$a>ksa<44cBp&N$d$sTTSdpLw}J~N9h z;^UV(@RUORN+hJQD9iW758OvDAz#9-Dg9ZYtjzHBO-^-G4YU&Y>MJPGhfSTHF+$xT%EVEr;DgXmVSOF_ueQV#!O}ZejOUWXzxuPiv)Y4~8h(KfFsamO z-%E{NWRc%|-7S={oPHs{>H`;cE39^mrvo-v7b&dz@Oa6LyL7gkD%T`0sQGGqA>adA zyd!Ca!pW~3b{4eS=TH4(Co&V}$~!tn04$tu#G|WO24nRU`L#K^GFgbV7+W>kD2p9y zm$aFF5E-v)x7bncKr(}uTpD{gxZg{8&0XJTSJeu;s}UKzc<$~atUdb+I25kx z-;G0MEV;9v+1y+gX53nw9~tRIfUQ2z67$lg3Y~`a+$GBG&x;rO;Faw+E?alo%MUD9 z5g&fiHENizZo1X1aa@vNm~P_rJnpgWK%HGs5WXSTx0lTL2~UU8uTYHNv$#~hWjYCg za@)7z)lQ$lsAXx(c-eabFOJvFLeiV!mOO#6-Lj8j9{jAbP7XCaeeNG)|0% zg{S2S1ll|CyvmaV%cQI+`x>5#1u_=X3SD>X+p#dalWC=7NlGZs3yLLx_Z~I9>wl|Z z{a5w|04#4P3IWgPR2}IIc-Ht>Mv;dgar!Rxp3pt^RDC=8_L==~BiUD8as|#yeu1h_ zvhF_K=BCko@KvBn_YKNPAx3!GhE3_9v9mXHcRggiv?D6>-Y%Fjhz-U}waJovF@Jk= znY`3b8W7t(+hpyL$YSsJP>dk$vG}4ppyJa~PUd^0=eiUK2sQyJdmx~q8jcht^7xp~prVgKbv z3~P*;kl2H(g*$J0J|#19oeLi3eE6XCV0b)J^^T=blUb{(|CSnCgzgDfigbF}Vt2m= zsQBd3?-7<@x4U(rJGYJJcl&QJeY(-jVWGp+bm2Yy#UVu$@^om?WDA#*)rdi7Kqx4U z3m>3ZRlvEhqAG$zLdl>XASFrZfr=)?3UEwnS20J1dY%Mv!?+^?BqY&In_K#eLw6&_ zc=vtpv>WV3@Dx0MSE@zuUCkwRVteT0pTztP-+zZ6tDBFG)sec@&N}B^KG$7#n@3di zfx@+ApFTYSnR&_0*NT^BA)M{aSoRqA&l*c(aHWi7035>jjt;q8rXw1`LsTu575wJ& zz)hXrHf(g^F83bp=(%xyi7D?@dOcP!^n~rw85nn8m5O@v_SO$Z`ep7zx1ldQ5k<5t z^V~5a2kAsSGLCq5az21=x+M7c$?yuP|sLk;HCqy{H?Jn>>ZQQjXmCvvAIS=+J>x9DF6=)qG$WP7Z z5PIHuvDOu9RY6S1LC$i?;z*6zk9beczpWVD`QB6oq5QzjN(^AmIc6zFRn#ZQlAa-# zvH0w;#zk9rSXt^du-9!l)V-R5ARr(5RAx-6X$6V={3GE+>}R8h*i#vc12;d?jg{LHvrqH6XN%Z6TZjSXq9aOC=vP}G=#cRk z$>0-DUnU+f7uBHc9CgWS-y@9?VoFczqL*L5`9=au=;Bw*5`b4bhmko&Y3xL4-9$5T z9ct;QSR*EObTa!~$l|(=2dqrC8fSIDdgJJKRo~zY&bn9)S#qE4PF2hMAz{N~F-_hV zGik(w0OAS)ry!%O3B2Uh1GgtBKTAQU5SDf;^P!Z$;`g~b^Rdm}%U&Fu*Aug33x)1i z*R62aC(KqnZ(Q4wqCK-+0EUL?BhJgX z`a_`mgQ2U<`|tmaJdQ*dy9TDtPTgsC z5`P&e{=#6O z`Dt}CDIf-{ly?2KXR8Ug6gv?N)6wO`4H9OXsdxW0PM~G-E!r~8o1Et*(mA`?_gQEo zFjEXy9c>o)@XTFaUnW7|_qa-xE2m}b9C%2;TBc#X-wvh@JMW;NekLr9A@>0X)&m2} z8J&PVfg>@O~aHPIf7v5&nnqn2gDiqmfw;NWm5v>+5cLzzUk1Ux0W0=k7v zfL$25VN~qy`Qge9eU+2Qt|+m{`TV~3lrm9v{$_9h+hzbzv(oyG2qsgCI2Tu^(E_vs zV*D%Z>g&HA91ht=D=$?^&_Bn)Cwu{g%5g7PrG(Qb*-1whC;Gg)tc{4dNoPkh;kjyi zh}fHcZWz%?;{P|Z*q09~topm0d}?oUqzK!uHMFVLVfB-_Azt;Hg>=%#Pf0f3Y)>-g z8_K{~1s%yXp=_?mcxIH}>GJKf_d*C^$PZ9t(g)O$9?HwsCGp)+%R`Jyj|K2{+NVD( zs1HAFe5Wnrt^ z<#vOj%WjkX8YbLPX)J>K+|m{*Rem>1$McnD6mzt9!JO3L2ts(Qc?~}w3!S%?xsDiu zRv#x|a4K9X)&Y3*WTx*XO7` zDL~H+HGnH+5+X)%=4Y_VdSV|TCjVma1I=86Q5NCgrE@ZoXw$_0j)P#bR&_fh~th9V9k zIH|*V6gZCD()0T2M*J?O#}L0#Ti1Cebc%GI7l-eAd0LhJZzc~7$`3OLISl`q{S46^ zZ8v1|2QG#{*q2bU4q+2kt4SJz5o-wJ8a_S-38!bGxf`s1*^gi>c9f!9WD^wb*stXG zoV|i(m28^pg!!sVFe``7J~)*cx%CRJco}#{b>Mq=o3H5AJFTw?ekxM0)1G8+VBAg` zAsvET9>0j%yc%Xd1O-i@ujfyw97o3d;tF#D{oE^RlplULmex6~5%2|!PvpYZv@WoZ zT5dYP32s(g5In8BjbZx31GJQ|V268lg}*$zBxZPm7!X9}mH`ip%eXuuXM5%%G&@+KOBQlLb>Arc4-5PCZ#mqnR9-QEg%hikGV9sjvZRG z7~va+wNPOmlOuIML4F;3E_Lxh@NDNNF1%?-U|0gv4^etx2rzX&SZF(gK_waQ2z=2UpN1MbKK-!H!i$QUemo4Dk4twVD*=iw8{+IAz8kQt zj|HcGme@Zc@W*j74{(P#T(g zZFRJtyy-I46&}+((nYYsMNGq6!G~cQZqjcr=QYW0(43zzupA099jGvNZQ^5!xhiS) zNWJGb3J9TbAOcZjCe9zjpBwS-*!7DIpRT9L4}AM9*t1)^_9ux{BKqm z2c3nZv&YIW&vZUni*ubM%2qwkLvg;dG6x!tv9{}n#}T+)?X}cr8a{c!_v^ix6hRaU zI2xtD!ot0c))zft+`kI0`wmC^s^TuWzvY!p7|aBsx-?_X={qyp%g*f$TV&nY4Uzo134xoS+~DfQUF#}t zBSlKD(Ltq^zubkdA+Xcl&L#pmSpu~(n-yty*Xy}xBmIe?u~RK(#YJDyS6}t*8uGay zWk%F)q;{^kAS=@ljU|BnQ)xFRW2|^?&5Q=054Ua@iSoh=r5g-{IN9z{72 zC9YU({sE~kP4guHkb0O79zFD0HkzInW>Dx**( zby{ZE_lqv3H~@u)Tq6ZD$Dx5;;hu%)%NKKhLk*;kj@WR=XnU5; zQPQ|Hfe>>J1TQOy+pq3^YK@!7mLPQ+B5QuLgLIqP_Q7=#MO&Ud{$bc0h76(L8uE)c zS59MmvSC>4^`Z!)l_;-vz*||NKZ%%-EQcs?gcPvhM~E)NbIc!m3Pps)Ei_=vRAF|) zEgCIWHl2(_ZJRYyn*D5Vf=|1~wbiC}1&@Oa=oJ<3Dq$D1q2E_*I2S(!@L5f8>!#!Z z+)!C8J^x#eO>vR!*XoW(G|%{JoJQ67Ol|a=Vm215gmD;)WE2Q7EY5q(6h;sx-u?;X z_h=C{CWgGR>a`?|*ssK0*jcGM)W`gZ+UIV9Z7gbj==;Q8CY<8}8tD z^;!JrJ5ZT=b#kgR$~l0nIT%x-W1IT8|Dh;1T;us$bGUu(xs0_f86_a7A^Ct$_H{z; z2>K4RE@_eT<_|GDshB7qC8Wjreg$kYJn7H5AU26f;rR_fPqwm)fq^Otlxb`^XAMt0ku{PbC^b)*{x7W~I8uEx7xfUG+SPXagVi#%5Z;cN;rnfhEM zXG%g9^wr|J^!i|0d0-c+PGW1ro$$1eesj(o-HYISIa15D&JI-ET|=bH=_!XE3-h?a z5&8Y<4{*$De`mZKj(G(Dm>1XuZ8ez`y`-gli*xN|SR+t4rQDgVAL_srO)_Tt?J8ZO z?1FwM#_RuUdn8Meap{}=iiE5Pn2!+STPI^+TwI*9laH92c8iU=Hn;5tR{i%VLY{OV z&kpN5gd4`Ck!nRfs&rfD&z}x>@gGZVALu{*Y_+cBlOw3zgfm7I%F`LoLh5C`7ic9uLK+cp?jt!>5-4DTx3R}$Pr_;CQ{%wS)^gY z$*ft?&D3xVjiFJ{v|AZqwADoX!8{scLEYjj!RbX(4Fty6(pwYzDB0tPnEkTFzDttz z#8r%_CQL->VW^XdOp)t+3_((vgcv*PvXqcr?5MNQ7#gdOW(K_`4C-YqI0FH!+)Wla zvVRN-+DKFjct;WB@2?ZXfRw|JSSTPg#O~+!53u;V}E7Fli;N3Ks~v8b5He)X+2 zFn}}EfZ9oa)_RxfIp=5|l&k$jTcwB@s?AQc&udR>??)pvVFq zG+bvpv=Q99+!boDw=2^_FBpwkR%gRxzKPr$x z-3VquSVB!?3@I{eZ!moY46XxMjMl=14Ut%PgO&#_ ze>rinV4Kbvu3;h*nV5w1AlT4}34_sIdR^iz1ugO04GZI%#(OGc^D(Sq$4pvXoo-tO zarNL-R-@QOw|~omaZ0d;k+}QKsPxBAn@NLWrk4y`bHWmePE(*How0miKlZ1n&aSUg zG_Hf*cNOCqFcdF;c>gZzg7NlJ_Ae706@!}~A-=3+R+?0Wg9sT$pQzoqg#>d}-moaW zS_wL!(;uK9(~fVZE~UvHQJcf=KBH^5+t6p|#KPA)MY~FjCK%XYbYzuS{rvq!hLw~C zQ0;K~W_?vTM@aCyY;)Pn?E5McsN!31(gnKt&pOVv>n=z8qSiSH@-8%FGhLaUZ{pJlOySYhrqE|PNSAw3`rM&u+}Y7R-uX|c>J@3>352RpN&tP+ zW&m8?915)s+FX;72hjDfF;p*HN{p%6S4oXY0~|hkjrF~n%~b%^?{Kc}v&1v&Iq#rv z(xXX%DA))5Ujw_4l)6l5^Ob-a^e95=K}!m?$j6Vbq%Et-VBbjy#>1s|84(EvNF?!l z2jjKw79-S8DM9!T&q*TKuZ9f<)`UC_1i$lBThjXDq|Fwm9vVIB|8*;BZ8RXBZ1flE5^+G_F{d&Q36fH$89i$2Y|v%Rsdvrhp9}^>+1aT?G)bF z42D(3Hvy)u&NZBzKJ6^3->jO@hbZRPoORRtY;UqMhJr9`iGMDFW0&7XELH_0fM*89 znb;FBDc$y7pe5pdr|9&&95)BWj*M;SOr{bFzI3ob?TL+|t*#du>A{N)ZMYzrYb23* zu`X*ZnP+PLCv5n!{uKrY%7&%y%^0V*wq`y=OxTEnY(oCoMzMUF_T#4Lhzjjg*u<8t)GBx58aZ%+dr zzZ?uCK{bQ@k~Rxh9vvJ{RIn+Iv@6x6uBnX}z$GVG<9AKn|DDRB7?W?zeb`cS#varh zf5l6~d`eM_9Yd7OS)yy1&oQNJI;d#H56l10#FLbfyIAvWWheX7 zdde{RupwtPWZ7NsFEdw`gqyjDOH!mw{=7%d?I)d-vv;ds<2%a_v?_Ut0kQ%8j8)?5OtywXC+WHzk411DCsvctH;(mLU59~yQy4cN;p zjRn`!cBQRT#@o$)X5%?SQ#_$($D2ms9(rlNj&k};POrdIo!JS@x^-p^2EZNW7S0-H zBr5&^j4Hgh_o}DgL&yHwi_9|F=8t)M1X(!3&6^qyE`Jcczzbj{V}<08T>~|+p!s^| zV36t1^n|P2TE0qdP(jZ(1@JTFxxwJi;$>9{(>0xnRc^EL@9`iYT=pmK%EPydRpJ5U z9Aiwd69mNBv0Bxm7m#evs3AKxVWIJ;J#t&R3S%2~xfrbgu4TwGrcLeCD?|n>x72;7 z4ks7R=85QcY<>w|j?@j066U6)%@25LYV6UOqgk>)xTfJgIvpXmnJypFg$2BO3KL8t zfU5GpxgDA`gRmlI3y_SG9;X_8Rz}3s=_j@1 zAMR~1g%Ej>{C){@9E+eHvqlC**AeV?AqgZZVrC_bcr=*uvh0z=IEU&Dg>GD**L8AB zJicmoV%GABus-^Idcx`(F4%Y#0EEFDmUFIMWC-|j9-xCPL2A#XepgcJ(-5Mh#fRFi zgWvY)m;#T+*6ZT$6A2x@tnp;vs@%FyB;wu<3g~P9mUR7Ml@pFAjk*O>N`o^)Rdo^G z#0Na$fM^&b)1PM3xM$W559wt4KU5_Us;+k<<*4#}YCyWY>}XR!U5z5rZ-j1cA$pwR z0Cc<9;p*9#oLT|vuJ|g+g6(&uqXtvozO9GEJdm~Mh(WtOU8~k~@bd+j9ES%TY-mG? zHIar%Q#t`)hb0=KCaMV$OU5rt%RFRi(Y+~@UnVJP`Azy0*G?Rs4e!+d%V(|v9$)B6 zX{#twLM5Y_#U9`j4oqnqFqmDe&_vFX`UOY< ztNaE+f$07vsKj!jGXOel0&|74G*Bp#ODNf&}SOxpsRi; z-T~U2^0LQn!64?G-u+lq7GXv?!cWD7*o|};ju1K$&O$Xm{Hl0WRYHb8v6e_)Rn}Du zp$E*RACvQn#ZY6qeP9w0Z&C1LZ-uwTA%S5R0Pz%Lf0TJt#1Syp!hQK7fI&oEyNl~LB^=-$BsdTvO@tL0n5aY2N>CHk{O+Ur zO+%bsvmLWcqav;RF9A%af|^3@wjDQOX)cp*_tA;HxCD?>J@#r3I&c*`z%_+SeNkQ< zMe5(!Vlh@5!rbujH+SZ})|DEUg`%r(#qmOwj_(fGJMUhEb`CLXhu*E!{3&7jT;H^> zL#0@)F7M?q2p)a%(Z}AH)li7PjrQYqJIZFX^RqMgU~NJ5inrEXF*E6* zBG!m@r{vqDuSbJ2`eCd)FP|ID_t~D~9e$F6%~4?tfN!0TXZl=RH4!tm4HM>rgTr({ z9$6u~az+g%AB~(P?dL75B&ourmbj!;^vP%f`RR7%M#)i(1lLzt8^j)I$z&Xm8UCwQ zTpR>E@y(9pZ)Zn#XN*hC#{RaC*^t_+C}WUjSwX?;@yW>`kNw6eypg>pKqZCobP{)D z{3Q^f<8PY?NeioFM%+jQ*X@au$AmkNP3gHn`@w^(=R!n32uMH8gthh^53(y#WzCGh zY;s1p=5Chi5{jE)cy9=A!gWowW6`Cz498&Kw1K{TH-nMYpsRxYc&7X0SJvg!;uo-L z58Lfe!d0Ns%*L)ux-%IUpMRL09eRW=4(y3xwGJGw9m@A0u zr)#?-h$xx@25^OobdLeq((Y4XbU8=0d}I*+N54}J9l0mGd&HX`DvCCj0`^vUG`Y^4 zrh3c_8ceuS-1gjOn^(G)ovUmZvW#L<1kS${dK_;pef84eJ8mLgZpyJ8gHaKb)sp63 zDop(m1#g?ixj#d|mU`}6^kgma$?BxP-?=O$y8=}31D%P*;FobgcwUX-@WJP2gPXG! zg*k?*Cg;dRMD=Y&WNpB$U2Eiw+!j*C&!ixIiSuaKV!S{{=|7J1Bg(UTgabtXPSPmd zF!p;lTP5VIGa5_@(U?VUlp`<#n!)EL(I}=`wW8l)STDT%$Rlr#dBVy+@Y#EN_vzgP zbNuST`1e6Y-f%^|4eI+_-(~FG*btCIpFD#C0gpbgt20FM4j>tkf@IAd_44!QG7@0NcyGvGSffUEy!5FqM`Agv2+Cuy$s_mr zPebn~_vNlDy|0nEMMODNRn`l5s-?Q503F*Xh>pmu)$d_$QvQS$8Z0hOL#oB+&1^La zmh+);d0yv&d-aOXw*!j08jks*D2ybXg(-MthgZKyzdUy{5U|!Of@ac?HG5k44|#$UPV7%>b`}O$q?7 zFH}WmFmv)y)X|6WIcI>(HEEC`UJ2m8S`59HFL+|q6;Y{$lt0#QZBd+$urH_ew{#Y+ z&FjCf#3H%SlSYilZK7{+WF>0|d-TTA~sW4_rEw_vxR5 z;D#;mVRZO=H^sfp6(m|dzrHv&VIt@8q}-XQ@3I*BGOj;T+oM7qtWj<&9VW} zVf?q1g)bj)g8_w|5p7bhg@(>56f&wc6!V>h>V@7xCDE*sl0gg5g3E%J0U(D}mGH+Q zy02pnlij<5*<^BeML=td1b3g{z@zUEWq*(`+8}kP{{(u#yZ)X~Lka@Xi@*AuKf?dv zD3-;$&9!h$E;DJOLL(*eUHSiW2V~))a+Fy~q%OaQL5tPTN=r4@!%qD6K~lc<+T-=M zgQa$Bk(SM|ykO}V>LeR7Hsg>u=y6j8oJ!^Ed9St~EEb@m!OR0Dxv`dwJI${)-*b3#y>37`~C$$MdEVi zY{=>=wxj?;bi1eGgS$304(XADt^s2zv^LT4P_wJFfqLNtG)v()@tYCQ*59qr zY%=pB6@M*<ehlxWkING5js{2+--MpT%a5yKqeVhvd5~KsWbKZv|Rv;9=H@xkQ1%8Bc-%q58J7 zRV2z)fJffK^Pp2wW0yzDhBhOa;#EzkL11xlaaPvCdlS9)jy&ySTJ^vhKY+WMH#AYf zYR*r$62)vHru)C$rqZ59NwA)9L8d14L=E9zoyqzAskO0d;Nn- z(3ivW-&NQ!LDU!)=nKdj{K|vU#c$dGo@!iihclCh&3jk1Q6ZU5%IP6cTfTJ_|;xk9H$IoX2Q8yl#R{OxHFcCSwSC4giZgbfRZk<_JLYiEMNnuYm?DLT~R?(&JBdH zsAPhsgYNaVBXQaLpT+7I@dl&zD_|)7eZLDMk4nNRt*9!%tPF-i`;GB$Wd{4FEKU~k z=Ub+CoDB8bx=901r2)t4%k<*jK_BRfT{y51teA#k>C#L{ttOA*bGFGG_yH{; z`;5ZO7#;xr{g3MY8o+E>0@1Y9322Ev=e-0DZam}XNM}y?dpKg;`@MP->U@0QcgEqa zm$RMc$!gDg6$pkY>gxEQ2!`Chk1TVKz>p&m4l0PkAIuQ@zITW^SoQ`^L53s7fv=E(dtO=E zJYzp|f`3-^)9Vu z?}TV=0f8a~75tu}idA82Wk>(_AaxVm=RtC#Bmdi^A@Bcf(*I7<|4!21-r;}l?vEG$ z-<@>d>+Ap5JLwue(Xcfx=ge(^93THocZaWT#AE2h>X+Tf=W)@Vaaw1F*~6v|1rp}f zcUEdV?@QiMrDU4=hNDEQgtabbT}AmIFo4MNo(MAz7Tilp7C&BDBEx8)cMFi zD{v$q0X*4EUI4 zxNzat`VLD*76_;R#RFgemminH|381BGD*ZRdRcpqWgCVP1{e%xa_*yOE+tsv?>r%&8Z)9agdFk$+HLVnWdU_h=6~*=U4gu>B$>f_?oTc?% z$W)Sm6#7N~DX=ro5P+WP>;4v64ETsx)31D8N*c(UugSeRe%4*vytAD6YHPD&kILuM z*q|F(+ga;++fPVX?!zs3agE03^Q{LU3EsG@+?`kIg;q1`MJh|aII0aMZr`4;V2D%8 zRA=a%iOKswd*)?~X~kJxxw>3Cw!ZwE`C4%ItdEtKn?xt4B+4@i{~wchfGC;VGB!B^ zx23G`|En$Sd}%oobmhApX}&c*HlrvM|&OA8JaIzwGQKKZzSU;U1_LIb2AyI@bVm6Y>S{#e zB|#&bKpfAH-E~y*Bcd%hT=4m_n#Z9sG5ueePCxda4tZ@=p7)29Mmq{BOQuEy{`0_? zG#?|qxyc<*+Aj|1kSPvMP~o0H=ti{@2RP$i*k60(bW|Ew>&I{pe^z2HC)@h)H66ih zd!!nP1zzVZy#wdJ3rE24=Hg^eLEpe1()*0y_42aLBU7Dr$Ffm!RdV|^^c$_p?cT{d zPuF7!?Pd>}qyaQpS*0&M+GdtfzR_~$hH8!l$kIwq>3r|pJE(tOLu72m>6KIr){jk@ zKRXJ(ehl3W_~&t>L>`dd*hy_{1RpP{0FG-Dx5W--=Y3iHi3+eCMKS%#1|k(OXi3xY z?zH;ujSTM)zJyq_J(W5)Pe=AtArGd(6mG)y8zdQlvmBx!1^)WIlx=?U z)qGu-%vy-tIaSW^HYa00;Jz&BCY9%}sS}-AMQ1RGa~SoksibKHPC52kHL1 zyAecF?o^GWuHs9{exA!G|j>$yJk{3?1Ji>VwVL}C=(OJ=;GfnRA zJdGsS*?FH?3;J~7Cub`3Ny*GM7T;V2GBXxrA>#3%?R`#{>3dD1+Faj<(!5-Y2h4vz zHuFeKtWU{N`K=qGDb z6yImQ*izg1kgCyiB_4g9p3Al%^|xG6N%4$GBvVe!<9ZLH1|P~xzWVpPuS!o`UX3)& z3PwBrj6mOi^N-7zeEBg_Lb6&l%*2+$?&Qyn)~MQt_hvB>s~d;tEXA?u(%Tb|3wILR zdV|*1OyeBMqSn3uNrAtZcrHOXz;!c(i<-KW4x7tB0Ed7?<_B9&pp7^U#Qn^2g({ zha1JCxI;vi^5(lv6FItcrTKC&nSMs5T(RSUP!IbHSY;vv8c~2VwEHD&Pt^3)2tNx+ zW6oaLNUBF{dqdyTFOEMSqTBwvrg*RJ*Hk^m#D&7n_|KXq!Fq#47i(}_SuzgSJQkvC zz3;TX6-DFbJ(hT{oGH2av&xu#R!&D(Z|s2^+P4DD&g23%rPt51n)A36qEbVEZk-{= zD|yQu!%`>Ro|6OtM=8lG+@)p|Egr7{zr42_Yt|&dLl{=rr^M99UOJgs-iXy+pfRtt zrL1E@1L0GKt~KBcSl=!PawTUU+uz6RnfjtP?~>*HAux36&;Q4c|z54P2=!pL>-42*-18XNKEjl!{Zr z$XNITPhGtVbX{RWY_FUA?Xue#UlrkdD##SOT^jB{Um^YLgl|}9xw)hI9}_re)BDUf zEX{|TQ$*YUcHT?cO0}xzh{eJWfWdmT&wsF9J@7RWS!@k}xx_houXrqk zYhV;{Wh0zuFHA>ej<#^B+2mCr zz?st-iQKXqcx>gmbGg@HZsftosaUgH;YY{woB8UhbP-4HRGh{VE^A?|lj}dmb$Ym& zfAM9ia6ohf+fn!O1SYsRM_a-`^kMe$LE!f`XCdL|Q@R&c*P&^b?K1w&2Nh~PNB;?y zAi{vZcFf4iN@G%tf8?u536B})KJ7xh{Dft3fm3Pgb#8MFBW@;Cdq3u;lEcocy{+y9 zwH}RUXYMWA9X8VOf5O|zM`PqcBtWEH zR`~9dU$}Wf$$^gt#F)vJcckdDuTTbyxs(%UKm`o8_c+p>8`l2_cjkdPRMz%Pgumux z)G>P*gl6`M2B7ARj~7{k8}=*qCp0;Fy=gI;v^By4k1V=p@M2oePr}l|g)U=+NSRZc zEAr;o`u-Da1t&k?b-(L+Oxoz=Cq`D9iBzTyfy#z*z;V-y~#v#x-*k=Sx8gdKmf;O9G>t0LTG(+unM+v3ISLNjIV z0GkeW2M9j*_wxGEw|bhw^wTj@V{^%ku(wCM2~5wlP=}2R8e>aS%Tmo3w<(uLLWnmM zV)zObUgIVqhW4?SBS zZEhzfU49qopksRb(~ixGg@@ma{QkL~vCIU3Yp#ng7x=T%QBCo{H|jpFxOFXDBn2*L zDJ;8BHMzV4ma7g7w8eadzKD5ix$jGsB^sPAc55<>zYUniSw|XBh3YK0l@&^U;5=f} zBj!jYMp`fK+&RjWn|2sCZdv>BeoZuVT`6w5#%{|>o8OCf!i{V)-Tk&$WoVYhR`NYC zby73-!izbs&-D)Q({F#cS2mC(S4PlQtiB>fDJvY#CmM(l1G7>=gz6f0`@Bcj6^v>E zy03ec`+N1%p66l2p=@q%M~%@azk{LI$#tH|XZ?C40j!dC3r zyMj!<9O(NM4T(}&b;oY?;;-?CDd-wBsq1mBx|0fF1Y-q-I^NXSCH z3BN1wUxB7v25|d5)mB6t?PaYGi8Pm5)Nkha}HlAXV$)171fr6p#GH^ z0r~jiIkvE5p#+Hc@|?r-lmPLu6#R;~c#w=A7W4oaBAs63-V2sRv)>(zINz&Z2*b3| z4fPnq1+L;=H`Lzfu`aeiD7Otk+l8^<)Vo<%rJ!Qmp|QSW_a=z)a89(GR!&NnWS8>M zOl8WxydvEMe^T^-rR8dD${xK_&oG&kKi&^Jrk;L*Zu2*fT;w-DB%o@jY1V%+(+&Id zb9Ve=2vldDm7)B4dGq*i6JJmMc%;>Ua6spAtp)?}f8HSkM_4i|E6Qx_L-`9kvp7+ zZ>*U@<>&Y87Y}F>kTs43OPDNKIy%)SIO_*1a0g184to9%d+!<5)Yi6*iXw=JC@3gM zu^=J>N(sFP3Q`26w}A8-iu8mcvIP|>QjBy20coLx7OF}U=`8_5La!kpB?JfwC$RT+ z@Avt>cbvaxjPv}HtmRy5-t(^4yzaUDDdVkD5(OOHqDl1nGTHZzS>GG0WY+qZ?VR(E zJto7!MShktDM8CyDtVM_KwRzxQYR@@PHUK;pFW@zY~*GcDLD}$m^k(^J>`u=P7-=K zMMG{OyJV<%$jh^^(F-!`wOcxA;c066W}zbop}!XJ&?mj~Hn6M=aXu&w;~8u#r@hV8 z`a;9IMq%r|Hs|u1kx`UA^q6PXXxMRK7ZTEd?Q`ysk6PI!azl{kde`pGxL`(CL1myCzj{&R(Qp{#*@vu=)1P z{7I$_$$PRnG!(biIZmT#4D&>!Q&PV$7RlG_e{0xpHQFLE?MLV9s&BZx9$3uE{gd)P zCRg6lolc;^}C zdKL5s`tEzDUgC)S)=0zje1z*^(qaHhH+_JyG2pi)JDMC{bOh5?xz5$zS?7`v1y0Pi|XIb`AZ$)YZ2Aw z6sX8WG!qTcO4fT!5EZr8AxOC!eY4Z17O;2?`v2>$? zfWR&4dHx<>EfUukSG}_kC*Zpy6^6bSemk%$+|-Pr+3U^-3snm}&K=cpSA^adQ&;~i z6Ak}6@<%h%*Em177Knyi(=Nq~idbrkewMV;V!y_owyP|fmi8e1>CXV|upJ@6H!HMT zuimd;TH<;{$dKi}XPjY}Bh$z8SRC@~J0VInOL~jso7BOtrqfcWA>I@?)k^)mOyOs` zH}fikt|RAuE1|~4gnWWschM7HT$H}P z)pAYg60?9hE6Wa#XPb73nAaq9*`b^iavp3xn^4*kSQ;N3<$86Nr5i21L4~4^Tn<(9 zGIyz=xLc9Vm4=qLFYw4wcDuhi{LAADgRwZuVBXq37$Dr~8oV|}zm81wo52n>e9^!C ziCG2dUQ~$O*xGpMEDTKyaf=LH#nxmFa5NVbuYh~-2=g%={^SNNXpb>8ACwI?Xc8#A z>HScBp?2A0cFfDu+V+lu&l2nUMl1Ww$zdn%%U1?O#{^P5znC#{(*I);vD9$taN{F2 zRQ0b7STPZ!icIcLk+}pFU8Y)T9BujM zw%HZ$dat<#|Al3e06|V#?4ki*I=k(oiKL`=wLfjo6z;dap?s1Olgb_70DfBT%MT3K z>vO5pD9WdJH3(hH`$nf0p*DRnC&{w*mva5*Z#3=Us#z*_VyVvd|H_JAe0@rFY6{D0 zv3M$g!3{l<%}mwB#zWanD$qpEm1{WO$&cQwkLwm=^m2OgjTshlY0ZMn+juY~n@_7| zae~6+Lu^G%vGy0%c4`Ca0^90?QBUu*<+J8Zf2ZaLFVD=wXB@1(J*4Oo!&eQ+)cW2F zbi3yh3+Mj`wT>sL#%3t>cI5;Wq5N}yBgXl9AQgF6n*2m-K7lYTZfjZ57fqQ!Yy{UA zbM#8`yYY*GvkhagFX`Cy)tUG|cyX`vs&0LKVlG28ufGM~W$kUaFms(h>jtaLM0&{L z-p;vy^!3q2wX(!3b(&2a?zicE}e4Q%yg!+On70bI81Ux77Bxd!ZHts>is3TFzcdp+cA| z8ix)h0M+)5{@ z=q8IX#)*Hh>;HUkso+tV0CLjv{L7O5jQ8us2et@gEoee(*D+Ba^EGoK^Vy zr+?n%@BdTEesmMWNhFZE>+`?d_aBS-e~xmr#3DzFLmaT!q3+rJ1!n!{fT6&nntN?b zYUlqx%HgkHEsi4kT28|+;QuzcW5?@Q4&xQJ((@P92mf!6Yd8vOSWU=O-TyW@s&Vig z0y_0BGm|I&_s2o59^C}p{_giLl!CJEywI4cXzPkOO($+JW{3eeroUhGPev^s_0?)H$Bg%GD$z;G z9ahrPHt=AGo!`dB^ENX|PC>D!DLcH&tk7&gfHc6+UM!bN`uH6%O+PBZAh$Mb zpjqUWoF5tfSD#~=A7jkCo%Gh>&wtOPPyBeqW2pU~?}=Jidq5bg&H`g%+|`1DMQwim zGa;qSR}2-*?;f`A@(j#)^?Ocv^(%N3*1xf?bp7pgYResG8}Jzsbuyk^V@NHJ5gpA1s43@0~?FW z`m!9S*HDTRU#2*?l;7-L;_3c)_9{&@>Z;r=R~Fjj2S?AMc7go!ETzY1?GaT1gVI@j zShihrl@WBHy-Xmjltska$I^%A963VGg~v8_Uq_$qW)w|rPcfxV0pTPRdQm0Q?v(L@ z{&I?F8rRF$j!@xB1yJ>7m-pf+kNUHit5#u$1xJL|(X!o3g;#y0F4H-h1(`clMg^Qt zkNTH-Ll~vI(YhNpO?2zu!SZf*^anT8WH$RPyB->;2^VKyJgeH~ z`S=Pdh{onMIyd#}9AWW7d!sevLhJTjt->*EQYBcwvO7(N8^{G(s@WkMDp*8>%A=2k zW^3?DO0m4swCtOSTj`^o_7sU?macc?vXz*X=b6>mBcLwouQyS%!*?hiOm zP$P@qhk|>8GoDY6k6ZUL#87mFwTZqhj4G{CqiH(1@W+E>Eu)I)kPshf!-{>KsKjYR zsPa3fB>7rL$5&3;S4z4Jrawq&mmmjQ2e!$#P4Bu`c5f!Ww|?gCgPfzqu;rkcYgr509TI3+=xASVO1FQInP;?2Um7y zW@s7SL_NTHAeuers?PRo#v&a>Xena?(ZInfSh@Iq$(hME2&~-c{>tg;{TQ^SgnYqL zSxsZvj9VHq_~1u=&u1OK{qJJIgY9HlRu^?m+0XZ2Gy4M`_Xu&Wb2Ef@_uw+8DlQz# z=FH8%HF9!<<%e^oknHHy_n_?2-0bf8@_`dL(Ui1nj`36De4iX>C{7H&ynKI?sNu0@OY&h2#yEC1%x-;u|ug7_mtRYnK-8R~N92nUtnido~D;}*U`bsFQ@yqOw z7dvSr*=%5!$@KfSuBQ{c! zxF2wfQ&-N=MDXgy2x3Z`iig$>Tm*2sPP$MVFJ)A`Pa@L~sGX82G}^mzP4<0YfUi8I zJEBwlL>=|q&QHn%dC1)2yN}f)8|53gc^nl>x&%6e!h=pL$bFe9)@<^I3HG=IU&__e zfspDxr*RGK`~kbn<~{Q%F$QJztQVj(`Gv)?O1Qhmib|+)0EJ4^Mhk@&(T&l=6L+F; zot_3AHaZQjwxxz~y6kuX%nHn3xN=G#7Jrg0FpLVjwX_B28cL>iuPd6Hy`QR2*Kq!r z!YXybEWEZeen;8q0fsG&SK*FoUAzj`*Rl_xIrm~f1#7=Xb$G$1GEJdMI9A81(smCw zGN6r{o9DPmOdV$}4aKb5aHb)NFx2^zkkG3s!laqv{pD*p{SI6J#5$1sOJGTt*ob!5 zK~SG8HnR;(>N$JG%v#~Jfs|PlC)}QL5 zZE2H>HR1Tf(xPYVxYwyGX2(}`9nSB`^F=ph*%mUXG5SUBF=|Mj(e#%|bZH*V@LAmT z*HP1W?^+^X6r=YR<>bi!WIsqp7-6M1_T7-;TtHeO`iZ52zMJZUH`eMEVo-4xS4;0> zFS&Ynxs-lW6d=)a4u&{Axr8d;^pnd0|1>4K;UFFe zi(H&&wTqQ@uo-RL%IoT3J>RM6fvelI-L8e9VKg7mC()%`>!BsS`UR=@ASgm|%N?B;D8p+`$PSVeLbcs#59>M6b? z%h>bIdI-H4P1i>e2xzJg>WM&xTO9gbRrJ=4%h_rwItaHiLVvD>SqP#iNg|Rb7%wmg zTAizwpIV_M_y#!%ZD(@B?FU2D;U=3VI7b8ZPP;V-7dAIpp%k#;9N(zf=@K|UTU9;S z)PZBf>bTGNVr+w|f`XWZQ8N8!%7Z$+vx&HB1JQ1rI{3 zgoy(fA_gjWtZ6#h;aJjqM^4_kZo96@e%bPg<9%A=QwZJP1+No(r) zY3rT@KR8~K6H%Eq>hp(UC->#N704lPG@I(YYQ?WdOzl^ewDpqrdsWNyUsF$#?OdmR znaIJFTSjd}@d7iC^5moQHNxMvD>(%%bnKiXCj`mhdo zDTFLu5_&0baw>N##s{W8UQT>~H<}tk;mXY7IPStL; z1BE8SO9rb)kA<_v1W%x+ydzJp$8~wTx9jGlKWOL-rG9gb?FSYqTVS`)D<|C_q`Gto zmA|bZU(-kr#qEUxih|0Xg<(n6Kz|2zVM#W@H`#;TiuJ`e(~FiWqF27R;I>-dbdM%g zszxbu?l(^UYVC<-xrH?p zVv&M?ylUoX=u#CulLM{|zc(;X^p&@lUwY1L0VNdp#D>u#%g__ORVWz|Mi1kKvmhrE z&RReHl9Aeu-a0#gJE}Oz4eW8KMQ8Twx&r-Tzw6mcHI;BjSsVylhBqBp`*Eo71zF*E z*217u2>yv7IXuUNL8eIF4E{k(QF2E&CZxgY6;Y$p26&JF(JUG zBB84LT>~>9gGa00VQ&=F{_QkRXIJKg^4G(?is?gVBNli_bv7}3b~e;T?d$Pjy1a*E z#Q=x`LqEJAgjlegMcx@*6*nHAQ7W5qiXT+oN~ibkAJ4)bAC4C}cBcm<19_$t`5^ME zANQj!dx=yb+9pp2A>f4?!wPy4szYq#?wYG(ozpiP^O+ab8&l1n$Ph%`7y#+wlpi=N zGC&w+Qy(ld0H2L~UX6QAoJUlZR|f&v8MqTk6&kNc#xcTA-~_u)1Cbu@tCNh3oIPx_ zY*_4BlnnO}WmJyhQOGvQlvK?I2RMeTcpHgUvR+#9Cwt@ik>|F?dM?WchKh=Wv!Ona zl4^V}vszv;xg?ACj3wd5Fz8(cW8G#uCD(A-0PARlHU$g*mT%}(zDf*elc?W0=HBRA zE|#=;sVD#BFJ@ZP@FNf8)hW*BOM84O-Kq(8KS%M2K*`&R5AGue?=>4bJc6&tA%l?) z00a3+^8tNPtzskB<7PZEcP0nUuXZ>L4#{-#$yITFG+}aZVZ#+CIs;9st}mImjCK9+ ze)RPd6YdGl44PG{T7Gteglt8kk*a`ZPC8f=`qA9gB2FMuS;R(z17+iATnBEz0w#+5 zN}7vqm{m2pBJ8K_%wiy!?&|O@Ag*lFtPReJI%^^|wZZ}hR2G+n>><+qgEJQ&etzXI z%>)`-99?|QhD>Q>cs7Gg9wp6z;M@eCu&~=_6YdCpr3#0{JK+Qx+@6^u2Rvl(7o$7@ z<=yy38S{6z&HV9|jq8V$<~59&rlg?75bvTekK@c}do*=l-I3{dH!|n)!$S^tkHk$-`R1aa@Tp#D2+W{ zDlK-hy7XWGk*+V&lM5HQRmE>F);zj2AF|hz^~a{_{`&=p#K&g>Z@`geI@~L>6M;1e zER7lR{rQaNQhK;V>(ac92debrMyhC*g+ps$k8Z*q!t3r zZ&~sizwYP=Z{46nqo6{lwhBEiZGRm9((&f$VS55kNSO#eqk8znxbZ33`>TwcmUjXz z7##RD?CwzTO(081wg80NvFIalQrPeA0KKgRa`F zhftLbG}412m683Ww6g4!Z!;U0SLMKoHA&_RjAVHMXac>K9eO4|s}#y)7jY@|dlelVfx~*U z=j;}V$Or%2rkZAD(lV$lm*7Pl-|P-1>XJ^d*A7yoJwe4T&AUNKlVYbGQWF9wdVBlR z$jKMjvj^DZApsBf3E2W-;A1cuRyByWBd;K$0^JKkT(n^)@v$xUS4(`T-#ix_>&3Ts z)()Z0U{@_k&jc{WJH3kiJQ)M`dSF+Jc7uvHLYnG6zS~sXR<_(52g{PQUv?={(cAYo z`&@y^-ivO}Ctvu71vX^+pbF$Ux3}gSq6TE{Zuhhe7 zSd8{1si~=VUdtQ;o>1ruvQ^S3Td>HZFLf(zz9+<}Y19g(MD!~r?N_hntzhjejGct* zFYs9Lg^0S--~jGW^inu02EVQje6Vx8*~!ZCT)i{`X4{b~OqZ}1`@*lhwXNh8yt#x(V!~H1Fmhs@-5Y`dp~3!BRxsoY`fy14rh%cjZa`>!x2Fp*yMD{b-l?5#aFa*ufWpwWms75CLNzRRQ=1G1Z-K-b(`~1I^aVCYx@-R)rTom$C|v z`f{~U_NIU27?jV%t#@N374z;3cN!lg64?j6yu6ZI*yUkNt3lPJAu3e;wxWFJryE#D z5wt`LSx-@@ReH2ss68X(%)<4FKSmBW=O?$84k&4ege~$3c1T=6o%|H!AhJ%bES>bh zyFF!qhnu%Ixf$FiKXQ7&0`LI{Yi`^8Sdr?}qm#ZCo$S4EB*9`xQFW06$Z?N^v_320 ze<(Z1+kgOMu{OQz;xi_>+w#T+lQX$Lqk@2+m{U3z_7dNIuv%sTanpJl$n@3X(8Ql( ztJ^y+8C)8n=Q;{&$}c+p8W9A1E3T9OklLwi(d z`vP5YGrci>Ib$POX3if>pkz&Xvg=#4$F{GOQfBab_0HrJ`se2T8$~t^tEg@r83Hd6 zg)VET@@elwdfZ?TH-p;u9kML`ta_tgblXRor{o-Tu65tMPpMW=yr7s%^C0zy56g^I{9}E; z^A(r(G~Ijn2DkNCCbgxdd{$`8Q$2i>qTCAwvtHGSvJ!QAbbRJR+}uA(7o=wC6F3X$_D?b||P$jcdq)+6l48qaz7b%gi?2sBVQOPKPp z&y83n+;t?+IB*sM;zR^SH?pn0Ro~d_z+MpxMa?^>clq#8sFT&2+j}-_<7ARyL5q~m za@IGAVtJ`Bj!>n^|x$7Lc+lbH_B~9z_qRRJ5%8b^ok$ z2#=gF+ZH+o8V|4$?NuCNia5~wj(v9!%d({CJ;3h6)p6^fJ4J9Q{10O5oOG}T`wjMr zUS@X_2Id1QOr`ev&xHTH^BvdQwA}Y6IhQ2}j1#HvRWWBc!;v;77-;-k22WP1L`Llr6*mE zTgFRaKyK9b5I^@;#j;_s{*F~O^X(g|`zNSr>z`qk@84loY*64Ne`?6naClymK=yDr ze2^t(*%W!HQYInGIO;&1oz4Q85t5^rRJO|DcpViVWuJHVjy6!W`Aw`MOxTqThGy!D zxZJ}wqRrzE*8e{Ga!7za?}@qCD4JT`H5FF0Pmq!Cs`6krG>!IOKgjR4V$}9K(Iq9t zut`N{(CJe zUwZ0k&*U+7Wq?(hV_63-<(R$G2~_(n1_<9P&^SpfWiVtTr!nEix-ZudMd7DMPc&3d zbal@;jBLmEy8fVXX_B$lGQj;F@SPNSnz-*FuS^AfGb{f@E2<44*6z`gG@L!iM5LVX z@Ei>^=(_BnPE6LO5TEgZBq0HgB~2&wBs{~UKdNdh^L;+~z3nrUR2||k#TRp+I2`Sp zUy4^Z4VeJDG%+}!SgWeMpH1fZ*kHe%)H%z#AGX%b7v#jXxWV0|6Lx*<#oA5Hc&*-BALD3cYAD^mmncFDbc(6IQ zc&ga-F%&zDW_3+g$>#cAWNp=Y<<}7XH>}L__|Uqb;!Qq?2(z`RS0X5sM1 zzR-3LygllfuSR>k$nma@Iexk7`}hqmN+a=GU|nS}v6<(lRGoe;7us&`fU(nnpVI2@w{ z0f~EkV9K|9MZBX5$Gc7Rq`uRnSI335Jo@@7^|j1!CI|W(932a=3$ed^Ug%+tGRyOa zu$rUwZ&;0shEbKXO#9`2!&+DFw+D@19{h5-{brIzzfJ$dD6oqIFFK~3#%L^Q2S z27h@Ui&fYOXHw6*V?OX*8N2kRX>Tc1A7;(pJUYF-7UCz&lra6Y0|@E4S=?>pzLpa2 zvd-KjnV~uz4E&A}u(Nz*{955o=rlMO#)KdH9`Y#cdTrh0Hsd+|)Po*Wo(=FgscH8r zXAf{`x+VLwqAS7#ufW;EUD~3~nu1v!aF`-zDs9VD>tOj)4ot4KwiOTdY0IG#gx3!GZVZSgvbJ$==(9DoA|P0PQHZ z{grJ~Wpar26>qm-uecu{%?#D%Ff%fV9~0m9a(S(msPKbj00|LJ`jt7AO1GjXa);PQ z%8^`%=O(9QaK1f%c}(_l4=iZEbGgI*`dCiixS31cy_Iwi?#}Pv-rP!v&u%!`jbU7i z-k#2?o{qcPLVW>SMa$k*@5^x zRs6JAjmy7A&M2`zEv8AB>>f|CswFzDt+@q)cv zT^ljVN@vjR{7;d`p+h4YamKN=J@8k#^gN!TBVo8v-|-F)-=)+13aPHtjyNlRg*)Lw zylL7yxpcB%8b6?zDm<`6PmM z2;1Wi`|WNAmU(?Vqcm$|mHIXau= zi>jbQrS|LHWXaF`2NQywPJIhaFm7lz3YN!Kta@OS{0R#oMVmQ2^H; zrDucOo-~Z=b7WsUv(OgYonzXkD0~7#!uP#Cagy5d_<6i~6+kB;rxgw_5ldaEn%dWy zNQ&W0TIH5)Lvb~B^zqw_%b!#%o|!GP^R4TdiaAeRjoPEtc>d37Xii2ue?y?L#9?w5 zu=mbU@i9_H#xJl4@^@LX4&*jUd~_DFT~K{XCrV#nNS?qi7h8Z^fkG$ z`w{eW-?ccaWmu5*#}z7&KSD;aYzrVh*^OvzKgST2_)Kb~2@Drev5@blK2;>qVSPb<0o9t#7+ z>0ksij37InIj!&qy=7z-oA#@H-)WPDR_>*m)p(YaZ}D&*k%*p%Rq$!Q71J>l zI$>@!5_YGKK0S;Xne!nZd2JQAz+xv%vwrX;B9XN=Y>%?rs4QBDF@rsBO6lL2Kyw() z_ULB&jb$X#X1_N;FlhVQFUCcFzZM$^(q)a3v~u zzd28D7})TgmKrc`9tO;JxBm&4ETtaaC@Ne5Z7=o2y-yXwa;ndni~0fUx}D7UqvTIl zu=cTG0QW;Qfke4!!XI6Bj0av+<|hS^Pu`WtQLYvL_!{?X^ikyxI88%5HAr*XrLatN8icZb8@athK-N>KpsCm0w}3gGhHVvd_menCl#^3-XR+U1L4 zTP5!f-e%fJD(l%wI*Duk0BL?{*ufq%hTrOv2A&CMz&bR!Zw}*rJ&bz@Lm>ujSDOmH z(YxPzZ*xC`&p+@=S0B3;;FtW}PnvH2;1OT>B}y_ChKpMd`bB=15tGEKG||`nQj#Az z40yh7S>XMX-P`LWM}RDsCpJt8_ZL!>R@IWO^fg&;KuvP8P@Ue?td=%hBC|5XM=keW zF@4YsnyxhL93U0=yg9k`=1g_YbqDd9w9Y_;QM%le_@(p-PD7m{9`wL_q&w16b_u{7 zzThcSq$&Ssqas)~Yoc}~Nd}i=+KtTRe$s2&n+qqTOZ?LA?DWojyhdKE!BmNv!F=)_ z8{&*y08IxEm)zG5wAak4SH(?G5gKIVp(vsnaz`)T*2enV+MGBY(oj zC)Cz`bg@<+-N!BTgcdFm`rfti#?^+ed;X+*KkhUUa2UnLj{GM0Uw-rJcWmx_a?9t3 zMGtopSQy#j*aj$F`NtRy^5k46$K-rjQr&M;=K#T7|tIc+0QpV^C)f@{%Jou%gDT#_5CFZ z_v_XW+q>(gun>oJ++4sjR?7$e0m1$$^3tIj@;MUb<x?6FT=e9}qQ$9OEYfUCA;z^j|R#T1ly*LB{z2c|N z>Yi0UuOHrWeD`6}%3o;=GdJ|zTG*PyeyXvgqGeZ&T;wi=T{Jaq>ys*0TP>By+b8pv zC(aWp<3D$o#zikLqPR>h_!W~SPQc|Ht|GO_#)Vo%S2vbht+bT+#QWH?`TklfE;0Pv zUnB&K8Pywr?@euGy2*4+o8F1@qSjncen=TOMCyN($Kf@TiV7zR6O9SDf zjrkQjs#^jNtTC?L`=xmB7>RVNk$ZnE^im9Ynqz#`X%{N-y0ZPUr|kOnQR1$CxYd>Y z_WymWi?vj$Qp(TS>S?Z5CAWILSt^1p{Z-*ZQ|#N|h>n+7b~?6I?OCwCYovRm$AK_s zYV&s=ZRKJ1vldmYxb0rD8Dn5dr*^#m^Q@MMb(t%AqZHW`v_*Qzf}M2tbU;-aC8`w` zWzN~1#*&UkIaq<>4SDkLc;xop^rx)I*AYUJGjlEi{{izHuj7-sA#FmaWgCZ+jvKk0kEDM=jwAegyHylql#7-)`3IH-a5* z9o)bzqN1o{Ur_B;J!fApr<6sX-GRgjGJ9<;U}@bWyQf_t9A<>DkOrVdb#?Rg7bL#` z5%RwD-)HfsT>RGbse9HeC0cusJwv zew121@}R+gd(b0J7=-uPCicXNROsphxXbxq6%1Pt%}$ONrrEP${-letPpL}ve-pD*W z4dsZuaY$EQ34P%b)Fi2=9@gQXsRAW=K)W|tHeu*MQ=jwj*?w-eP9y3D_w`4AvU5%W zH~`d!jTc|_Zp0?W)yYxYhA+PG2vCG>%9iX6XK=1*?QL1*7^P3=mfoV`KpltkgJatN z#{Lf}ZzCr{yF9jktXJzdjm{|xJK1h8i1S`&h?9RYTX@cq=5QPMQjbvI>yeX3lTvzC zH?`k}snjpo%M#DmbdtizDZi=a&+OE>>QQl&lvMnNbq@(|+e*BG`DMEO&lC#m7B^mK z$N85&WVr!3)?swD@AzL1IrDrO*o2f@|CgSq9DoIg{fiDd< z4v%7qJrY>y{}9;W9A11?_!Hq;o5@^f{hP_h+xPNlJwN}C^*mzXQQK~g=0%cn+^7A` zW31pkLWKnWPICVyOHx-Q?9Yr*;Vg&ZzxjEG=Bx65;rEev4?WUUeN0#zwaxi2ZlMz6 z(d)3*`? z!;Fg6j|Gh-whT-p?5FWlG zL)q`2`Bq469995z&-}EY;*nI79;99ZCgYj@wnpk3t!XFB@C3RGH&8k=INtT9-ohNb z4>_X$Diy3L+!PD=>#j5^wljy zp(qq)1s(SdX4>@gp{iyR{6wb}I&0@uvG`0@NzpF^=Or03R>yD`*As&r{fSRfty$1fJ&EieZnf*Ilh5X1| zG=GMrkTj3nnwuiMLoXQ^QWB(@_uLJu9ks~#C& z*RUp0mi{(38z}BgcdsZuFThb8>i#mmR1a+5ObT`t`PYM^G!l?6;XhH^(vTF(H zBFCz90`j-xuFRe778+rEo>8}N>cvROniqyo6Uk!}xB-{mB;H>|3`4`g7+7JjYvqzp zHAJ5Hs#sCboeW$o-U1txkb{~i--Mvyp)0VO;*-NN4cOll%x^If{JGg`dLxI@dD(R*pD4OdJQLXzeArE~gi zFvl&t8ZK^(Z`D5bQsgKpOhJ5E_VH0+R{xc3;V#G9ibeynN2<9r1UivzmCRNag6_w{)lql9aI!N5WAEn5ZYj`V#GJL%TqPP$RlZr- zHt)aa=zNghP$=(S328DK%znS@z7MR4!UfGzyA~l?elsd->(uO@`Pxe=B zmCh2~TQtN>US??93%u%UF|r4F0@n_qKUo>jG~tg=5jGKdQCzjQT@rC1ye~N!IoWpd zxo{HFjby>D_wTZHMf+G#t!#?J`kUVFVQ}-MD#}(AFe9c|2SsS?9R);k)($O9wUHD= zAms``I7O?3bFU)RqMA?0Ij9!4=>y!v>&dX=QeC;m%6t^6*a+8UMc4`BGWvOFZ*5^` zx1i;8b&7TbVF8JdPKzO!$mrl2x_(rZ;l1D#o0nhPPxVn0!~c*xd+#WO{>x}-Xvskr z9tT)+xn1vanrkIQeFPS^4w(Ws!CeLbo2vTDV$VM;5WrSG^2i(tImH|Txp2BwyxO{F zZu7lJ!ZlR?CuXny4)VCDwf>&S;gifJ%b-yM!_8nvan*WTrFu_?Shq1!B1IhtKWE ze4oGe?zGLUb$t0>C}7gM;X5r2^K5f>dPz?|2oECykPG%{&^%<34z8@mFsi(_TSjE> zN(z*Yu#0%yJ1C8~1zh%m_q0o=MR>KsycM(;92(pPagIz4W5zTbK+Fa~^f9-r#hsOH6QDovaVP zv>>`Hh#(j7f}xM%M6Y&aux+RRabm|_QWV~v2(S+85{OASJF4+oifbb*;dQ#^P{~q* zT_nlbtZV6B)BBj5ZrwYs7i>J?=QJy~jh||@II#*Y*V6{(>%TtRowoR+bN_aN45zi_ z_eNk=lS&C1q|q6;S Kx5^8&r+~N6%(G)J*&Z2Fqim+|Ac9WE(2*}%(U4S**N4( zFt#kYF*Dk6E>E#;Bc(s3r2QF;g^VC9f;Q{f$XuNLA|Z7~S&e#66Yh9k(^(B3XyKC; zRq4sS(l{O}-t5rWx1#zsUdIG7kske=+QiSasM?uKQ5xT7cLsrHt<^yxR@vvgIGqm& z(Z>2{%R>VAcOA{c})J~BUAZJ``WdOfJ2V@8mVu+`TB!nLEyXe znt5|W@Wn>q$8Y9}X*ZDwM3&cPK~JaVK$_<8YdgMpb|1HN=*=|ZF2eA2E7)Sc-v6-K{Ts+C>Ao9+mEz-%70V&bP?h^zuuV?CEX&0j>S~R8htl;l6kKRhIZ-$6s;G?%E|yUlq}`0DEUo1KlljZ-dHmE~nEVR>I`y2% zqor6?Wm{8$^ZXA|CsXynUS;Nw?T&4T{(+XQ%WlY1+-PX-zjv2<4$JkYi=1zxv6Nfh zM8263I=Egs9y}YTfV&-prGPU&u=& zg(oCg=54)wf=E>ZVs4Q+n=Ip{jesWamN%4#KFnv;O0f>_c6<@)QT1_B0NC2Q|Ev-G z`H|CuMMg8lQK8_%m-tWG_hmuT)PpZFlA;x87{L>+Cce)DhVhMTUSX0eWEycJuy3Vci|K1#RP~g6#Xt44EjEoWOV9m1;4mj&X)O z(lQZy52@gL?bZ`XX27bzd8G^mzF6ivHwz_j7CvGFnM5A2eBraQ-fl0!$_sytbmbFc zwWeN*J4W<$;LU0)vQf3(nV&R$;!*kY;dF!mluVBoQFQ<@y09RGNgn7W`Z&)>?oF#z z-%U&5YFFN%RUL}22!)ZnZ$QWtDk;tE- zP#>F`!dUQ)sM{wWGdIL=hZ_bFYVZ@1<^ZnArzDYWrg8TJWbUrT(m;CXt>v|A7;))$ zc+0Vh^1FrGYgLNZK?R7C!6Ay^X%>Vz6TZpEG=Q4BsIvTrE93`ThjkMgJh%*SNy;m%43%Q#Ca01`A8943*>0V zFr&s-6W^IWt*aibpJX&n4EF>}^Fb4h)Af{pGT7&3|4i9^;>niOk=8$mV#l0tBV7ld zDI`mdHKIfE^F-dJ)n3gO-?aL;EEv(Kld9M&<&;uy`3*zvRM}28JV(d zu#o=HVA#;js~3?~;S?jjs3gPhcUBX+e5C;hWs|j&$}7Lje5qZhY8OKB@l~lQ5Z@Xb zP@a*K!)>m=>*VceGFr+~6Sfgosc+9TacUsU&PA9w0;VH~ch z`qDn2s#WyUKYq!ump%K|;0VL}RF+iYU`nm#>g=OWg=P&RLxj>V!r{x|BQVp70O+^a zk&eQiG#+8r*nw;L8W>j4D(itUk*v2dNIeDCUBVBdQ0xoWMW)td`erbA&oUAA1=5BmtR!|>$$?KY-9OvpYv}n> zgxseGL&bB+W5M#ULh{7W#J9M2^Hnc38g8X!!{lFx$C2N%P;jC-g0(xv z1sGXiobF9$;_$1bF9OuQEdh+6X9$ei5tmQb-HHuNMb12^c7A|UrgD(}WI!kcf?f)N z_h|d_blQflo=WLHD?eU-6Ij%GacMxdQ$wQUOQ1gN93M_MEyhb5R4bV_pKtWOGXLjO z#0}Mm-gacpQhj}nW_3?*Bg6P3A)I-LaYa78Sb{Lfae(kyP0#7<(vUttJGo-Iefcf; z8hLWu+<>E2M)8yWmw64fg#x>iJjxC0&)3Z@A?AI%yUHPI@0K2eXXQ=Mfox5|`lOPI ze1|k}LM=bgqJ!)WoS!YXV9(KE#2|BPh4t$E7^-6`4vJkwU51)5lw!5&p954CGp*D` z+JJltBbEcRq3II&;N_h3f_!p`)471^gDQWRCEk)_IOIgdfkQu-*cg4-vq(JzJ+Y*v zcfYImmaE~LgH`tf=JgyAvaL7Kx8TedO8EE;AK^tuV^HZP0P|`qD(^(vI1>`s)VU06 zEU#d*Z1zxig1xiv$fDG@hOgN@sM$ZT0DJ^O0GgsAKRq@xZ|hM{YISIkU)4YDnTNf| zn3DDs`o&NE1@_7{4+g3H*N`Kq<1ll)l(VrhBB1+L-5OSmsB z9nsHI2W;wV&fC=f@Tt9_Y2Z_cmnDpU@=nw{(CWT^1dEK<+w>-9aM5fn&6M?cJ7woR z&E76=-}i_M$j^#1%i1sJ7#qA5LyfYMRaE-3)4g+OGBP+9=F^J< z)I03?<-C~B0?7U;K8{UhtG{OL~@2re*Ns5Z2Qw6}}`tW`jyn@r{cAhpM*> zh%;K2MS}&G!6iU&f(CbYcXto&ZoxeScM0z99)boK+@0VKgWKF;pS#a}?-zfW?zO6` zs(bb4duSn`uJ&wX-2^sl2G0^#`cw^P8vs{RCaMxrIx_NuBjnC#cu(u@s0OR2Tcm)3K;J zT*U57jne+eiJBRWndb44wP2A{mHCimqhrIf{zYlj0=2Gz>QD`J1-DVTk?($V3Xetc3lv2%%*=OV}7K^-cg$wT+v z*l#u)=hbI|agJ#kOlFF=X%}B6PO*De!Keb33mi_-9i+#9IihKp#g7Ks4|$zA*Y%H* zw@;ZObh0K@#~tn!&q|3H70#m{*q2V5P>hy3;Du#%zg(SqT!f~;i(juHVx{HiWMxG+ zM`fwxwgFD=Ylio)<*_;GSk#x)uX*w?!HQ|w>c`9OQ*s@B7B-M)#qX2p`^3HrFOco_ zN~H14?&We;ZPXxvqbVZ7z0<#<0uD9-O7Zh8qS)+AqQjS7*hO-3Go|a0eMP$@k|cJz zD{}`29=57EX&3hlD}>-ai#1(q*^k{P!kuY}lcVRw$*TE+LXNjnvybgvUHEddN%frW zTy#miTuSS)?$)!S?i`ZpF%J2ZJXxQYJaJXv1V(zfh_Eg6_ec!S_F^o0=b&OWVg}+^GRyYj`6M?OnmhI z$M=T`Pp7MaEkp0<#rMBWihIP*hZluQS5Xrdo-#LEfH6Ie4F5&Hg(#rC=Xhx{zRt=| z?*##j5E`YysUuewzdKQsL+{N?X>1MFKM8A^SWJAPtADb}8)KM~?K&9cH{#m)T21d3 zZqqw`>Gx@<$ro@MHXLAK6xtrc!E9EuL8=QD*jR`KUmrLbk^H56`lAKm~)&EN0g zs^Gib1T0I7^}*8|83KJ%1Dd+WKN839D{|^rHgJduFB`197{Y z+vG`UjM-K~S{dlC_+3vVZJr&#^lVA8T8vUw{!~Nrcf&ahM`c4%GnRC0vlqLK@>Yw! z=bBHO98~@=CCzq0@gQD?i~qc3CQVK4^Y}yw0UMxOW3D6#n~BcBe)8^|w~yk%fy`|~ zXQiPBm%CwZRf?(Nzpy6vyTQIgZIo=@YFCiN#N)BOaq0M#zwwW@fxcO?{Rti0VYel?DmUCCvdWG&QLV@cwiqX-@Ir<|453$v?rVP97T+S?$4v@*+2_riGZDX; zcXJu*|C!7G@u~O(ofoUh=Oyh|(D#XMGaOIOAFoTsE#j23N#}@NX?TZ$bSy5cyz@BI z>lpT5JDFU69|5SOAQ~)h5N#!)UTumi5weG&I;`!wI z3QQ>juE!{(Y+f3N9DGD7&s}nr{myI6+M%K4IGl31pNnALd{JV-WRy`!%Q#au!Czm2 zo$^t)T&53CYEoQ9#h-=QjYR=>~`pv`U7-QaW11r?(a<2;4E!Cr? z&(mO(gQ`+>nV|S>OqRcN7qnYFQp;@pA+3dbdcMTR=d6N0BmUqcGD|}W!>_p^Htuh_ z@1iUm)W`#@DsG1`8$Qsa58=8>Ca7UZwvBi5(7H)^Y|v5#CjB;ELPQ3b=tJNhm!k-C z)lsTKmyiIQ%%L-D=0K=DS1nNR+}E$Iw956})=4`yf$6BalGewy9fVj^NtIZOg}lC8 zkVn^Rj9BN%!=_W-kNuk0pk$xjSN$Wiw&K3nheXMfpKYv!Cahzy|2Cz8~i1h$a^;7m6LgM=SEh+nOab zgaWEGHInZ84#x>LSStdm>u=2E`yg+sJZo_0j{h;~`vetV=zo`Uv?+ZM2_%*9NnGdg zv>C8qD_NM6P=SHkU^>{5EM_~e5Ik!-PhX6w8Rf@(r5R4aZ~u9o4w<=&2lfOI*u^<$ zlNzwr-a$UZ_je^8#c;XgyUiYlnDP`a>v5Hj#s`6lufH93nnsyb92TO{XXT~te_ z)r7fO%QR=mZL?by7xHx!iTFw>4duI)Pfmo$vUO71(=QbGFPwEdhiIFL9fe=6b@Q=Y zm)tB=vP(3W`ER~ee_lyRl1jUaV+w{ob=^&a{%{nx)yAn zZHgeI0oy7KOIqjd*559UFY>dS15;vTWGtJ(+p|b8*5eo};M|`V4|`{4fdMY$`zd#M zo&Jmlg^Y*pWv}SF>u+Punr2tojODNNDC{l83Ie$CtG#2uuLAz>k1m%<{&zdVIfN^0 zN+sl)dje~Z9Ufb$b57N{26cVaJJhr8Zm8xhdN2$MOEt0<+%sA+DP&zr`1T1WmN=|6 zZjcKP3bpTFjswoD=I31-DCGiDQ+x~!^kbWK=I0^w!1lgI;&B09g>G`#%ah3ve`FXv z4o7uD&-1LI&BTWtvXo)B$)TpJRvgsXnBryIfvHBQUtI0Tz$>XJ<*eU)F?Rm zSKmbU%l(<=|4jKYNMzjDtTabfHAQQL-tF8qOKMbM4oi&yY<}w<?a;oo`{OAOhPL`&0$5TuB-%$TZBI_oHZSUGfk z8+ybW^ZQ47=xJ7qm+k0xe1k=*4CfZOBA~M#x5c^Kr0|kyZ5s2#auk)t!2Ij*!BQIa z7ExZfrzB(A+s5d%KAhzZBwtxjeBXn9dbTQ0$yUP2VVVV13% zz@nNA_XI=uCj}P=`-j)ap!T|7oZ)aB`SF{EP>9xP*0U5$tTAs~uH)!{S0WRy9rMJo zwn6omMU<=rgBk8z6DQ4nvl&rK0q@J2kh(?u-zrP%?j?7$T2rNnX zc*@1OJ&tzfIHg{VYyF8u$4BQL#da0;YBjVZWci_h%8`Q94X4NYY8)y^?`7E4=(h{Wu)(a2 zH6Efh*;pNbc66Y5MMI&_C7J!Ryhfz^ARr+2>Tr4+?5d%*h>lQg*BvgB=YIg4a! z8eFq8L{@s{0-L_{=U?PR>eT zk)Kz;9(g#Fv|!j^f0b(mxeW9n^9s={?@D{cknBA@@Ec$dxe9ZE`FJw}f4Nd>a4EY+ z7{@!KIKROKC%Gc9*p1-*pp|MAIU|aeQM4N$W-ji19>P)PGBMBL${?>vPt^CT(cjf5 zQ~A;i!}dscHcqy7OD^S|^}u9lobltpx}&1s?fIn86X$>Km9Hn$E&ci?5{gZrjRh?N z=RbuKU=&41=5p44jtTyi_d^NpSN3iMFm1?W^A&hf(3y?|Sp@DhI4LRQ2($P+wp2p90H&?%)Q{N`b!0vY? zL|t6I!@WVlAp~UE?6-nC!jXY61%Z$OzJcl5Tkx*{&)4~br!<&<%o! zw1i`A!o?De&%_b9Ga~&uhg_xzpOid-uI52GY}l9Ifq-Qmp#oP*E95=`|KO_>jo1lB zGFhuqA%1c7a3>XaGcU8NfDoDr$%x;$dw#eFovYkR4m%8wXgMz|l6DsIL>dgwS-WeZ zVMvmPPuN4%`J5jUoP9@af7&%9w~vxDbYXGc_@cndYi2Lmge$vAY*VpPuyRB^%;H5u zec@`t{8|+MtOaEvpcR7`?Hq7@$6+wZSJp6!&e5RF8l8S`z^XqrYAca;@hN{*$HC!t zXzUDV(M$Af$jE*2cH_Z2HF>U?zvy4Cu_$t^RLs>pMF7XkYq4@3N!FcJg5~SZYNH3$ z6tRPEp~TDEJFwvf2>K>(6|QaCE)~BZt}0=Wg}$8SuxbN(j`f?9fcxTwX9(>1 z>pE?W%wPRWjcRryZl)e~@M^4uq%BLcZvs&Db1_Wg9PQ0wAwuGs*U=S4RgBraqsR3v zH86`v$Jx{6AR7pv(edh`i9w)R8i{3D_WFjOYb@QK8KzW8(dJOtDy@mA5DFNO$K|hnA$Db0_k5j&fQnfaADaf z90K=lXlzPoe`iMMeQh=Tts+gfvsKXe^+pnPeD;ig$CYk;=qvzaEY!If=UEcFgCbSln?OPq{tNu8CT<$O$|0A2Z zFm9TwkIrHbYOiwPBZM^PGsNM_u1SM~zKvU_bkJCccO@z~%4c`*M~A(pNhjW&&lJzL z7vkCnw@AKf;daq)W8!w$kn;Arh|cvbcBGNUo$giWfU;uC@}mlPQP!i9`5AH(9S#3; z6CX>H=-wV(p-!mKherBuT%qJhJD|C$g(n!uJOg6qjZp)inL>qPH-X;Vw5Z+OQu0hK zh{y~R#!Y`@iB@so?~Xq4bfC~3j6`xv&GlC1xWd;%-L3MBIQrz?f*drVY@uqB1^+DH z=`}azu5SjZ@D8#+0$p=?abbx0x3$fZN4IzAt^`eos=xkS?MkX<=QC%YolshwW6}A^ zhr_opN~^Tm|D8FwZo5UcQ=>v`zND24tPZ{DcxLF z?SD{H^nY@-S&sB}rG{&14j1_P=G*1<*3V1xq@uM|Nnh7;M=11i0{`Gj^zfV)eswUq z%7`Lx2dRa14D2+>s8zEZ*T-EyW?Rtjwh?)y_P6rLDtR{6dG3+W<@uzl8U)&;o^nQK z3L8Vqg6=zymr=%({L?!fr+8OGx|4^BRQ`}k8ALnt5x8NhfVc@-gQtEHt-P9IfqAOU zl8)|5Q4A9#H&V320&NgY!cpNQhem>9-PT|Fzj^QjefYUW0{4gmWh)tH@`xJm-34Ai`-%=#@jFJTn1eFKeUzuu~yFqtLi`pg7tPQbkdftHc%{3c7a zM@A?Z>(*)o>-;2{-`zZbVsoK~y%Iy-2Dc@wQJHE+j#(G%5m(x8Q^v9 zyzJsa7*^Q=CuTA;F1Qu{F$`bin-Bg- zGJ$=3^YB{38S_F1_51?$C10ISfiunAAKDZm%#F* zhrC`8-=$mLpW4l&;6k1j_lrM)Fcdqz)-t=ZbhY;aNmcn@dQ224X_ln&bCF`=R|>%F#;P+%rg6GaBm4CbGZ7nVZO% zx`_In$V0M!!(Wu9MbTUb8@1dX86Af{Xnkz`H z>js!Gj}S0@5-0w7s%?%N9`f@qazd4It{rmSeOQ{dB>0?<{9rTT(tx_ECUO(PssR92 zI-8$AGmz!n*vaKBDJXrqVaV&cPT}gy{r#{D&lK=4Y=+g1xW--ojKrr)=rj?{%K%2= z~2d z7O)j5Z=B0SN4gcN6aGNz)3;1R$yy3bIYjTsO5WI|F4h4`KKh4SPIy= z^>*fdy`0`R17q^KhK5*+T0Dng%(u!WwNn-=h(de!~f0aSk6YxYvD`9^ng?ClQCMQ=2LTuX@ zOO5`%_y-Yh^!1U4VM6hbAnW&xb4_meRRHHgT)#Bm`DA?o`DiR9!II=?pC)r_yl`2N ze;=Y%oRVYU>@AJpSLh%}fPy^ew)tBQMGCvJh-lWoWdp8xsEMXi28#D0Wn@AaSqK)m zGw@p^zW~Iw)87m^T})}Jv_6BAM52d}zKd;4#IVh#=ix_m_Y%7@;+f$7(rd9sOmXfL z(81juEpjUQ$?o~H6wxL<1FV3h$S&WeBD6Qy#E3kN1CODn9OMN6i_;WWyl_b@hvs9- zlhlBO%D8sXF4ly=ImjLi6BEYHK1g>#isPI)5#9|%8QU>skp{~NkEB&j5rk=ki^Yfs z%JkWAQ{el}7X=mWP1`lB?gfChC+r4~J0bYQlVkfuB#152veTBJuzvpGq7s-de zUORI1J7X`V_jCMbo?2;oDM8vuzJ~(`s0TUM#`M!8@y)%)OO&S16CBaxAaWbbKg!s6 zQR-wH1rxCMt4e3`8lYfb0@xb^HrDhU_~S$S9k7KEW37 zrBCi@Lj?^u8D1HAgu~hqw6eTr za^R;P#waWBi`BeAtNOYD$$h^6Xz=ey>`*RURLFs4TWJ9oZ9JpH5*Edy&T6Z z(j*lX4JiMR$xfDK*5opPuwu|;n4l^dpUld8aF(9;=}*;%=klj}48fJ43DF?Y2sFh(i^lvy(vImX$hA(mpe;lI-zlFXFGoIsdnN_RIObk4Z>3API5Y* z4{Z#*=?eaKh%DJ3$4RKrNblu16bw+KD`<%RsosUW%<){TPp_Apb0aoOrTcc(x%$@A z(8WLkCK*S&HOoK$WZ6kr&%Y5-wI}mQ)=ln<8FzyzIe@tbNKNo;Z{es{A@%8Rr60lT zxIbijreUOb79UCO4eKr`ck~Tr{j_vS6t3R*x<}>h?FJ<@aL}79XZY*Nbnpi91-VNT zsznKbx}>jihFv1&hBRelEgK^zdsATG2Qk!B7)5Sdzo)mXs=$W*|D*$c1F|Vaq-laT zjiq5r0M8;=?H8G^n8?#8cvE*mzV23Xj=bnE0t=}&Y zUNwh;8@rb>MOxS}Tjr5hFVwAYVo1|49ehf|O7keh@VLoIgHx)ueW>>%f=$tm9m%6S zdUjw9dR@$leshG+%|Y^QcGX+m=UiU;ZPKmvv$r!w#13xlUSPEPuZB&a<|LR8yTvvF zk%NgtQ5*}X7wq(g`l(k73n;02eEUS z?OmY#ttj zT!o5`dW9KVnz0z8mOoU&iyr?Lv%nKl7t2qRgg>_F51a`GKP0ZtV1GrQ-a#a=t{0}4 zYS}U90v$9lBr%edVj<5a&8XL*Hxi?!+j^n1xcbw^!FkX~85?D4D0G|_SxN*&yFn_7 z69S~7z@(6Rt_DEI$;Ca`d-iAGYBhP<=H1<@e)C)@ikC){=h>64SqgbrBlqTt3H#3I z)0{A~K#dXiT(I~%_PaVc&$m}j3e+0-uVi;x$mjDsemB^$*Q1S2#LjX|{u6BEFfqYN>v@xCFR7*fA9o#a?q^?(@Lhvu;g^PlXT2$kgL-Px|#s@LT znK@Yqbsa%GfO&9)K8z=wN3x>$a_jR7;C9|;e`_VrX8wk5g_yUkv&wxmuncIuu4<07 zvWM_Roh+t+3DLF;_U)E8yH4MhOW8k29>}fnamE#`YMGks{p-$%IyEex5(sYTRFZcQ zuH<9ls_XD!R%&#(6j7tK9{pg405K^jSD{5ThQHW97SWi?XW!9nB5^@Jb{VowJi3-g zN}6&#s3{*=>b)dQGxIrjANn-jLQe(TafT{3;Qs4epWtO^<4|cps}|Tj2Y>*HI9jg( z;(@mc2l`~^;Ktvuq!2}vP&v|s7aQ@IFi96@o}Gb}xPXZ&-o!+{e=fJWQd=DeUII*4 z%?7Y=05wtm)lR~?B|qHq7_p@+%fwt{%VetP!6Dp}_IyIE7=%ci(sA%co%m-fJUi20 z3Hp?ec^NRapCIY@q;>#y=Q05Q(}hhHaA+$+ayPMoW)t(DaV-LX;x5RY12E>vBbONO z96x2%FE<;0SN^B^kK|jwH$4W>2qO$MT{t8#ZA%>FF159r!S=8jC>#b_SKxNN%Px-g zXY~zmUkfYozN)&V{+*-}-sLa#lP+J7no7fy&(Je`eVwSSNbMn;U7aY6wI)dJ;y3@o z4>}OL2jZ0`)s~0?r9o^;pOesBO z>u;jGJy$&BFno=s#I@(NJhTpYWU%CgROJFA?@Ur$B~V4E)9zTPT)_jcZL#ZNkiYUf z_AEX$9mcQY2MPaEH3P54IdL+;esh*+s5W8xq?L`RElVevdV?X8Vu*yO(=N&xLr`nz z2D^X{)v9e*m$4GrfJ2~ry^sc`7woVibY19O>r$Qavf%b7uHCf z9pdxP^8u(t+y98Zeb(8DXq8HbIkl+dt<3eMSg+nY63fEM&lzV2ZfX@Xsc5zSu4;Wd zUaXH<$$J&4t+e$l)@v2$K37R_oBRlMsp`+zb#>I@@66L%L~N`=H-N&^dc(F^0ry!~?0TY>|;n1p{#au*l=BJ*|$UTY3* zoDMD4^Sc5@g-L=EabQZ^#CJ8wz*8(&Rg5aA+D&0Yyos`bH~s)+T%wsK(}qr%?gJ%g z7=;l~Y=JB`RRk*oEk;Zb-_emBJN(U;to5?2>z!(6Hp%K`Y24cDEs~t<3W2K) zPp(_^g-=k^(8}n>UYSZQT&5M>Bu8=~Z9;=_0y5zNiFfmBDOUq9n`rVZzOtCK1i%z{?ZghN7Gr@`^Gm}%k_VPG$^ zZiXCiPJAd`6y-Di`NgmvWUH-YOB?4qsARqUE8&(UTL_DyzdUa$Wemgkl*IyOj^j~r zj2CXCL9B^&**z1gpo8GaPf-L&39@5{9wV{#ICG&j0=>mt^pic33UPhMoc;8}LOivMi<&l4)^Y3;e22aRM}&d~J7@lQt0qsJ6`XhR z9t|xc8q@WB7=1pMGF^5Uuz2vh>ZhOxLz!N;b`CC*f0!&fQvIw2DT|}kIrU6Un`w#^H$RB? zEmE!VIO3%QqDvAo|CwJ6O&?V}#ViITg>hcRu~Vp?>Yi&3r$S0*9~Pu!e%$)qZtDs7 zrf&o5(uo0dEwCfOZm2d)o^V8uZkSDtX^bLaF~Juh=ejz}?7@YEM)pm06TS|@-*F++!5Bt<}tw(1sNv9W!agVkdGpci~ z7OOieXJQxtEI{btf4+W72`MsoP7rl(WH+g&qJ}@Y^y&3{%! z?-W>151i<8f8{TH8nZTy4!ZVhYTX-tu(Xld3AxBg0y&4guhjhOS_%J1L@knGB4#FN zlaadc)!OOPFMiX*eomR7*wNXbj9aZ85C6Ag%Ks^&lM+m-nY*{3ZN0+u-``FF zE-g;5yjV`sKJJJPT{bMf5z4g(6uW*)ehcd8i94s6gP2{83fvKyPQdl}&9`PFh(Jn6 z@ag`A@bLYW^!I9@=a+0$$FH0Se!hKS(@TDoq<;8Od(Dwr#PR=1dxAW_)F1+tL;x6yUEA1eh`2sh^6tvN%MT8+!ZEH7R+ojJ1`7vG< zK9fY?$nC8W=BLs4 z6CK5zgCA>}77#e<(7E5CdHt=-@%ZT-Hj6P}F6DL9TW2C}yg3%2E3LiX5GZUDKTp^|v`6jgYI?@zhYD(C6<*T8alzE>fxkZNs$4FU~ih?$@H-9%X zaZr}T_q`a32`v%ZjKMp4+RGnX{!@J ztD`j@VRBkNwFOSzC>-@9Ygxp_K5^-g*e|jFj3Eof*Tc2|g<|2+q&fTWBHcA1VaGJ^ zRQsjv24aq@tTgifbY6V!5QJ_@yJ}lY#}pB7rG4%0zAd;R#T5y~8g8hPJyH?^MSj-I zHw={g^{VwQ{cj=CpJ%%Zy;ngvaF^s??%{uYZl~+@driaxInS_&Mzz1qhw;M%H+Y?? zQ)VSxOa75*1a2MzKQNWCm>LgEpgyXf^sxAZ5EDaHWTzE}CJd~${RDzUJG@sXf64c~ zx>8M-$#TLE>Y90pWMag*6i}g{0%5sX>3+H&LQzJ=g>x_&Dzuy)_MOD6Vgk1EQ*A2B zYj9C|?l}u2GwWA*BUT=8>QmdF`9Y!(U9SYu^&M0sP4+&R5Q|b0zlCnwP8*Ru+6v^! zi#yek7#ukR6PYl&H8&$WP$ErXTR;7ob3W#Wa22CW-l-@>-Q5shWWUP_z&`bod(YF~8g9!N`r?(Vvv{|MT zr;BPW7e(3~KSH&YjPd{n- zJS!_G8W~sGU?ILLf)A{A(6FS9nZ3d{-{>siKv8lVb%xvMK?1SP{ zH}Pw5;x0JGpC13m7x9JP|D?;yM1qagZ0+=?YIR73rTQYjFa8S}-o{{2W?R|xK~)h$ zZKGNE;U6We5e;`V9W)X6uT9UM`2U9Y7j?Gl-F9oh9!PiF&b-LbkrrA#@dZc<{?Y}* zm*upN!YhZXSE}z-Yzv5UAX{UlGhwWe(3}V$TXVtq)qTa8Eap=fCncQX6jgh6D$E>y zXiZP0p8*mm`=L7!(ymewYWvR@Je>++%_mN!4szeodDG3)``9!%!hZ*wNOw2#os-x{ z__ zQ-r#xOf9<0eaY~zYuXWmKj^>K|90PH&!ulcJhD?s`W@tgdzkbh#IY+3dEsGTVyz9V z7Ckp9@1kb_5M|KTbF;%eC*Hof!`4U$e|a4=Gz;*9Eo8i{fX2y5Qw9hIp{GfjX?+KQ zSAtrXj6@*?!s&lRAUGuyWb*$(hQ@~+q2 zg#>=(XK>w%%|P2wmr8eAG?fHf#npDtdAYy!nZDUO8)vxn!w$FTMy*=$64Wjkp zoN}GLrrA!0_GHjE2$6@?UEo~KeKBP$IssJVkpuj^ z*5qMO%VM(!a=Dq&taK9?vHG)gEQ|9LNkK-T!nNqN#^m+b%c|aK`i3xis?lXx_F2o_ z8=6waY5?Or;?~)qj19$`JiZ|5QSi*3%G^+!lTry>dwtdzSRrSPc!?Xr$=bvfxEyI9C-N~nYv)hwAvP=YFtK=deN?D?;1H*j5_GE+-+d!kZe z`f7MUworX}Boyv%qnVtPR^FOsd|z-`wv=9t>91-u6IM=obfV!#36-T3^A+Vc$J-MQ zAoDxVMThX*bSJb)T)5GLKpAY{is~O}*>1x?Sj8TiRKmcgzo@s4_D0cZ^Q8>{h{$NF6Et1eKd4t z$`tDfTm?6uaOvY>3Qdbm;>EjZaDdr1^Rcw``RbnC==}n7oom{#hZg5J%%CqSs<*iT zFsZ+N=F-Jwa87=|xm7;!*iwxSk$1LKLo2*10WCFyaIvkN`JmeiGP4Fm(k}>VvXgUV&A#CTFe@G^cfAXY ze*+xJaT{%ozW^M&j{PI2H@sHAFrH_+Hpiox6}>@!dglg-)Di$TuY#%Y260#6ENuJc z@BiD~s@z-h;LU>|!M~MOr0uRUpJ*><5xV%Eke@83GbD(H)Q1cCbu5iFL^aaly}!+gc}oi)CU2 z_inPJAmDf7?uS3II9(Zdb<}*eZ-L=h@a9i_mvz<#rMx|dBL6~>(@L~1a|J$vGUjRh zwqz({I(Yic0eo?{fTa`Owzs+;eILn%XO;z7BY#)oZJl=oht^Z8LpI+OA&|>1W`K#f z{iHeHdrwTd5X$=9>21R3iJ99&`hVL`$7?(<=ipZmajBDKBYP{}w@kO4)f~AQ21erT zVt4?>#EhyeeKA>BvfYt{lyQutv56n-KZUgI^i$1W)jTCuYw-mlFS&9FjXPF_|{G7S$i1h!u3b9QBQTIzds zTR~|NPvgtcikMH6?0&+Q%Q)>~^qhDKb%TvX;682QKOK(U1&SIw`oMNGZPo^853O zW7uE>Aj7Sg0Dmpz{d1}6i6GyGD!vwaFGwu^Gx`y77rTbahX!d>nBv;>FH;z5RS9-5 z_~X1aTa)B0@D~w#>uZn=l@qrY5Q0buRl5rJl%XUI z^V?w*JU42|pG8WR8ewT3^_hIZ@8kvjXw-3Q>-~a%v3;K&aAgbt^}djwzjuQEXBtN# z43wAT)YDMNpN)F45Bis@aj|ccEc6H{O4X1VO_fP-AVNsn5SQBeA^yFEP~GQ8>s;aO zyd$|;0f3YlZTL5Pp3xFKl&_e`4FBGM=PKTGEW6hj8ij0E)^hA%YO;$I(1=uA%9stH zot=r%+eOU~mF6n`%%d)=b%~y`q?}-G!u*SPQI-~R!T;0n$r=TB`meszrCf+U!CN0o z*T3FbD?>Iqb28&D$J|r$!?)fsux*f_x3kHvd=FzYfa{&A@hT&EsmZ)}iyju1khj>95j0X z{O1WaJpce<3NHOTzahGVaGOG{ep75rz)6v)Hy#QGcI6zwb)3Ua5!sDGOs;M(o_n|a zgMoX1fEP|gA$2_sFs1?M3zoFO*csL=fCv^Blxo!I1a@@v$n?s6~HMT=lL z5yh4VgQ>NTD)yT@zTb&2t>Ni_mB+AY9_>r{d2d`Fcxc`JF)#w+Z->24Qj8s}YYO~+ zuQj}43fxKv%WHI;j(DX(Nv`#ER`dA}ze^L;^{IQB6FRO(+EjeHEhvQTc)6A$dO)QZ z8@_OGs{UHGdISE;n!Cg6D`Vc0gm8D`9Zt?J1VZ?&ro4rOgYo?I8xx%ao%+{CPsfK4 z+_IGtz7Evx%4W_BYt`!-m)JA1&j5L63~xeg*gN-b@aelGVw(vC;eO8UeTV_;FmSN{ zm&KQcI=yxGK8z6;I&os>R;w}jwVIK{jg30(o`q>(=N_eSL@G{b2mZXl<%K4T?(1SN z$8UE*JFF3VQfKqXI`jHE8QzcnffFr$2@n~`hC>NnIPO<=!J*52gjJ=wr;xW?kEIg7 zS0VNAf4|FnF$@NF{*Oc>nRWy5DUv(+$>-FO@r@j+X-qZD1+8yx|FKjZiCte;(SN*4 zOy?p964{yhyBN#p7~D$YnG}EDXdWKuDO2QPU8w@ zExmeBS;h1h`KsS1Xz0z98R-tP7#SANF!WKb#rP`7HA$cVK&ZD?<_3Y`t^CKPWs!nn_j_>hv zhFoPL8iR-U7C3ftVw1fH6D%@uNXynPYUTKEo0L!YEyWftsh$L{TztZ>RwMBvRlI-> zUbJVnDpmiR-#F6MvrJt}?U5e=(2RTMVeM_2%cJ6@MUJmA3sz+mb%apyvrrNKACqR5 zy6+=4CAaxEH_b>lnHlBwU1~N)? z>gk~1&tCp%u|b8TM3xOM_eS);!lCuo@5&ma82>~Zg3##wDl(&Yh!9E(O%ef5FORIa>XXUY6$2{ROTeJ0Akk2bXi&O!J%**(A8J!{z6hQyXRQg$5D<8d*qV5V| zDdOp?n_(vW-NG+rSx?)7R3}FdY!^qhj?OEJaLcj(Hci5*lRSo0-d*Oh&}b*lsv4#^ zo~y};n8Qdq@s(~R^7<~^>Cy79F@f)0hZZ?VXPTsqSZ>B_mu{sP`ioTwfsl^LAX&L^ zbOI7(413F+5ek{|dK(s)?s3x+DAxZw0-&WC!_7GsJ1_bf>~+-Zc!r>ivhCipDIOCU4D&t?;$z7+=Xmv!e)JAZ+u~qkeg^T5tP0Y8jM}F1;DIGb|WeG(#6kA77WF5#4=GRKvBT3D8zqfOe2a zsyp)8I~l>Y4Z@37SYi$ZO+a`{Ovsv(@7%Sua!gMR}rbnN#K zLEyT*lPsvu>C1X`;>$3{L%ihjfB-J6_rCQ%eNhQ+H3SnpvH`gI zj;BRU_$MrSm6zS&1cnJ{iV4k737ZSueNz4i3MC%29Z}lg%uI$a3g7981_N zkKS9PoiL$xAqPo~trTiq?4vIGnmt?^LWuL0ok^Vyfn=+nPH)+?*&GlEw4hyd_27F7 z58nm^(+W@#T(SNiw%#%>$~Wp7m6YxVLAqODknRS7p-YiQTIptxmM)2*Te`cE5L7^< znIT4z9$?6scmB_F-rqSN&d2%P-|o5YeXX_j+H1dcCztS09lsLZB7Lb*J&SYyAWK7& zyW{hCA6_u;4lO^VlWm%1nSdw5hFc}*B0V}1Reb5RlR@-*tDX%pg@)s!cg z$E%!2m?&uz7k^DHk^cr_1OJ}v0i6EpU0lxc_+9RZn~46-o@M*9XKH&9mBJj^<5fWhB$N9fOm$5BKe+M?|=QCH}BhI77!8~5xURsSQw#l zRW=P~uy;@xvHp+A`w>$^=IZ*=gUFS21J8<(-pQ3KC6}(Og=%=Ew9lfB8KPDP(Nae6 zGefKozZpdn2U?hywBK$g|M@p$m$NZjg5Dx4N{bxWjD=*m0c8=q6+j@nthK7*8%w-) z8^0Y-d9V9dO~9R^=$=!885{Juo{3V)H+7ggNyg7Yn>N_HUO@Uy@L*VIu$dv2_3z^^ z)6o48VSA^)Nk63g?d9T*xz4w@@_VyYa;lvRK zmpFWd0VI$OXLAC9)$fk{(HftP9F7$df6w(3PicD9{Kx9%t^(ei&HZb}Z{DVrkG90P zmQe1kY{CpFcR1hpPJz6*5P11k+wgLaP;--$AS2J*l`hb40rtu+SAOu*@E5jb0o8mB z?Evo2|Gr;cm>ItFnt-|OdcRV9{L;_n)v@s9rtd$y5;?l}`til)T5sPO^q&`=#XAi> zHJq8m#58bGl{Wl3G;-m# z22oo`CZw%4J-c&2vjye8vvgRxIgr&sygDUdX6gL8FYYc`iaBZ`!LVhyCa&wAAmd}> z>ws|%X5r>i4kgNY#?-_6uBHF6F1dxC!#YN9A8Ui)U@~t6BY}eG9eg+oBZ|a`Dv=atmM*kk_ic5_`%h(%~zb z^;i?a&w2}II>#7tc{uEd*aQs^wzM!fd!sHcFFg=SJBPm z6YM`3Vw>YNN5)HW#tAWxrW%XQY&&no1#2W1cFh}!gX)L31e4(zAvn&l-pKWO|4XhD z<^4E?ly;jCj;DHcZ(ctyA7b0jvaOwYy(OG*j8TBDH4;w?d@n4-)jUo@IMQIjQm3Tk8g|;ceu-nWEBISR9Fc#0LpJ zoy2rD`}ht4c~(_!p$4+v{e1pLIVXpB@Qol@$HmDrY+an=&)u&TEoiypu`Echk$Oh z)~&6R0)ze9E1~i5OdF50_cl>q{t48LPM*C>Cw5F&v9e9k-2ZD*J6PXV;2k85l_VXK z76z0p^dpS%y;JXxH~4^j$~j)J_EVrnD##fQ@oqbce@MuRsi7tiHwX;SL;{=p-R zM+hL3|096>Kh1wu5WEHJJ_YTq?uu6ob7vfM<4HRmpzWKT%}NBkRLr5S7P1~cWdySTU2O^F{AAE6)o9O~(S)WBZQ8RlUDczPxK^%$6c>rF zQw;jm{NFv8U8gG%trSfF&17gQFW1=|>;Lv4*lL@JMCt7vpJNx=D$}Bc^^JnRf3u=; zZN9#(-&6W2c$(y+parbXF-sDYw@R<(@KEUy&@*`5+ol#7_N=UL;Z4AA>|(yeLEIzS zN(Uc%Lv5M~_6zqSPoiqma$Rkj%zXyH@5@?E%m5sYgJ*5V83+%${u`l#DRsx^?#4mj zh)ay|r>@V*yZO6iu3xNgr)-IP)h7)shl!rRqSF@P7e$i^GzSsQT!+7y!$gzPQ3f3n zCGhMfHopdD7D2qJD4@8}JM!jye|26@G$-Dno?rfcb9rsCwYHp+yA^26n^w<1V<<$h zhn_3q7{|etq65KimM-}q{Z{1j4TDy*VvT&KngA)DQE3TY@_=aX|EP4M1Q6s0OJ;0B zB#@03)f~MTC2&vUN@?(@rJti z^S`id21Mrigo6XSCD&Dg<83j?KJ;_fn2>#ZY-hcB|0OQpM%c~yjLTAmwSwWdnMGr) zpL1)}Nn1C*CPAMK{hs{zyQ(A|#%}u(6+^M5cly414|SE})l|0eBL!UhX~OnzOB-d* ze^Sd0nMLOiz}> zsYo)KYeptEjo=?I_^dvC(040wj0{s;K}$2{QCwr3y1lQwi=V)#6hOg{3lFAU_Z4PC>7tUr6* zb`Q?0S}q`)_bujLupx_WBbx``RlHnSe-Bz5+_#Jkohg=muw`T!b>Z42dii2``217$`o1kp-`Ch&h8Hu|*a#)CXR2riEX=~sem-gi(= z*219%0pakY9%nOr*!yvuWbdsFei;}0Us-I z1#yrMP@*;anO6^&+-Yn%m>dN$m9IX0TX>@%KV18XCV9yY2zmv1Ol8%Im*;aEV^^+E z-VFT+@+ZZH!^>4>XogvTaRQU8fkz(&gFI+>FMl%_gWy@1uphk20KXChMk0cqVqUo< zV`n}m!;A$Y!2Ff9lcvNm)_7@c5$Y&&a}e-qa4BKoIAJP^2t4XI=aM5$8%22XVh(-$ zKIw*zAK=E_m~i@Fb~=Fyk0KDy3}qIcOUjTY+^S{Vi=}B2%`39CuLiFd42pZb zv7kcahma=u_P@4Cyie#=eg^%q2b{aquIFM}(zm53Vpy-;Q_^ z4WSnx;x@jv`%UKdcB4kWgYEd^f$G1_Q`6hf|EvG4WLeTOGNA8q2F;_bfL8*-{${0R z-R5=AU`O@@(%uGaDE=4VFtUK3D&tP|BPB(92-96afl)P=@ z7bljDkf|XR*H`D8p5J*c=5s4pG|S&CokE<|ltSAc7Yl^=1@(d$G!m8hL$8#Ge%-3g zB)1t;rOSd_rnUOb%;K5`Z(0w#AI}CfTKbZ67!tl_`9VKSH3bX$G2R{ifCs4~0S>q; z5u#9s(5;(i7#A!Lg80WcY2UX5w`OOd3O#HQ53~hoY10V_hk=s3abmr(qzs_87bHiS zT!O3g$^eC14*zUh0{}euE-r5Q_VyIvkC;NWAtR*bLmb=RScL!>^%l3DS&xEk^3=_u z1Am8Ka;KYinAMVUKpuo;UPo|?YW>Wg`K^Qj;^0a`yH}!kF~c!gggBD_RL{^-DNwq$ z5NLM1nfPZ&fYC&jXsvlUUXk!D{$Y!Mp+=(U==;i0p{F3MuC4+89=_>2^ zwXJSDu2p9d+7H_t8k3CpM?=v@A%yY~BIF2%`~Hl-j!L1Gt@<5#Ji55idB^gCr`O%9k2&}j^wmqx3xZDX*HQ#-zI2Dw>{y4>oo6!$BNNa0j$-d7!7j4ZMBEN9Y0mh%yYR3*c2)p zr(oEej(*sDGo<-?r8KnkS;sFEboO--i%*-zAeOnS6vxqv-qxL_>IZQQ85p;^(wtr-=kV0-XE!1IZn zAIc7SxS|NXxf#J~MJdP1=}}0b01;&26&Jl0crcw-FeOZwXYOIuU=Zvr37uf((&>-8 z7~G@arPeYO^WS;Y($iON4?X?jh>u2mpXm8UZ%5;?B21*>B(3m$nQzH5DlX;)uH7F7 zNe)I4Plr%FKv}pC2X(gR;lMZ|)2nrLWp0`Mlyk7aGfu}VRCtr;3FJP>O)0g1HlA9l z*UlDZxn(v^OpxnI_Vnyg;m0o!Z;LehwX^l_LfP6HT?jUmAi{bc4!ux1wYtXB5)d#^ z#=~Ow29IaA|K07m+ZE8qHiqaDsTPhS+7w7cyg>|4&twEOcUfX%a0pYSmP`LCAT5Fg zUc`@z(;ytC0jfuh$;^ZevX6bZ`QGHHi>3QwW#ynR6r8Fv61aZ&fygGPHea7qjF;EA zjtnQN))Lm8)P4Ihv_CjArQcytSYPk8?YQN5!MY^MtjQg%_kY<&n(gT>?JAh4Lz;OW zb_Jy4eDnWr7QoM^YMQX)eit-F4iMJW9QbE3fQWEfRIngdpZ$M__dC&@i&b>x_1J`x zBXUT;o95>7W8QA+wYe`wihyL&bqQlRhmnA42 zs%M|D>&N>gy&zjRwy13^SXpok?Es~%+qim;{2A}Q>p5p(*Pn!?fcYaI_DyiE+7{{_ z!M)x}6XQ2TD;!;^N9*;_lK#6r*>0lbPw}I-e4o*WFP8vjGTKwO7d)DO{&=V(To0%x zHbeRK-S46-P(zHcflYkpR9P@usN14M>$-%^r&@KRjj7?dwMNQ3UgD+3(eMd_NL{qw z-#o@!h-x%HCL!V1M|a}BLgmKvIS!FjZEX`(66YKI1`S3b{8jNXPeLW+xcDD!UA&Pe^dHjNHk^Y*n33xPcC!qu1j{CNQ(FCuatpk6Ma{Pdebx8G-VHs3|^v%8Z&`bF)DK)kFUD&fQ zMRLFPrIH~@tye1#4dZoY42L&^E1t4;8J?RfRP!3kEiSb!B9ax2Z!MPuE|0}<%_kqr zoC8E?F##l(>Wo6==ZvWMjC`(#HHZU~g~x^TbLOB^5+P`!IKy!ZwYRo$S@K$p{XYt( zRM}li*OB3V?jG&^Ky+%VrS@C41DO$IKUr*h>`qCR&)a@&YqQab!8}IU;{V_$PV*x03ZG)J5 z?21WKz0$SFP^%q|iB2r*$Yz~+2>~e|R7)5;dqj|noPZ+Ulndt8^y{y7*T-_Cn6}q&{=QOEJZjS;L`~)49XdNhCFl`}!H$`Gux&G&k)U@5Z*|L-ct=5~d0- zZ2ue`Q}%Ple2-rhd}*MC0@QQ`S&yME7uhN9iuXf|XKgs5f%xuo)HOt*nm4~1M^1m98(N=5fBU#VawQ>}HoEq7^(fx}wc$)&8f$hx6*g_&o>OmF&DQ&TXG!*!W>j!g z>ZJEM2)=FIQf|U!-O3!yoIu?{09X4QBMb3WiCuAmgMIc#`&Wqu2grqwvmOk-G+<2G zFu`tj-%`K0O-;`gb+r(qX`Ag1FgMZiTzQacbg$Fn)3VKAX5YQKF@J+iQk9?Pmb7s# zr~Y44^Jeh>HwlCK$ERgbe7rX&otQl1(UpxZ044BgYtkrY1~l}zw(?!!g}^su?bqoT zu*e&n1$?EsiNWT0$hj!1a@$!8H;Y-~c5xI2&Pkm56cwbudGFOsdf^<=k|_{c%8n=j zD3AilGeOlCWd_#~JuO=HN{*C!KOe1^p|v^M`To;AQ{b#I^I4eFGfspW_AV$6BUz( zv@QKXlk9OL3pd%@afw**Q#0@jntl$fc(ZM3UW7BAPZ^ZMb$)`+&4^@hCW*l39V+}o zF_OUTsqUV*L_dIN={a(+h(XAP?O}uSskG zg2gq17(z-fJ)UMIniVrrNQd5LXmW^7&Y?o9ymUmn)2H)Nk(P(L1$9-=73?d^_Yo%9Y-bre?zCU$ zM^Aa-SJj2}?uEJp7j2TP8L)?fC-W71noGJ-dCy3AhYe`&Uj~sqe&k!RHplOd#stpM z{<%b$e^%$*p*@Q~qX`UIARA>_TO1dfl9}(THgR@E1J9G$gn~l(bTn}@9|VHWw9Hk> z_4+6&);RX*-p0NE<&R%eT^FgXU;MNw2^%mHj#%F|LnMH#3V*AD5?+GFH-}d<m%=-VGRyZw^wvOki{!xHe@k#GTYMdlv=5ds3&BrCxrE?%NvMPf) z4uGNG-Q{X)nDXyW3|scYN-(1lY1$0>@?>9qMV!*Lp12#e68)4tq%WO`L&P9ACQ{|u z9sUSanpSm{p++$R>&GVeDecgliwT#%R9PML7}!`L2?VmW-F#Q!Me8`9_7w;H z_lxj!Mbd-O5K&gWX10)~=K+^uZfwrpvQiAU=Ogr*PvMrHo&ODs?~u*2BpXP#AXCij zRGjU=qpA?2b446+)T{kD0`WTEMI0%4HfmRCdr?X5ZPD`R%=p=weokBV$%^0{(77?G z>~nuAH39?C$p^XmdxlDKaUATcFJGdkoEq=LeC;uL#%mxfBM$V@j0x@usA!*XwV;cW ztW$wCpf!6TP6Q=OYp~EHR~T+t!wR0WX}2MUJSQN_!83D5rI=Ccy%3O+5@u9#w)Z%t z^m9Oj`zijp&mlqz>P~UEk)!P}xe9q-3sA!k=WseWe>i79jcHwSLE9+n;^5r!QDOFv zBaVi6kD`Wk@cylIeC#bo`|!cIp0oRuIv;%kGTPG&(Rc+6VB zFdOpE2GvU_pBmmd7%kyeYDv~3KKl47nKPcsob*}?WCIKVTfWO06ka<6s{Lajvk5^b z&PpP6QL$9WtjFqvuQ4l=2nKG^+mJykt#IFr3^d~3exQZMO(c-V#!9u>6|bXlekh9< z?o;oJA$XiH-z;}aQLNk>|+qgcy_;S zFp2U0^o-Caa=gQMzu#xF_dBAM4qPN9-(vttCTZiN<0~q;TiMfpJ?%O&WfzmB5|-x% z5H*2q+6mMVBi2<8L_cq#L+mBh~j5@EkpA7#7mQ$;!K}aJ8PQQA@gT6vaH%6 z^ttDE@k7x)*e_Ai2e0?5!ZZOHdOPck=RftQQNW(2APtZ=P4YTtcF@P?F?qS$q%Cak zzLEBq(BwFP>Af{qzASq2hezNXCzoD}(@Mq!R5`i>t&!1SoF|H6A<=+Fgp zc+X;m!+DzmI|y#OTfFf;thQ7O57xvVE9{Jk_rOfPVi4t#MfBdRzXl(3S(a5 z`UoTHLvqScK+SQ;1Xna)ysY63vYV_^f?8hfb@O~vXPNS<$=S_Y%FH^}Z8N*@3FlhY zm7%_+YL{uMD;zDm9Hb$R7~myeNswYT_C){?@DQ4;=Da(i&(wj&0 z<&)iV>`|-q0p75fWl#Br+rH!d7=npz^O$iM_p*%9!;3(>e8pZrT+Jk#bhk;V>A03H+_9yc%SYP4mKGIUmZxkm&QjVnfq}9mH z+VAKF-xR-a{QlTZXFGajo1vbfI3eg#R^ z8m%lL{ZHr_Z;OehKk3due4bM*g@wSj&?T;(qYR~sc%EQ@=Q3GNy-?)Mq@YcLAgFQQBwZbT>OKwGFrtgJQr{Yi<+Y~wc^R#6(@K&B9EDT)>U z%S)X7hiiOKeX0lbS$s>kG%_w^adv>thamcyz?5i>)fb<07~0FdzqVuziM2|}|LG>x;$E6yES$wa>x2&72^T(aNPp9s_;!@*@DF`Uae$;^u{b{Yv8|PugMNd%#f(j8?gS)2 zdd75{WcGC31vkZ+KTTbq%uRpn!T9^*xlct3uAubqa#rg}lBDSJ1iw-21vHawyjI}t z&M{AjCWOAG@TYS9u3<@`rOGEw0KPCEe>+|^-cuXhl!EAtn8Uh7< zyS){k>#vP8UK*a}IH($`#GRmd2!DQ3@kjOX{GNIBU!9qOFTfBiAG=dRoCBG7t(7I^VOH#wLK zFV{jYZo+tY&oH>(qS{Y(c48?pkUm_HIRIH`1R_OhnfAh%bfalFC_U@L#Z96&O=Y|R zr0^px$Xh7;v90i8bN0gx<2iIUyf|$)V+o-!1ivD_sgFP<_Qtgz0eG;4Gfsdx+is%s zjBiuc*T#Z=3?wIT3ja6Yaivc`S7}=QCm(J8Yq&Gb9s0YS{@gz3nMst&%$Nn9vmw#X z-7HRTpit}k3=kjw>pN;hQK${M7DuqA5k=l&tMlGP$V^*aB|KgEm0^)qn*8e49y^pd zTpi<^7V9_7L9#y?g?!;hK{!14wia8O1z0ERQkkK0&Cafm4UrBR;f$-o*-X4fl4{`o zsJ2s{4kz{F)X$aQ*WM~-J>#+x;44OD8NEyMcABQke#WcZtENf+ObbGD&c?+f6n4R` zeXi1)qY6+kP!3qp2v;UwLKC5~^tn#F9*upUb{?g$XVDW@rkav5-q+c^_&&mTvK_6K z^X!(y4S_5GGPc(o)LkSX#;+r>}0@RFC?0Y+Rza(!Iqe_pVlK$zz<_qPM*GyDsDj!B#LwdcMFio;xE zk%EvXkXQ*f`{6u1ykFA1q|ORD#FM!(!Xz#-vEBzIpAor~Hm}2jxBWBzJb(G-p!MXh` zd1lU+$SB73t}cM030Dd`n$4ND_BW;}|8hnzJ7xs&3=2Qu;hJPt4tqt(vqzs3G)(eRM?b)S%GS%mBI(_<#a(qpe%R+r-kBA}~}f{^{Qbs2ToSEHGujR={h8YZEP;*W~<9!eC#S z`3MPm#hiq~Ay}4}QEM6br9;B|5nFlW#Z9EbBSD4i{z( zMRi90o>;Db&(r?Y@dcnf<${rm(nDxH=YI{|UqxJn1EZ3C17+Scef*MbC)#U*fZb{; zh*P1l$japXr>Pypi~8srBwN+m*N}u$e<+K7RR)h^EZz3Xc-J_%U3hm~@Z5P{L;lOw zdSQFfi5o5ERl{h98mYqLApQ&^e%FUnvn@O1Y2W%lQ@qYg+sCR=4#p9Tep`Kg<2jLE z9GHYb5%8PPE~84_P^Hq*6p*-wcs#j@0^aJ!yeywRkpKDa0{@lNc5Pd<#>eV z@ZcU_N4TdiBAA$R_vf)q>D=CMi|}jNLcLQiMD7K zxKFme?@G>fL5H|zFv}Q~YO>-}-^s9|V7*qNXTOp(nR^oBGHIHHS&4AiK5DkB*ZkXV zMEwB4?@u>uTx%g%mkKH6m?T~uuONz}`6&lAbDSk|T#`&Zm@_?>m!!~dh%L$wDlt#i zm@9Q}rb!i=BBcfCyT6O=CO<(9-E=h#^Ku4)!;uzhbc+Qk;U2(WtuHbv{U&;X?0bC7 zd28@Z9_&r2XJnBq51R@+ih7FSKs@I5|!2}eY9 zM2du5l{wvQ38!7!`oH!xr*Gq9YzR14eCDuQ8e<8*d{fB-IZb(7>;*ZbPLtR)fC9Ch%Us6&fS(Tr4mM;e(^)( z4VY!&-?~Dm4R3S}ZrRWMn<%WWnHXQc(Cqei$v|{vQdnIJ{e6DM(8jTeeCDz>N)4mJ zpO9DnXDa%8?lhFZnY9pyXiF0S-@eS_ROD9VoYqPM1fGB}kAMtDf0bfI63i@t%|Gx) z*tJ&if{;0}B5d8Pwb`td|A4@Zz*1VYdpFAc7stK0jv>|u^jAQaLl#y zfkwR8MdpNfQFL>$-*{h+^QV5ZkZ+s)I7V+Y!^@Y!9OG@PHDQfZQUh>nV-?hZtPB7i z*Ve~lVSK0bc6=Yu^^<@sm@Y$6h|0kCV6f?je!0oRG=Ta%k>;&1I4f8O7%Xnx_k)jW_)hiHW%j)Tvs+4k*XgP4r-3 zg53}Hh1y+XLEUxggJ)Vh(f2I0Z2gu&TZX7-Dy6%|3a2(cFX%WZbszoac-$Zm{db0mOd?K_gI^k9e z+N~%cM+FghU4#|RSK`EhdK8o}&zXhs7z#)vV|1_CY95U~1skpCT!~G4XM7t}2s`X; z%rC z$aO}g-w_!QLaeLsVUZvi00{nc*O+1+#ft6h9H9WMoukfJW|8`&X~IC=HO}od5Mau6 zzI)zd5Uvd2gEB+Kp%Qf=D2T!!FXcHr@z0*BjFz5diO;&zh}t`bB2IsDgM@u-AM#id z>xVAqHrUi@pBaRY;EBrw`5as);~&I+2hKu1Z$gnY>JAd;&e1Gx%Sa>c9NWKj@>3m~ zNugnHsH=B(Gc@_w{`{7AWF-VdcD=2zYyCVgTTbU;cW&}mGS)eJ_70Y^<^8S(fv{z7 zZ+6}|*t=0km>PVb#+h+5;v}e`w1JD3w#F9cL8e9RFsQ`MCVAa zEeb)gO&HpA5jIXBO#u!<$kln%oWt66nNn>BNFP=6 zx^(C9NwJ0azeka#>X7hah1YAx5~tsSy?zCwA9_ytyRG}CF=f?`6NxRnEJnE86cS|nmp}RO%{lH`gJ?e^S?d&L83Acp2-$TXnyz-YHq^7{?jf zK#XA_8Q=VCve&!IzPt+7E>a^BiOt3EcEX%v09r!qUZetzr|_HnVCK@&3%nMb$6M;t_4{rAsr zOrt-JciJ8dEg{^>j|E*&yG`3pwGeiH!K#i=iMEN}zaDH!;SsHHhG4rO8Z|lCc})bK z2Ep6kHU}!wVTFr5(xbP>mD{V>uV4=aq4?#g$??oC$c4 zfy;2yHkesDT7SQ-pr;iKZGWZxu9fqLvbs-hcAODWDoZkYbu80ftTXle%OR>=y-OK% zIT$`g1f9R(E6)zj|NU+Pj!~s?C}BBFk0U8po$J=QJ&k!yWB%uJ1WHp{&dD#gH}q$? zl#)zJ<8%#cVZ`QCw1dghmaDLcsIudb4F8k~eGYrEM(@Ey+hF`z?Q(xx$i~Qy9FI=&owc~Kk%vq{$)(}{HE~04Tpz;Z{5oSze^c${JHXpK8|Uxdo3z{63zc8 zejct?qvI&8UG|E)^@`zkWST-zwRg*G7AGEW;K?@sX`e0yF`H^-e6~b%XvhaSUh~R8 zLzL=efF?w@KFe*=B!|c-n(!!zC@aH~*)zX=$B?p=H+u1glEG`V`(p0F7Y9k-WDKrg}&4;O?Fs;>WWpUxEhYwc9XG&9=xquCIy%mE+I4FI zBF4$*o#r`r!PKmUxx>`~qe>F+85_s^gg;rM7CDp@+z(x9^V}P~bZCg+j?Y>_kYnJ( z>G2|2EKia;K`)1CK^7GqltMLWqSZw}%BWs& zNxCm{jl|*EIP!2o146>dhbRjEM0~+eecD4p!KPWzE_-q1#L5G;qielM@TMIzxoJ(%z zBqr{byr7W4)sSJanwrU0m{6+sjq>{#q2>da3C z5K&?T^5g2;2A9C-k4;>)mPe;0p0=YY{#84gSY@#tx^v+$s)p-|N zzPBd!{1E#$?yHdfH1A)*ZgO*|+Ih*#;s-2zm|x(yOyn4j=#e1zM}LqX^u^F=6F6dv zns|H#1w%zHoK8fbPEpTJoklW3TuBLzyfCX0!)`*bhP}3Vts+b}t@8@`acg8S;6_MBS3x zE(pmkDHQ3Z5lK63IOI$@1l>VSm>;R%lOJ3^QZFYK@VO6KW~i&c`LvW}dPvK@Th zvwIw7AC+%KX`SZITDnj+d}R;z`!-c6zw)^YU7>k<)jSP+-ZU;bTDaDT)Y%KkkWAQs zX~R4(Z&zTNrz;<4C7opdz^jSbu5=0{*66;Uwzrf`w2BF~_msi^`ZdNjY&ETT1?_Eq z%+fD3aC$SVOB^I!Z^xg_#;;RQKma2_GoN8{^m4xQ*LDg#LLFv9w+};v@&lA4t)}E` zq1lhuhxFw0!gT$;bXxE8Oii%b_!nlQaPMG3nd&s{#H!P{>{q6Vs30+C`k} z?8XXuc`Or=<7Q8Fem(}r`@VV0+kjeV3QhRMsly+dnWEz{=Q(eHd@XV2%Ao{#NFkgf z;NOh1VL^$xCkce1I)_Mu+ZQB?G!|q$;z`JzKdJ(@r~G(lRYvmzP4yP=c|&qX!2uyB z1(fG3Zww(XRM3xuV#oY{_UbTJAujrjK4yS$TR))TXqt>&vcYQJDVtG)S*^D2Rh z-1Gh#SRkrLiuhar)56q}E&szpn6s_a%?BAln0DusIHkJQPNy7#FjLJ8{waVynHMs~ z1YSrS5~-f2?^;Uxt;~oqx3$w|qxZ{(hPHr6Resy7RnK}TxiREbZc!p~o=PcM)p3FSzEj z&K5Y%1b9^xi^99SDfv~HH=-1Xi{8OXZ?4h-&CsJ;4}s5?jnJn<$P|mc7ir$PpVbSV zXnRndH&K0O9FSv**vjq14gTy6QZ`(Ju zDYW^px@i+UvGY*$I#qE^idi)5m!=yrSaWSM41dzWa`z$;hOd9$>%f9@mvztt933I7 zCNgY0K1URkYnt$SRyy%KZxKl2i>xW~!3Yl%R`g{43bZD&=~ZL{=mVyx=g;+U(tmyQ z-trrMGHXQu>#lC0qQuO`9J0jzO*OQ}{fF0#){g1-{jU#K;TW6$0nf8<7iE=ft>EHN zwtnrJs&?BEOe9;qs-mlu)z&XFaH%8C`aJ2Z@|&jHVDBjO9~3@icTF8UK*eL^GSjGB zk(<)8l%FlYz(a_+Ss!UB>7o8!aDoRQHfR5_i2~+8$C;2oNIl<*i>GIVqdd&RX8M@) zU0&%thtHZ2C#67u?4@mT2w=TCaoBjnp|s?lvbJs_`ZF)X)bAv3ePHiryT)OKvE2F6 ztLkk@=6Mw46~>m~v4*GrhS9E+5nypF$l;%;L$k|k(dD zc}KwtRqGk(D32n*?gc6QR))7w12AaB;~v$%6e-Y$ine3ML@Z&Vn*rBWE z3-13f^5icY`~`Thwv3C?Nn5z)5cKE#pW~ZPXd5Q0w`xe!`iM{h-)9hE?ZH;?*wS+$5q(KGy-ccpmZR9Vu4_$?s|50#T`FCS>??koFg^ho7cAp@?Xz@6|*F2=bePdH_^XlU)XxK3uHjj z=->{aUlva35|Gj~!~#9%G$alrP}d+pUs=>No^XZ%Ksd#q(i=H_TC9RlR3LorC7Ed9 z(Z3BOOY-)lgoL7DrI0Pv=_LMg*X|Sm@}Ln@1lm^xa6@}ymFoF~$4VzRaZ|O@Sfl+p z@161Y{|Ab`v;Uda)7pQ(snbL^OGy0;D5@ku{nzx7G)RtdG#}*27Cy9o>%jzkan^-y zcKOp7UW%%C!a6+yNs|CG8A6`5tfRN>tjG_@0+9HW2B@vS!oQA98qh6=0R9?6}*G`nxi& z0(_!y3)zz`0ia< z_ob~*q+7g$p~rghhk7(#J50z@mbZaunuv? zqmNa}UVuyG!H|fNv`^k7MCt5{&FOC$J7Kt;Mc+)F@wb%P6MgZ?(SezFxvv%d#YgLA zM3!I9G{!B4Ar1W7%Mh{7$#L+IL@pl?^Sq1;;y||Wm?)xo7p@O^P)?+t$Go%?9X~Zv z3F^J27*tCAKWx2)UsPciH7cPD4bmy0bV&}9($d`}ozmUirF1LO(%l^r14?(wNXO7M z-@*63@4dh8cmIMpv(K~lUTf`jo-M#Awaw`3dQ55Bq->~aw`u{hT;z$Ij>Us$T$2$J z2(~&**cTI=z#{@43Af#@TChd@zBs0mUZG6f50<1o2d8j0#SMM)dcJN?zroic&(6fm zNW;O(VHC4%0D#fnE5(PVE}~y|Q_x3aRkY`|lI_QpU4_Ve(OLU*nCoe}da0y&o&ks( zz7f~+uqAM|`OLY)!@(N$eoTbU{hyQEm3e7BOjh#Mbua_#Z(WxX zG~Jj<^0odobiHd61ChSCX*5NLKKA;*bAZ{6_!=>+F8OQJA#ZQS_V3yWxnO(dl+QG}DAp@qeKgU& z28L!fq%+WzXznEsFO~zHEJuA_hQF-n$}qcWdR|TrQ=>u???dq%Gv$&Dn27U2_ItWI zEuW$H?DsdipH^NaUzENrn!gE=E)gHxG4uDN$=C@h(MnHeQ>8!&yog}m67;`s ztO+2uf~9$9Imu#6zAu_pzH>`^DVBBJ=J+Bbjp0nL5y^q~FJyaWO+IFl*)DP`<5?fF zv+}_VNw9PStIW_j{j{^Zbts_9GY^DV7V+yp7xnGf4M`^crnILGKyqx}{2al7cnlVY zJ6f=!+p-qj(hON!IsxCybGZ|TI~LVyfvw)Q`_TI`hn+cmm}Ej?k1=ehotEi$K_3$3 zH5-xoBGweB!%|yv{S)nSV)OW^m_EKkT^Gsr9Z&3hDVR)1v_;KST}Y=%23?yb>+mb; zB8vLhgd0G=dDWJ)Hu(Pg*+c+b+V$e1#>yn)XY3aa3CSjNIp@saWT2AHq42TtMEZ37 z#25la)lYELDQUZx7G2A_st#|dvi_%@qFRdKmN@2vnyR|q2A8XQ9^IT9oh}dz2{ao0 z6h_-;sPKz?{pVR24h=cqtAK2>@R^;3(*2bQm!CM0{yLkei70`Mi8i6D@u=$r4bQ!s zM=B^mk{kO3a}+UQU*T0WQmCBUgsM}cv$#hzq25brD{<`%dG8l;zgP|!+o_h>f@h3+ zE$NNGtTH3(T8xcfy9Z@Ou&r-3WOz0Q_a+KrpD~0h`^1s4!C@6D z_1njTmm+s8BbVg7X05!HTHh+B@8{^=FB}0~j_P{0(&M1x39JgT36_7$IkU^7Q=DBR zxg(hjkDPto+tFKFrcz6}12?-PIKMw7D*4+Lc$I?Un4HSlAi2Phd&SYTmHlZ*eM^;$ zT^iig`~vVH`rjOdas`=WPg3*==nO-&Z6+;x5Eu1AVeNqWLkc)|WRHfx~RBfLh>O!jyyK366yHVtq zH&cn6)@|>;dXn4OabM*%KWm*`Fc&;x`;5aI$|ZEP8R|mry8yf5qI~6fpdvV817-T5 zDtS^_WD=^&Q4%=f5paPagd~1FiI=cN{TZVBn!%nE;LRKIfK6`oT^FJ8tzl?gG@kn2t8Xwz?UDs5OV`{WnbR((5`9Mrv zeI4m_yvE509xAOdf90kDasW-{cf-@Seta@wY+uNp$vVvSX*|=A?ZGV~{J^?j%&ClR zgwU(=IS+A>1~P4C@KNIn;^&3eOUT?8E`<#gZE)bwia^QEi;YH!J>IxL4|*Lbe(##s#A%Ps=I5~Ww5`b$-V*dw%d+vN0s;p zS)(o?7am9p??cs`oRFT|^|b;G^CJv8?kA_fD#|Juk({Zk{_~T#LbTe0aKgHgJI!A4 zbPhGsXyIpkr$VRSchmJUI6=kxw!Y`@vTn6UXdG^`c*&d%m|kAUJwJh+dI zv46Qq*l2=cs08dvuk}}+F0ndFfV(F7LtHk*td68*z@s)jOsZcN2y*0Hq+MiA{|dk| zshJ3D0G7-rv>L|KrJ(K2(Lh-)f!*TdnRxY1(-@y|R%=n*{tS z&s#p&x%=;0M$I*eG{GSF7aK(*IhFLiIxsCl-l*}HkjLMgW7U&|oX^HKll=4#Tq--+ zFIr|>F0RBRBh8cw?tb|a;0nsqXg^H)PG4nS>Ee_|iE1tvmi%tl2oE$VJLZ8mL=~L= zZr39JUO($;6Z9il=HX!yswMrJc|6BeLncGA|mmP93b*>y-r4SuUER-&}h3 zFlHp=0>ObWQ8AFe892hymGr#E7$1w}67c9PWL^=8>9U8v5d~8VBy{+ESUjTIC2MN0 ze!zKTp`-2u_8#p0lKxvmt|jJ9BG(RkA)Qz3X*!B{|7n8VxAF=N_yJh+A4wdjo^I^A z81WfLj5fNFY#fU%MuB6eOc-pJ%VH(}BFLY9&En&%!{Y&TIV5L*NIO@)LtR0>uV#`4X^Z?H@ud< zTHkhCQm&VAHtaZauVa<#u2m=U{s^YAwI~oRt$QOUUo*=FJv2K z4WITyugE$O?$?Ux9p5+*HTtdNF?=nIt&Vmam90<7gfA|$Z+n91g+ZM&&99#nQP#(~ z`{Sa9jZg_KJNHN1KFKVxO!!Ly)V9iq8}_h(ITw+Eq8{|?;T>X1rmYvR2p*rq&;sy6 zx$o&`ny16Za3Q61*`uY7bk9Vb%&gft5Fi1!r%I)cje)+{q-bz4? z0?xJ^XtR}Gw!=d}&|OB~R7R)T>3K0#b%|ZZvJwqOy?l+4n5xGC={V;(MM4U_U7;&r zi+#o`zjTT6`>Yww)_~c9h0B2S($!af$37U;EY9~94JS8XHx~rg>YAQs@U7P&6_!Ti z&G2b$Lwq8_^lRVGq1A-4HkbEIEF}YhAZWszj45q?#H~+*T3ch9&3aRbB~o?SP(3;f6`<4mP;hS4Lt3!z_b(tpJg#6jY(As! z&rh)ddp@$#MOZ|C03V;(y1gl9#Yq)bEp$)1-`J}3pW`qr^{-&)w}aqkf?OO?%BgBi{b0Syj3wI> z7a%3(YoFLP8Vfhrust_?P|!JWDY~NfR~#SET7PBkGORf0vnA*rYuHVF{Cc&82YX37 z-RfU?{Ei3l=qVmyxO+>`FVxTalAbus1#$JIVe4-xxwty$NjXu8ZDX6JgRGV9A6fqY4 z>)qVHI70Y<^F{v&7or*sUpmg^x?*gAby5fzdua+iPvsk>0ulk7ib z*UnZ!hS9HHCHJKDp1l|5;=y{C@Fv^sv9HZTZ5gK!=No~@^|%AI+&i6%s1o790~x*K z$y}o?{_!s6-g2ixFTuVu#k>`>EmfZ!bzDf5+Qv;l&L*9#A<|y1g#|WW$aq~0*y&B? zkL8znWZuHVShA^jHiSlOS1tV!89jCHhU_O$h11UOt0&N6M2;_)=e(v_awqF{-$Tmx z7lc_Z+G{5y4Fnj$qFJ5yzSi;`W6t=(+|7|$1~z<7yMmu)T#VknO!{G29$lOP<;?qI zQxuLqBsZZIlFxsm<#jW@LqKa!c%;F%^B|*S{%6 zVs!3GkG_BN$#wMqB9;$_jv=%CIT9WJ@=Dxki< z%g(v+`@A8z?u1PT;U90saY%rlFwagV{6!OtT0GrG;y0)cviVX>+m73vr7}N z_m%F$ymBb)C<+O07Mmo%N<*lYjM*Q+F`y(wt-$jIEu}Md^pl<;O0HDAsAD230&3QB z6h@yvMn5c`odU#zDcdc_0cYNW)7)|5^6+4dw{G&6iREY!)04x@vI~w>>E@O(@Y7;d zkA|ajkZHBc?+?KjM5gCMDu`D~?Qq7rXOn*O*W51D8gew+OexYbbo6~!-?^- zmM-IxR0g#9afqx8QfxT`7e)`y;?%UPN>!qztxCVn3X$|==}+fkUQceX#P71AsCZq6 z0zB$cHFun7?^xVdS$Ze@@WakOq`FKCc zsj6!uCI`I0`q48-;Rs7Z&tD9-L_kXPCe(f+Bc~|D*^E|^u`Mw4ly8=EW3#hJk6h*I z5ATh7Ny9xmm$6&_8$j}PZ(_p)3XKU3@sEB~E!g#w^_iN|)hP@hhINcul{(3Xaz974 z$-$?O1Q80SeAXM;lDPl0kuiwG{P zcCu~EY0}G(-)}ZneDg-Y+nY+vX!~({8bdZ3?Qhr$$jhXh5%$T zj|<%ENsJcyOpda&$8y|BJ8y3CDzDN2`~21p2+H#w41a@uLQ!v8`}cHgVD$P0ssX~> zkd>QLvc`|+WvuHdz1wl<s{r7bG>_0>- z994U>RU8j0-JYS=Uhfgd`{`y5@uU+-X*BmRZ(f&IxWa$*>OAGo0)7ye=+5mHbt) zTU2y0C^kVsG4l=s*Kt%;oRBQR>5FKnTf3)e_I1-1RaiaYGamAYei&JA>tX9I+!o3% zI!m$F#R@4owfj-d6_c{Elran0A3oNJi7m`L^k~I{gbKYZ6f4z(@1KL&phx|)SAN;0 zdMI&XqHU#>EuinV$lq^KYretEM!hgP&Y3@dI=oJZKy!+fec2F{!H|g}4i?G{nhQ23 zE*B0|Na)1A(c2;+-t}IqTw_Cw?soMM2w%O%i}qn(|EMH_Mbuwi)f+LgoTBlmLi1b= z^FS-yv6D-J`Q%`D_TAqrfg#h6fG0e<-zaKZedejt6lNS<5*okU*$) zO6*>*D2i#8(JvhL$1Pb*PD9jHU|Oa1(Pl|RL`bSB960@^_Yb*;Ng9bvkTUh>C{$=+ z0w;f2iG3TpYd=TIlWJ3c{@$ai-DXpx7ehdgTba-{g@uN7l=tKEyO%Rj*DHg?byay{ zq3=ASLL|=6`^qxDh4?lm6A}QcP(xH07Ji%FXwu{>%hqFTZsldiEMMpX=YPpz9ou$Sy}pzB*Lr_3eyqJ>Y5P@vzXA_ zrto>$B7jZ&N{vz5zy()k4wSz6>!nzt<0tq zSMzOwWngD%N3!6i+S~IgBVQ6#&I5<}59>r)m%7a1&1a1i-Z{_815YAyJ&R9G8bc~f zxzw)w&zCGQTkco4h5#@+r#t$>hq6Oa)`Bq;FAKkm#@$WcuJkDHP|HstPKCN09^ku$ zsYW7Llc#FOV4%E5tidtYA#ysYGK``-K4_UOYA8$EFlUwbOEN!i-hE~^Gc2?+i+(@I z3)_NBgf*H_ARyh)b4q^cw_C2)hIzb}^rm$jr_`K=togUIn?@qmvp9rH_!)(4^_1R* zox}LSccXL(7kAd^wNwA2@2@x*k7~Uf{}pND_NHB0igtH|I%wWd=K`g#zmhOk@=yn- z28Wt3!~s+Kw9TLW1(QzT{?CMO)tzq*92PE?B-bsFi?pA&!v~BCOx6)|nR0r5eU{%^ z(?6JKy~%Waq?zgVmjprIoRm63VjOaK)8+gJdR5x?9Z;!%oHb_faD^5mlX!?+J8gI! z5hN701`yKkmC&^}5g*kxPs@GmH@Wts?!;2Nt|n%ySW^udaO{XPVvb?pZP4dQC61}U zK5)y7R5Gulm#ou8jXKDAofYO0$LX`m)PL_B74SJu?yyi*5^O|{wKY^R)f~tq;Vy)z z^nif>sWc+35#>K=yE#jMm!6OF4Sr)}tW=E&zj4H+%p?+2S&P;XK3V`TK+vVZ#hH$5 zOL1LXf&SKVag2of`xGWgEJbGM^)VbgBlBM0rU>isWTxS&1Da`Ts#Hq|X*6O?QQ9mP zO#X5``vtP^nLs?i!TA)s?H<{d8>LXSHsbo80#C2(&hjorx-jzS{eu<)Q6W7Y@2if8 z?XUE&1aB4@6{AuKc!i@~NZvOta?DUO8Gf0^4`38d?k#os$)z+t=ny_g`gOgH? zLD{ea`qa;=d^PFWtQPe8Z^+-w96YQKg+W`i1XK4Ob+SteG64rx^Tej=#_+(&otQ5x zc?&Tc!D9srE6?>?+_|Oe-Q|~RR^)_wujcoy+P|sX-c9wXDHtxaM$l{;ltNN)z1aV$ zu3SKgX{h1wU;Fy4bKr03e8PMq63a;I8vay+pNll`vSR`(2433Pik*{(;ncACepI5w zf}m3$Jd_L$%Q4wdjPx}Gzd*LW(QG^}DP1!$+KOjG+$BUH*u|&?T}{uRr~7X4AH=z? zm*1T^eg9o`#^ao>u%8O_)(|KNijN0zK|Bw*d84bx0t6gojKTn!Fs8e_R`%x7Be6yi z1l2tH4!?aDr0|_sJPYd?^5vVh%bp1_!~Yy!L>6T}=Tq)`1BLmwUSX7tQ=WEmN8{hD zaWm6nT>U%J486{y+oiApV-+7I$8(mP2(Q-o`xnQ2&{DL z35U>`dg2>_l{c?peOWffd3L=E8&jB%Eq>igN&pU7`9QGogB0E2WWm=WlZUW&pF_>% z89~Ha(6WM_-Q4moNvcB{91{fSX?%J5zLnU=Ax82s^8UQTVacs_oZeMsI5&DMmgA$6 z#YUVJ&ma)5ixa%z@+eEk`MH*Y7}0l1p zoJw=h;~fq0LSaNsCaax2Sg``FAQpN=`i#ok1_$_lD|NO&%a=#lD-6ikcK(1-LSW!S z&ld6}&nRk)Pen|3W^~|bwI9q2|B`nj-SV0A-;X{eBMD{g%@M3#{QXuYm6C^WVL5CU zLi)w~ToFsBZ%8LQMAe+<9gL&1(+X`6yK7L1c9ANfB>3w7(bCFzWHaEK$4#HS&e*q5 zvz(K0MkND%l7I1nBXmwYdrg+M`00DJBc(}P*l7KXu@`Q;phj?#!kvoSCZm?=)8iMJ zBU`+%RY+X1n4mzv8iS}OXy2(l=@&lQF)nHBMl1SKMv!)i|7Mr_QW1V27?t<2~n zf5r)7P$LvC5Kqrl(pe@t?AN*?S_kpz&8o>Yd^VE=Sw<+$P2n5N_&mYd93_GcL6Tfa zb`7ApNS+?A==^0|iWxtC1lh81Q_+5D48=-Yq;?*1jS6&RoXL4`=#2c*q1Z^BrrL$QzMG}CfF~EV=hEs*)>D2 z*Y-&3iDNEkV3LOw8r3O-k?<&|1~eT^u^@|`fLi}2J!v)E8HM}xi5tQ%zb0N z{f~wbXssP=>T8F|w$d_T_R1VG*IV=83Y4t|as=n`{FjJZb5;5K30?g~Ut_LetZ!#E zPmIxjHqxve4)_+x_n=E<1kDlki|{BE@Ho)(cJ0$Ld|UZS&xfsZ?(G5Kf)yH$_W~KY zL;)dZK^B4(eAIjo$`(`tELdGl zpFoyDq)8A&-n9&xao9`NK`tI@I zNf=+!)Jkl)vH%toSjMaXQ8+%k6Fw#NF)a&vh{l0n=(pHv2Hvb?7b{C|z@1 zcMopj;L#!8mmvteYn|XYIb`0J2uk|u1>imz*7d+~KLz}&qGSmwLH_vCT(U?*2Qj)B z)q|mD!ZV2pet!(NKDH@Wi@c28U_!U-j2^izIFQ8SV3G znt#klkA(a4Vg%# zRrbKpX}D8vwny*Azw>AF2; z7Q0)FdJd#xE&HjWk~;>!F=*qF_$j1=4awnS_41YNJH#4g9O}w(x+;VI$?}PBNn-h3 zi)j%N%^S7pI93X4V=r^$c-R^YTtZ#SP@$it`Vk)d1?ZlB`2aX_Yxwlp(sL1o;h5cT z2(4}yE1pBbW8SuSiPSdY&L1p_8>@XZ+5|eYtuP`2p*cy1E8&8{_&l!{L4-@u>2{<3 zG!biVFmWWr7e_j>iVYQ-r@%Hc!gZt(c|)t<&|X6}aYoW;_h2bt>)10J8P+mSRlQyM{S( zYRbR<)&_UEornO~uJwr^Mz<@cpw8h5YVZ&s*t!weJA^kqaAW=2+f$44n%8P{b=o^B zWiYh-xIgt}VcB&dv~;hdMDUh@>!k7Q@fyJ~FNlW+Qppt~-HjF`W`>b9|AM>{!y$VzX`>ge4Y zf?k)BPFU^r7j=8iu8!U5>Cs*VJ$b6TZhexm^!o*3=$wAMM)DcmwAPDpGeirxk<6t8 zZoLN3#@O^qZ^T+m`=L)ptKP`;%7uoVeGPGQUSR<8x1MLg=MK5nZJuiHFA9ZP)RhMa zUdJ$&{JyCKIPMoEuz+tS1on2u?+I>PeX;5Fip=WKk`nW@^&|`+hx91lP}=$5BQcb$ z^sto;Mjnv{m{uH!I9J`s3 zD}SDH^nScenA=EjYG%I1$$6-OA}Axs5Q8s|S1h0Pi#_h-SJA zf;NbP10L(@r~el+;x|99`~zcuT}Xlxe(UDj$Ic=m1C?_^%IE_Uuh6A1;@yj_t%Ky; z(LClOigF@^f)fmsw=?d~k=Wsb41yw>d0`Pu?ImL{D)zfelOS{-_arpy3Ykj1&{KMxg3iAthj=<|wm*^&} z$!&Eac%X+zo^6Z*)~`Y#^~@+K;jGbPRhIGDd9ON=$YTSnb=^-wQ1}!b61xE3tBlnP z$@xN)*kv9qHpEQ0OWj*}H$!PS8GF9j38&(A!q!)lb*cdz4gIW&|AmhSxS7EjSPF~h z;fky6j%?UA8Cz8)-penM0)6c2S$YPAh+ zBytfhF=hYQgp^R`nX3_(l054^ zD4CxpN{6l72i~>uy^+~@em-LMy;VW2=MzU;CoYdrysTTanAv5ZAGAElnNqZoFA#|x z+Qx3+EcRGc8){2+j_o71!#i!LK?h#H|D-<&ZrlGzL7lqY;~`Wy1n-Vw!;ZdCfDPC> zoFxMefJY4LTcTO&5!~M!gG8FSqtI(O$3BUmIpnB$vjwC!d;G9L);4$pei!*R*n7D- z^xI<$_<(F^$bILd$8HCs==T$c;$HZ)GXBJ+`M0KKgg*&_QG!hOb?w4TrL%L2_hs=3 zZS&ER#=NAGEabhe(&*uacSvPJx+jkcbzse-_Y_kEa3s=f#G?>x#;5)Y%9b+!PaF;_wvt#x}35B zpV1G}-sKdA{|BD5&q`oJkKv#U(~A9(z6H(aT|G3cRl}oRg6KpVB+H)sBJujg=lYLk zPRH6eAgfIi-rU-Y#aAk0$raM*bQ!hjAJJ5oZAVho)u-gwg!(Ykj+>C3-ju&+LD9}G z^iR;4_I8G8J{m3)=p(0+1pUQGc@Td{PpyUbmRrTTZMk6jlYe|mSSqcK;49P!1Q8fB z0RUyly4B_?8AxJ*PE8OLVbMl^z3!%BgTEcTHzafONnPX?AFc6FREqAfmVCn^VvJ%= z89CMiwlKH8-x+x;!`G43=c!~*xffHH^poGGN(tJW<~0xel{sjSu?~_ArH=^OzWcxc z&Mijs4o&qS4Gz_U;BQ~Fg>1N9k$@wZFOc5$&kA`Sd_UGf3VA!!-d+LNl9eydQXM3XEsCwVtEACn&{fW1wK|D>a zum;e=TVQ3(v|_`C>5?B<)5~FX9Nl5_Wk+_vEPxby#9}pgX+mVnHgkM7*vn&?KM;2I z_#M+EeglowteZP}J~P!~H>rfZj7F(kuMR*As9}EPqs`zV)btw*qj+!(xu?wYCF$rilA#>8~j0*((nn@znXs0`I!BYW{-D}z*i z#?D`q2das&~4Ukm{ z5N>!Uq-gLF8$O` z>JTAe2vOV6$)>A@Bc$ZA=8g}qT!DmO?zBxNc!DhI8<{cPx>2HLHi*Cy3ec1+ZNUZW zLEkgs8ZH!+l9P6#HC0k?R}K18z>EDNt^&OSRp}0n*DWrsTx--Hph#ktvBcTfbA9K zHxHL2_R)D%mf|WWb|^nLw)G<*vZ}_4j{BR<9KHYON9#LaKFXi-#Ji)Vs0h($xP`+@ z-O+*+J3=YGV)?ok6Je`?)aA39$QP}D4E^h~dmu|`@KVcqyft}{8PZ(?;@`tWZQHm} zTIzd&pm81Vow(#*Tn=)k`nw+{1PeJx*EsIzo*K#@Q2O3b4KZR!2XTipWoIYh^tkJ~ zjG>^ptOm7Y6H3H5EuCb*H$LqJNg zCgFkp_tWSl=*!)Cb3O`5@(aV;K64(?_Wuc6R?3lOY4lT->quw_S6Z^ZxfIjFDW>nR z8efbR)j*QHq%2Ca$K z5S>6JwJddF6-*GzJYn-o+|9fZ#2bvw0atU?yYgKC%x+66|JU*35v}@)yDKRAyTXeh zlrO@>(`nuktwCM*o^2~5ZFft&42BIsCQXqy;o}naUox1)Xy?3HV}3Gj=tls@JWafRi(utCF%Fv zm#oVlr?49EKL$Vg`mkO8mNgY3G}R$)S4Z-Z2D6jnUimTo!z;(;6&q8hlPsU)rA~H? z@w@g$M70blM&bo!N1F^z2#0n1EZdF%$X-r~U|NWaikH^-6+TX+BE}qqCy5}apK6Wv zoCy}`yCmcTWN;8F8ci!de2qAAeNEt6XSnpwy-3h~>x*lvij7k!i*L-`s-*D@4Hb1F znvRl(!BBS=`&X-y=R+_JH5Bm3SlgcOCp6*id!q)jmI?GiQb4`|(ij)w&em*7DowS} z?O%c5Ex>&?Muyez=uS1fx6akPR~qgBFF2VijU=t$Im>Pck4q7#G(nb6>gF%Gy~3yf zwoax!)3rYMNzA?4fMQ*kloe`XUF2z@gi|cVlLqaqyF}ujaFkVBVj&l^(o>za443yWnm>N}y{RFBucfPZx{t6!X%az-)`NqD@cw25nrp@wJGz7K& zD|0*St99B7ey~_AD@lg5CXSOoM`Ygb(H2JC*x^Q`;nW8CLq*eyBV^XliFQ3HmkOiUyCf{<-_spRxJy)xS6!se7y{9KJ9bB6Q(WhSMvDE zYNOpOxGSA4EKA!4{ldsb#W%@*?$4aif#=2JcB+exjrPp$8K7<&li-4|&P~4G;McaY zf1Glq$J%*us&3Ebp7NR=CIbsdg>_jnMRR4t%XrQP)rAK~J-(iO9ZDKfNRv zzl{S@#kgzs*+cJFlI)}gDdOUY0#CR3kf2^~d`fS8emxJGtmnvF9hL8{d(&Hv0bI@` zg=_IPdOeO%J}-bo&+^l{ACC@Lbz^{6*SdsCjx#f`WBN5w#FpU>R4gq0$1>(LcYgIJ zBHuTE2HBPTcK}`ahb!_AORvb)M7+ZaQ4e&q7i?2x&WNv8GNhR?jZ}GcHE)GKyFCKg zTxMmh+|kyy|si%$!6lGh|n`N_Unu1njYhMRqay^(QARjG!N>=U@p z$@K7Go`Ns2-Ez~_YkH&@z>HW2oUrip-A{ZO9&ZZl!I>g)ruDx)BljN1Z*uk64Tp@L zGI;Xc|CPar-oVG%brkf?BGSKa(hfiBTcDZRxzM)jktvIAj>|b71D)7LlB(Zz;B=NQ ze;+Mcs>-y>;pM9zFjH)gN%O*_oY&@GvIQ7k_dMg%XZt;RU$LRn4&EFx{^g!bAsp0R zadAF6$`cl?xxc#N#`_6*Tc>j5YAR>$t?%V)rop8X32Pi|r}u4XVcJYCug1tYS7-p4 z{TKvw&3e1v)&<0nR~Lxkh%Rk6%Xc~2kN3CUI7Go-#O#$^WW57%DC@QkzwUQ!QU4S3RK>*0#xy6094ac$(sHvR+@_Hkx4f z*DFqMXsFCBS%^ggCw8Jz(ND1S#obD zNv?Ko4KLIpEj%B{hWi)08b$?qK)G?1gSxfBq3g!%bd?67#mA&f)^A+E?2*`bdAzEi z;02r$_+7C1ofAibxGo$_>pB+Q+n)}3tw*^7% z{#B2XZJhpR2+gX#3$Au4D0E1QW9C=1qZTu#PZc0R1s6AYIhNR&drbZzA}LDqnv+Q0 zjX}ON?ana9rIYo@KVNs+wqLan^$WK&2OXzG7YjIeOBh3*-2$uFJ{fP{lQEFDgwsAc zku%0?J*=w!4dP=)(jl|!qy5)mc292>7&_zuu;`?>e+@L3h&1y&z%8ywAr zYMTzkHZE6Ae&3D&{5T~#Z~=6*|1D)u19^$<8}DMmmBz$|RSSw+y(jafWkpF{3^HzC zkPi2U-Q}Mc(~i^@vXLKb!Eg^JKTXX6z2dPo#s@7MG`qjB5h*&+wH<5SpYjdaeY47Z z!reD;<<0vw(J6L7tXGu!4?A&r;&oR`Z=dujbLsVlB0ArPI}x!RZRW?vBxk|aKRwYA z6>g#qNM=IzdQyGYhZojGj(_q+0?24mmXeI-j8%#2%-*g?@{w_R$crJz21|tfzHQ@J zaHixJx1T2@GfC=Z$TfSLN-@A(PF2%HrI%3|1%hD7?!FRhD@Mz}9Exp_$C~mG@_Npq znf!q#M*Nc3;>Z(@%Q3REpd(RCkNWox=g6+dZj^D_>HXbmg)n)MWFm9%cqNMSXjalcv1n!G>UfYhnAb}aelO@RkLygIwA9h~?w>^#FCiilJ65CNG})}xB$$I# zjs-NqUB{!nm=ko@d!!k?%`1#KX+l}cWJiQSf2Y9~e=!LUTBBv|-b_zmt%vAwI(;AO z6T@F%I7!;>So-k!#K%iYR>93rFnG>87|fRxHoL%y%;cV*p6jK0gFbC(_NLhCOlYSz0$Xu9TOz&;Rfeng6hP5v{?@&#okOAxqo&E%l^x+i9)gGQA%-1xF zYI!kbv3~K}aGfOuGVvDac#qsRM*TRjDSXzUL12T`xk2h6y>%-@nu;`C%Fz>N%D_Io z-6SQa4lHGE$yygLTViL(%8W1$w>FvT$PF~JGE#-XhIo0~7e$N6ZvnIV>ih++n zjiE)!{vYRV6AgnsiH(?2;3b(igyp~)Cea6N8-F)u{zh;yywXY`Tq*=5c!RYzU(&MW zOp|ZoSC^Ei;t?L5lTconzpqAcYd+laoGr(-<OrY?mFSm20M1gM?FoF1rX`k^}B(w zi=SDn9ZOgpW^&*I3rPSzgQnDwFh?ltX@y@uR2; z#!$Jh)Pnx{_;PjNYB<+FvqW8AvAfmEsW8ox0Nj?y23Q!E&HQE*3Slit43E<&^^!3- ztfk?_na#<$kj~$-pI%I9c{F&G*^92ct)RupCFUxFh4#~d?Z3g z*8Hx#P&yG<(ctpY|Ir8&N~^6LHKuTJ?z*b9-^auUpYncD)Ck-7=_K#rAqo?jUkT3~ zewLe_2N#gjR-&H^IglrI3$XFY%q%YkAVeE5n;t=hO5Gn4i6r2m{J)as1aKw5+%a(3 zOYK({9zv-RU5xrzsgsC!5^e=^(_y`Mta7d?-ArlzK{(Kt8cH9;BcWf&D6I13s5cMux&Jo_&lf|sxR8q0U zTIPH3zM7KEO44W}TELg|jJdY6=)e^h6ez93%n@KCMW9hbv$N=b1*%_jbD3+h6T`Zv+Am|$>?H@(H`Vz+TG&?>}SV~mzAxYQ~Ib7r9 z9L8$hp>Z4n&ELF|abicO4c-Pw2IGp;4KCR02=VdMsH<%Q)e?a$=nkOe-X#nzVA28RknRRY$|7gxL=}yQ zUG3uoDUV%{yisFJVb2RV*nBN1#B5zyY6|K>jf2xdkD`24a zVnT9Y5{!7vV9*`>=4r|i&Ws>(%O!`ySS9(f58;~mgJ>4!$EG05p+$-{N(8m`wCBIY z`jA+#JW*>p-M8g2joU0=CTNVA7&#HzT-&h~S;BOc-EAISZcU?eAxPP9tszse5dJ`l z^{Y?$k-_=8_}mA@3?}FwpyXQH4~ODM{-1FW1mJ!3lj(a_@9V3Oa%&8~INfS{VW7y? zR@)12xw4MILo187M**qEXDZ$im^7fhS23r||E!1A;_!QGvQKD@~GL`AldZn|K57|jl zIG2?ceXDX=p3+}ULSH-VT${vQ?^QPZLzC5aZi{ufDoU3^>(zHSpCSY}Rjw5pj%^5s z#-LI$woNpN|DAd2h3t3gx+4SDJA0JhagL1-js1FjdE>>m8BzT-b6Rwq9Dl3&4`v_g ziAxGPr1%BPTGmfrX0>)z0gun1FKZ69!+3kclaN63ZZZlWHu%ajEdyL3NCVwlJg1u- zhPN{o6>kgMbKrhcD%r25?-TN^%?SNg(IlFVxCqG}Yh`cWP0b1F!Pe~Co4o*@NRyf3 zRJIwIbc!p1(uT9&8hn3BsctE6V$|~^11=C|LSK z*!=(N!9pICMt7GU}=WYLV+X zYUn??A~0)@Y|-~ojf!=0?x)R=0t4}}L_u0$QDPg^e4)g2;8?Xx+F3B8XmUb#%g!Em z{Hy4+XJ#HWe3ZG5Wj^?&S+ae2Rcm}S)L?LGnFC^b_+s{OOm~Z~NF=*H2{jH=jo*3Z z`aJ~m%6MrRM9CbZx{w{!O5?rx$CEtY$c*91FdXdYe(jnRqLDPrFE@wl&K zNA)h|7nLN=m$6Ief>Hgf+m~=>tNFF;KfAZfrqG=e;u6sd9yZl!yc0XrkP`}iOw7lle&a}4Rft`0^S_1ybjeyCn;`R zD-|vRy2YJGs7o}eW%6Oqn%|8a*l8Y+;Z$3<&S)LaSWuw>H&`6LKN+)$P>n=9rrE8e z{UUjh`rc}yv5T9H3VScj))+r$eX+fN;3lva6Z%Q~!3yFztGdF^ACBYKvy)!-cR$K! zma_c(cin8v3-8&~!YE67&(3t?Q7hsJj~9+koaiAs10biq0XZeu0otc#VkH-m4%*Tp zUDN1vOr9H6uR8VkVPPr%aTRZ|aFjOOR;TBWzu43zq)W-8HdoG>9E=fYbgX2A{wyxh zKBdJ!7hO|A&E3xqKt}{_&EU^Lwe-P$7hgMk;dc9u?=9XgaQVR^H2Q5_DQ?MYw!)5Z zU;DU$@Sz!fnb;+%JMZ{QlDc1!r?yzXrA$+sr>ACO%T91EQ_YBR`!{5D^?$7@;IJ9w zLQG+jt2}U{W6T2kc$55*7lE@8nQ%k#cTm;C1LXH)_7M72hvh{Mllx3@TJd!AL2FG* zE~elID;8vE7s`-!duzCk$1XP<@7U>0mm=V^xB{I20OtP#0Hw1ub?~d&|3dz9C}hKS z?Ut7Vm{bk~TY5}uFy5ne*lW~pPOGzpyYSIg`8U;&oTMewG7lY=uoHI0oz?vvlg2oamWW1*SIMwhS$IGj*dOh7!eAx zG>*Xa^xR6V<`H+wgf^ZXjYa{KU`-wGpZL^%^&+bgcX{a+ck|p)ve(ml1&I^ib zt1;(&(z5TPsm<&Bh#DPXWr+qJ?={*Kdy*$6$Z`WNIv!=X# zU_tS3-uQ>id@)Kp_V(qm@RSAD1-TaAi9z``*JcCDc@5&gR?>A8EK|mUo~@v9+63?W zbva4#omyhf0&ccq!GHzgWzA0~o`(e#JeI7C;al)g&JP=#6e)s~LjyQ>#$DhprudA> zY?9$JnXOwTusRi4c!Yy|KD@@KcvW?T_euDwqlm^+ zOi92^FoWyA>Sr20%Hx|{h~Mx^C`CVOqj_>fy&QA?xV2G}cEb^aKX|P!u{TjpeXY1C zqaZu}T64elT@&V*y$#(8&UbvM9 zK{`@^(sz?}%G5k23cW?Xeeg0pkKyLnb@n+S?swUNe%z3#lgU(4j>UbIULlB|3jQa-(%ntnN_caM+EXPA-a#na|{NjWJiB^t7_)EFux zock91onC@Mit7U_v&tk0Y4EK&3R=Xgfq8aDp4-U=cQ~VTe(cHeLI-x7TyxHtRxX$_ zN_^PlC{+48fIj?`Q~Gd;RKqV(hxnXmT~Ly@wiC9bj~0YcSxCiEW)W*n6rC|K?#d3p z-}qr^tW71iK+m?COKt0h@STz}XMf3)k{|!#7XGKspi6Bjd>&Df?TQcm;k>V>QWumAT2P+&X1%Za`O)=r`15DU z2hYhBSAIAfk3GIiU8d=cet#X$b;Ev)jwR9YLE7$fDvF`~19W*VRArUhq1}N}TTKng z`F1fB!wL%LvBI;_^i+>EbDVS85qwiP8G`MxKO$O_8+cxgZ*wDs<~j%#2i;}EXDq%J ziMGuwCh(wu9^6qh^`C2A+XxCK1ofnTB<$Pe*DddPKzY1QrHSNrHk@Q|t)g)_9Yy~p zS+1?s?;pvVkx5}G%HbCk`J`MRaY=dk`)*9;6TZ)0jyrSjKeRQtu_Ha z1}hV3BYXs64FlCXJ<}^6Eq=Z~$-og-()S#fn@@TI?i>LBcDrJVkd!wHgzb&`&fr^6I zlG2}5$=#OMVqdVf1!?)5wPG@%@f@5oK>^C%O3DJVAS$Y%l*G|D_1D*&xkhKIDx+UC zoW4$+q|G|EZ3-l(8hAo&#t|K3rWQaP{mxV5fmLRF!DjC~Hy(XOntG-o2Z%LQGD#8w zX*mj*YXk*CD=24bCg}+1moSCdcs5_|t(^J3_Ez}I9<$gw>tFI?BBjVJfG@4q!BcbOba=T$mRYLaV( zd#_OcK3|;KnMC)noP)0;^B1nTq#FL6c6BR?{hOT2S(hn-$cFxozT*gYPmT>wr|b=l z4?=ed@Vnpg54T5UIURulY#z+Hy?mOS^+5L8+}-k0@ueX1^9jWX4u?9(?A#{69$|wu zf&6X>;b8hAjEh`5T59%5Ny6Qi`+Z}u%01>qgH4r){tbU*EuXgA^({~%AlPW$X2wV? z^!(yP8mDWA-``$o-ydHkBNu$sgP`@hJTXJePpoRG0iyjSz5bhxtWFf3_Bewg+g=c1 z``UB7vst}nw%+))``$bbNB=D0X`y{w+WZE`@3U?6C_G(sQ{iz5eQc&({|{$bR_SA@ z+IekjiM8T_6++X)vUo=?E4uMe4X>Y+lrADU%p%KLzIDn=M&=u_@=EtPWYe`eC}SeYIj1|68yx#P3O}$i zx^h&+N@3{}!mZifNYGc+l1CcWb$%8KQ&D3Uks-W?ZV{Tii}Pj@vAkKDVux@1LYIn} zY8y}1Jx!(|oiabd-9y@1{|=&sZi1+oHw@R3esZ(h*n!oN2Z9w}b>Rkum+Z4yoW zQ5oS#Rz!hGN{_tPbm(LMj*E8^7<~b$JafvzFElmpo|@w23B9q7^WuEg5t$Kc>%g_$*yz#()5fD*W>?(r01k-$yNZyAEg?#oV3iLVuv!_)sd10gGa6E-}imbYhF)-uyNlPE;AiIwF?+*$m} zZ%&U?mZH{4Ii_yss;Y3=$>ph}OC0KOqigdlC>qGRl_30p*-wNh^n9(R^5B-=So_ao z!hAc@HFC#=YN55Ce%P7!Z{F{s+2>-ageNzRo>l2a4&YP=aa?N^_(K6JKVsEfu$bO3 z6=7WAk8p$gL$5uK0QnZN$8iHgpb7HZ(`Q3bTFz}30KEt8s0-ydTTX|%kxh`G1?0*p zcH-N~nN#_+RL&wNIecxtkVkbqK48Wt*%6{QWH?9fT+U1@{Ma0uJNh~5$N$oX<=T0t zxubMP-P^jfyzYI=f;8>-F4t;_A51*fDW^>$6w?pk=41yO7AOi<`2WrZPk(t47TD+I?fJtI#uEa_eF2$80k3IRBr$_tMLr&;67~jTU;2-O`Aecl?=~ z*gGdlCEI6{7_r6wOYQoao3ZlN_b2!kam50XpD;#WJgj`XHK6AVVez^<{^;_O-nC=i zf%}(DuH91!;c#OAWC6v_ado1@8}019!~((;@16rkTDD$$1XRy_(9eQ>*I7^$E>)vm zf&Z~JP^lN5o4MMCAd8L!I;$)-(=6<^@9oMS#q~}a%}?pf+I%B+)$YUhiN_UTN!|}$ z{X~S7JyI9>_Gw4nlzo3)uTa5EOFBgx5G+%5E9G#8o^Hp2B!qE2#v=n?%Q0uOHL17T zI-k)x%ohgaoik)s070627tXX{# z7g{GQn>{h(g;e+vRQPqaO-#X;-|Y5bE{^d+vv|Jhn6U{GA&u)(Z$+Kxz1nIGs%;R; z#-sK{i7QW9Ayrq$#v-rH@q-qJZ_i$CVtL%eCK;Js!ACja10iB17kQKp3xu_>wq$-@ zJFa2KEqMKSYj&M`Fsj1NdpK0!lwyD{6y(NpL6x$?#bL4WK|fK<)OjtjJPRBDkzD&8 zKmTiOHmZS)00V1faC#f1U~g=SYabGk5slqE z9JbF5T~wF9E`8j)%(L`bu16$b;O4Kl8y<|lN}V260c@BkcAARVvL|aAjEuW$Q|*L@ z+_&CSc~NG7qTD^}MH%QaV-DE#_kk}HhSetWvKXj0(HqvrkPQRl8-6-ie;42-_DeenF2 zqV0p09aA%5pLt{2=uGS6Njk{OU`5yydCRv}6nA02my+z%IAjKJ5cnygPHDeR%O>vd z$eW@iOe4Bq?xzhY636c~WSc=j#}LMq++F{+M#aL=EFMW9`FA4#h!|;a7ZLPjD4zEBo@NJwAHlA9s(%^I$uOnL1#u^(WdpOt)QLn?HH; za+TAym0+9JJ@2k`=&$4Zbz>ngE=73lW_6|=8P_Ebmh8{K zik|*wzUc=Ik;|&G0z{p#**T%dj-3x6L3pWBd%!crd}|4D>FI^3K-XC_foA>p2W`;| zh5{khvH?eOm@hz}P~-vKH(;)dyt4(OEdbA@uuSt}^BQF~h}sXPGoMM#ovF!` z*2l_7>@4mfJjhJ^CU!?lPLI;i2aV)jD`mV@^9|tH2PT3)BXN^A<_?~hZwW!u^c?MK zXPRHN>Ucm_#H*kI!~1Kh_2{MJ1NGCxv_^y>ALD6+m49fPFR$4}v%LxDsltZp_<_HT zS0-d>A2EkUq)snkX`1Hu0dz<(+6s8eq<&FC^yiBv*Bb8nDvl)*$K(OqmwavP9d$sy zQ|H|5J$>1$8&d}buKZ@)|8n!iIcY435x+XLo_C|wrcIx6FzRO2%f}Snvv+-O1X2yL zJITPdw*75}Mld^DY}lx|g8)wim&{VYhoKQkNw}&rz@973q>N9meTinjjDYXF*vNO1 zCw5*HXhqo%-cN}J1F-3m*yTq2oYjBCR`^6*|Tf^3z>x z`&QF1gTXut%D=ODVY0?KZZJ*8rIvWL@CZJ$Zml=q;B3m|f7;|vu?+OI&%E@vgR#$A zd@vRR4g2pQ)(~?;5YOg6Z2{=2!>B_Vhs?9Z;=C=|4PByByJR;SRI*D`@=~@(1-bX^ zp4MWxSMz*0TF7w!f~8QU8NK6!4u#Ttg0Rav=vJhem!Eq{{bid{e1ZwW=?TCP7w_Nm zh!K_{d00(zWZm73`W=N?C{y_*U0(O#Y^J#g-J0hKT6aaCk7OYvholdw(!3p765z2; zCZ$wq=wpUE_TnK(Cj2~m8~~)s&{p_)2jjoo@S+*yr-W>#P9D2k9Dy5TO{Kt`n6{tp#d`0 z)>3mvX#klWbvS5pp}O0lVVq$uON4Q5>8v8rCE(W_><6@VcSh&ad9PZ1r#)HU-Kyf~ z7cwc6cg}ICJL4 zH@|CKK3B;@IuGl%pFUzK%iP6PG@}_29$>PVx^5WsfKkf25W<71-!d+z z!VS&!7Fat>;DjtKZ|fvX_i}c~#OrWeOu60A5nStTI=x?*GuUUhDP+hKGUqmg0F8Q7 zoA3UqfX-C(EbYZG`j0ZC8NlcKZa{+2clj0&0V`A(PfUI2`6o;14$*JP^`%q6NAifc zLlW5+Cp*I$WR9z6lt99HGPr63$eIg+>u&w-vAJLesGW3O8rg-@_*)*uQJ3fy4JodT_{JUkzf!Ya}M_h z`n9wpZW{ji6HQZ^dG=dJ#Lx+{OcBNsT6+XXsg46GCI$grEJ{Pp9&BMC;Gobdu75FW ze+js_m@s4HgUV295N$62)pLCSnu`EaY< zmV)KPmO}OFSyrg`8fH}CgMUmoyVXh$74XAUpGUJLKZCyh|OLi}aA|Rg5^LuqA z^D_sf$&{TWGUDC66jCw-Lj+@*bqd3T-Zqb-X3s;6<-%XY*< zXz0R_gXP3pkmSPt7B|XKj!H*nt#$~uPuGFmCgJ9qBI4aUdwl2Ijc=K0uHxX2)FvhH zUB89l2<~(YT%Q$3w9p4rt($^~?*t$a;nEUo^X9m8AT83FEBDVPN*n|1f*h16*c64H zv1+$TLD$uI>=s%ZF&PhW~1WZ_aZc;Q*QhBYf5F|op zaczdE;4)DrxECk@_Y*j@id#7|^K!zwe+zGuc(3f$R}VXJg5J8Lf>=OznkN!+&uexi z_DiC7z~U;-eu&=71g22e=(<&e*uPTd!D;!QomOZ);Npuot9)Gh0#WJ;3&Pfr8LK$P|J8QZ3gcmTGngu3>m*54eP zU%Xq%ms(?evoE3O>)Gbr(CTk9Sci$xMFUInU7C z4VYSG+6M!q%YJARp%RmT3uXS{cUPAzmUJ!;*6_v=7ISLFwWtPoZLJ?oko1ALjtmRHq+!Wu<1nc*ATL%r zh1Tm)r`MNhJ5|F0KPSq5j1JiRnNXAHO48a;y){a8zYmAHKuC<|ddmpu2mzd#2$v?k zLLG$PmGToG43Oghr_&H;r-Pn9O>hO&8!_$&b&UjuZoOLN<=$L0-@S$C zL>C$zsqO^WW5iJX5WG(qc{4>%|4_(K|BwYUyitq+E}$JOd%#Rgp3t{c z3{c;Q{$pI*I3nY>0s{^pRo34?XWKQH zvwA&&&(lkL#vEl}!~4)GfM20>lgmx6+{(DI_ zPz@a!w}X2Bo^h@*vN;8Exzb3*n&B1;8IWxTVVKz5JS`P zEH&Z6`RC$O7}~Oi?qqm%X(@&FAU_7=XA;&4KnPl1K$)@oxaG29M6(6B_f#<)=R9k- zId$M(z1@w#XW}e>DnYBJyKkgR>OdDq({fXSQ9shQ`lbh9Senn?~sTis*gZo9BS1J}~rh9O4f) z6ct`u{K)6R)(dm-;m_4?P78;2DUa}~Z~XU~azfZqlLa1k26kR}?H?E!o?HYrj$AfK zmM4NnAo=KN*M^!TdUZo1yEZF{H4~RSkilV z5Wtbc)C%xn5wCQq#DgJU#?6h7){v>fc$o7ngW^x6J|hofkgww-@w#?S)xMc@4EoD- zFrD4lr2-VF+7x}D?0x#yYp(;M1ax0)#9qXfY+m>n4$ztqdT+-K=pKEqtPZ>e^@us` zE&yHlT+FS85m{pv+6~cl-Fhd^g}5Pz&)^z}>|nrQLTDAR7&&t^II`6Ju!<8)^v5f1 zjmay1Ra&pelyN*a4A%|zZ&lM>#Z3l*{hr}Qg244bYeWl?ut6#8QmG`I99Oau$-fVL z#XnONLN*t+-Zztqrz<0N|3g>QWufZt^V{*juSOEen@N7*1}44Q8yWrC(xR0AuZ?#QQKaDxEsp0pz9#F zB?_lJnu3os;~jxDXhCxJNV{K8I8&{^ME8M<>ZU;X3MxvNdHdH6|1#7ZggpM}*prmhO;YY&8R?w{lWm?5_zt_lzvj zEt}dKPhcWh9G(s3w)P%m!3R8kJak$+Tf-BdD88l+To*E2+UTefi2Bn2+}O?ro>cp% zTnbq)OdUYHOn8T$f);fnI|}k8tL+Gfn%WhyDJU6`xSl9f!pp4W_ErkhD~TXi!gtUZ zi%Ml?$cf+L8H0~bO4sg|H{wVQ-dEzPz}OVJt^kJDKU5{HSBpVQVp3})VYjR1sz+&S z#dk-o>-~YGzov4$U(?&^DEH62o>!SoOt~Cn29omVI78y=j_2*hwfY9Y#UgT88Tepb zJw_*iG0nrI$#E&c^o({X>Cdb*W{|K@3Cc6{p-a)KXtTpY=vem8NyIIgJ^CfNkImzG z*m>)E7P7eE0|UqN&GsNfH-00vAVgeTP#7rXy-b}&6^Hr4B6xp}Il~_a-mKz4+$hDW zfI%JSJzFSzxYI0D{vkTJfNRa!i{{m#-LSl7EM^Fg6Mmi>q`{+4u zx$8A+R6_2}3ARGieNVUl-}a|G+R77SEpirYy@(yw321V})8xu#rWv6Vmq?mzG!xXb z8z_=w15Zvsv3@I7oyPi-| z5t)O+qTP-x!NF4BF-T_v?li#5223pG`@!TCy)9%oaF#zN!DSayl-}&+KHX>ozSEK= z*mMq;MGtJPQMyUt5Vb5t%z9Gu)A`0FTsLZ}D4d-@c7@oof;&iDjI`Q;G%yYmuJRi2 z9BT_(N@Jv-Dfkw4Y0=SiNtQZWP$&cx+Vi?TT^vmm<=;@-xh}+(E|j|ldSVX25k$Fl zNzLx!GH(r9F!5FI61W;;sj*DoM8Cg+3t=rb%8S33PcH&5(&s9un2D&5V0cjCWmA~* z2j}8)SThFzRPmwb_8>6P67O4Qd(;>`j*zV-vnt}n4s+p(>b=O8zhZ2Ov%~i9+$&V( zuGe;-`qc#?rBe-8PgCfMQQv?!mIv|f{9@!S`gFdDGJQPfcMsMp`25(|%c*Kt95Gk{ z@MG(d)j!$s;P@ycvOeqgRH3KGC(pR2M|}$>gy5J(xe37U%oxm zGJX@RNzKMhlGnW+HQI<9E+s8Pnqv9(IsiIn&>2h#B@p20P==e{)htngmN|34&cEXo zf$h!$>k^f~-yYE*!%lF|2QX+nqoy8VHlC}1VkE)S0EY-19qpvgu-jCQ6uF9+eOppl zx(@Nv8=Tve5pN}oN$2kB$N);`9{Hc-Rq5G&?h&g@U!$#Il97RF4;i6ji+O#PWGuTC znh`{1td5R!D<9ZKK8MCE|AFL>(uUE`%Q7PXRZ;amcfilqbFH|qseOq9+ zC7Y@G;inHNC)rVj`}8KpR-H9~8w8h{shG8E%7e{fH%x3i&ExFZk1wlV0iS;AISWpq z+S$@+Sk^kS@O$YbcX?eW?38VNYoQNy`z*m}hD8vrQ$*t^mp70<1Ea=UhrfiePN-=J zF~ld7ip8sF1LkAjTl{gHWM|d?u{m_;dq>3}lU_fd91zet!bXi|np;w+K3pg0YU-3W z$FUgRygchM_OfI8O}~I&pDJ*YU&R57u$Q=t_~O&<^$H|&Q=uU}#X&&5#XRXf8AxZS z;bXE3+zsb2aM1YuA#B)P@YemMfJn#M{o$p`E*3%l{HRkH4W?NPfr8_1z!p~{ zu`!O?M{5e;Is(I5XK2D{acJ13F8pA_FmFK#Hn{Kke%LW{MhC%yDzl?4d{yd;`_<{+ zXmICXrpm~KaFZ7_T zb}zeup4OwrXvjiZ==t$loIi$?sQ%T#{9%EL*isX)TQ|V-r_#QY)Og`f`lO|rS1Xc?|?bLAs>yf9#*k_46 zkw*LH>(-kNJi&<~tkCQ#k2Tz@NE{jbz#5FMhZ-22Ute9qBGyPJ?&B16QW&R!71C0i z$Vc6{vWdJr)X#etOOLTgy+ph(55vt-<8)FuvCt1sovcl+teWdTteS09wlyf+T3KvO z$*6SqjHP~H&mRLE!j{gi`x`Qx*CN6DBXrh@Ppf;XwG53uIzTI-%SuKLA=^n*$JU8{ z)rKvDj@0|}chGLQHX1rZxu~*%%CnSfe!DTE1ZmB;AL36uQ~WCE6ZLX|wI9WwWYsBt z=S-UG54y;^n}r`0743-|*ReHdB}*b$Gov~RRB3PxA=a^8O)}=2vm4NbQ(QOc;kNzL*;ey0!>k?YmW$c?X;(d$ATtM1dzd-7bDMAgE~$74@*;1w{V| zctV@4dY1_qPzUN;oikrpJ?lT+q8{4o-%#j{9(DVgTv z@LOThQF?+v0zToPLyCc;C{1APT_E0&=BGzuORo6JN!je{(OykxRF?(OAGv8r%Koox zG&dh^{G;H<=iAU3246DeO+v5j83u3TgjK{-6Jj&*nM1xqL4$P@sm!%|UPAheT`!3% zx2nn8ta1u3q5=#PGO4Rl-(O~+I=qK;`La~2>cjcvZ${NUuo%y&US4Uj8)qq6ubi!{ zuoh(TnzL@e7H#n98Aa6Z{t2DGDBsvj*jLTcMJx~2{Zu*$i&Dwl+1xP}!3S*Zj%K{q zx|lO39?zK)z@lAX`JDhoRqkDli=~Fs_vo-I29o+83`8wENSs&7q@Ox&y5lHGO$LB^ zYg3;OaXTwO2@;P}B zYI(d%XPj<@Hmmv5L<)*=^%-dMWAjTw%AxnqK4W8PJDP^Ou`c$^4t79a^5u#XyjI54 zu*_#JV{i=ab3@B?rI?u5TEcG36>KR`Z-KcNk?3jj%h(0%-g6AJg;03WZuM2Nf{6Tl zcM9nBvYQ!|+js;e+sKq3}om;rOSnJ9yhY1;- z&<2|_+~>=Mssik!Y*EZh_z|dOZK+Fd!tXBh(sXOqiTlRiG^H#fi=deh@3#1^Pu|L8 zzpFuKF8ewqrR#F6NDvsKih5od>lunx!C) zHFs#UX)Ub>2e$O%8RYhwQzlE_kOr6;HYM)6gw8oo{3(reKQ5ui=|BS z<5pjz*W+xxUwu-bNw=h6a=z~%9HFwDHoYdO+E~h@gJR!y#+Nyg787?9^0Nl-84@`P zIk?~l6?sQtkMhMGCHvsPqu6L zl$Dhz_D>fzj^N=O5znOWe2U;~D9Y*~4q)wlbcF~QiGpx}sCMdxe7Sih{R@k4-b}c= zD0Eb#_z9U@?}z6QSk!5EidF{*L#+7Xe)fx3lE1a>iYEY?Y1I z>Q%ocfO!BG8m}8OsHICUd~Lw9FJj~aPQK%Fh zc0k;kCdc>i)l#%NOA%I^T>Zl2rtppw2jP|62>FkdI8_jIKBpUGK-B4@%$V>a*)!X? z$S}~E+l1q@!1?g246q3Hk0qycvGiNzm@~yS!B?9hO)3Q$onKZNU^JOOyT71@z0+S2 z7Rr_$cIZaw#eyf;4W8WB+c~i#)~h+EQ~y=j)*+~4ERc%?jiA>+fonEFWRj;QEh+jJ zWZZL7Uw9IcW_MoFyGBogtC?63Z(sRUfN>r(>*%w8@Bb6jX7y}zwu$+esk-0 zkN=`P!yU#$KKDx}iM`X%?n!3dpkFG)@2Rf8E?&hIY`=A$!_QU1;l=ZnqTAM8pADXT zCH|SN#y(DQ;z zyfq~vSNE?YP#x#MzYhN5mPv|4JUPGpALRTe%ik~c()7XKQ3YK0=7!`a{Kzr5WU9(u zeamCQ>X@s{gqr&Q&P=>yxVrDv7iImI;f~AQpT3UgrHD_I9(Vp8h*FQg?CA4<*wOCa zFZGH1p`0nA&6sj9i}za#>ErZsccRpvTK_c=#Vq_@M!l5d!4<5jw0G@7UNEPBmdQ|8 z`1_@TTiE}0Zj2tWgr3)~Pvl81zfSx7_b56r1mgV%B%L)?c%@%Yos01Pb*kgrArgPT z)MG+<{9s(=n0`h+EhWG&wT0_!yAS>zMbo{%rj}6npQ-(4YX4ca|H@EbC7b?Pwf{Ke ze;o2v#QP`K{(l^6FM?T90YJaW%k`r;#F|3h0&>U4x_LIZrAlrYya=4WBm-T9GcAEm zXrKoH$jG7ha~2bUx39nnK5FZQw5$Y7E!0*mHM(HZfg6LeUQ_3D(|E;(PjaQG&Ye!< zamt)L9)(p?#QXn!$u#Q?H6;Ps-J=a;Mi~eF6VS6^;74IBp$6u@py0;<=oz4!-G#l8rqL`&NptSkaH>P__C=aiUN z#P4t6(N%)1Qu*KT=}#pdW*RBZ|KA^Q{crGlX{jp)hJ3{XPvO`2&lh%&AbtDynEhh7 z0YuL<-$roj#dgK~2)`)4!55Qa{)%wPB}sjDHc%MQdx$ z&+APM_%3U84!mO%_)Cb%m*S9|q7BU7)taE4n&}&3n0x2*5-FIb=Jfel=YYze(G$t8 z{8g(0p%lC}l^{eju92*634>3MxgWpua`8?nazINMGTJxWJN`)B zE6(}wlAuv1-@LlWUYJpJl1x6RwUfwkuOAp#Fh?2McqAO31BJ@$4ywuQ2b}e7Er2d{ zP2d3=geEbt#p|O{wlRobc!1#d1YE~eyr)yW&Gow&Wd*UdtsAz zti8t69EF|$K7Vglrl?y%k>JDfGjrWt&CGJ2`T6hOE3^tO+$6C%uXjo2lscnl7=Dwf zY;4a?=19GCJJDXt5!9$tbDb}uvsM#x+Rjp$!%I4h&Hp3m1m@rIeRNUmb>M|taBg0@ z+{xqfSUNxVs!K4rh^Ua#kC)O#TOh<~Bi~l_Mh6AkAGbaP=GziTGctUjuJqlMYcRI^ z2H9$i4PVf)`pVVU5}AKJ>j7TuR(C1RfT>TXsLrxqk^!)9(Ty;C8HgGLQ;Km8*v~;s znbZTHy{BH?2nnM(y>H0C<zFJkNA~YUvYebL2d+1gqUqwqMpJRc~OT2fBP;K z*Ao|TNR8+GbNTq)74Hkt=q(wj-u(C!Eu!)CyK9AYz#|8d{+fKfw?QsEuQrl(cC_)0 z`$8OI)0Fv!whKarF)7EwgXzIH)N*4|>Xy1xW`7>brtJE*ugz4Z{iS5(GJeOZyuia>kp@=pz&9q1-@SU@QK+mu)5va8*|4jbHg(x5+(fUZ z)Mqb!+WCfylG|bxHejNvDo2^btH#~Y7wlmh$YKXB^WF)WdG+?AYlHgX?XGBG#t9iX ztMWSsBi+Zb=t*0`*+e}_C(jJtXNr!gl@`Azo|E0@RM^Y*FgIsN%Gluo&rhfcI`M`T z%clA~q+ZD#ic356eU*|@eYN}o{$u&Q0Rp^_?a*8xq_bB^0Fth~E#htL?XpMKE5_b3 zxvBf6W)9)8Dd=6-9o=kZ1ALd+=#^dun3mN2qt3=V1Hxm1I%U~axV(XDGno=>o*CUoA-NN*O` z_&s^HnYBJ<*6D0a5M_|g4Ey877g9%ky99~)JjeYx{~ zi>frQAT3!`+_X=LLhXIND7xwZ(@Mix$1ajf)fW%>9F+i?O(#q{#SBr>+y%>FPPZ6U z>h0_kP}4C;4w$PFU?QL>ns?>s{#OCb52nnvrL6*nv&G$$-6COmFWr0@09D59wTtgu z3F5RI{z~dV@F$$PE>M{Ie_Bhe8(j8)@Ra@WGfOzWDe()D{Ys1vBg?d%5EyyyP>x+Y z`};k8gPl3Hc($6pb6=H5hRre->P9UBnWU1ug1;a1?e+GKKgK652hcQ} zm!>cpM!w-<;gJd*+6>Gd7vIIMUo@%Ei$1TnmBj16Yg7ND|F*Q<30A=``fTY3cFpGr z*g?}aTEV_=@W&d0LB703Y3fh9KKHu)vea|-XG7k1Ki(_;o#QgF=ZNb1a?v9XDK#zb zb*VzeFU4?a!_=v4xm)H__i_%?^$It3nVnuJjOIj_tNqbPzg%R(MdEkkGQq5hR)m?q z=eJspI~K%rg7=19Pi^}!s<(A%Bx^(IU$N$Ib1&>(@=;BHw~=Xy4~Q_s)kQEN+*D|O zb>%?r2oe=DB=Eg{^RYqk*QTyNBU)tj%M>j=qs6TNbExBCR@_BA#NssBGt++Uxbo;R zoneM3GIo@tam3CcR#JBEJYTpr;-D$W<<57APx;r>zQDezsQZQakhHKBdV^5^=|hwI zzI2SDctdvZYqV9v6|DW07&e)38?Ap!TngzBaMpy54(b^tPXUe5g?lIopQk7L-bNlz zOt^Tf zlSY_N-nL^_Q%hS?{+?!P`(udt7xMM;=_k^IFAN?racFnu({b=wTo|AfFDF68vD$uU zn&8M66CSiub3_ZRtMV(teyG}iq+0SPT6w@OePnLQ2}o5egC{nexFx2^N$B&#o1dCK zd_Iv=yk?Hi#i)q!f$wQR@#j^95nP$d=QluS8DAbe#XpX2eack8$~rE4m%u}_c-b+=Wy z&6Y39_mI2NhEt-haYeZSaIu4r&X;RAx3$}kyZV-+P0vMAlj1t;yA<{Tx;sHnEy~!6 z=|m$xx)aR#HfO6$)+xa)C#ZRaoLI(2Qv{48k6q=14|se!pGOvdH<0fRh;XguuP(0f z*;iURw&;xPjueMr*&%&P#e5(`)v05ddy{%DNcu~ZQ2y~%LMYO}D^ zDO+4S>n!X{yRiR)Ju%C5?J&dLEcKX`X0>xIcRFd8#LPb#A4XOhZu^c>-Pn85a(-%c1 zxvA3bN87UW=g0y)n)(?;SC&?}86Oy;X>O5#XdAFVf*KQy z8zjm)E#D>0Opnd74=vNMb!m2}b&i>t#Bj;mj?FRW)qTH4YIqfLd>&Ffx_$lCrx3B0 z>Fjj2#7gw0MT!fyvpJ57U^g=?Jc`FX0hwmZHuvpG7RRF`{yA5A4M$OSnz1x{5v>xP ziiUOdu~Se-Mn_SoH$%`rz+&UU?}XTaMh^=)eIE0dy1 zYA1nekKN)Nljpnzi;2)ae%2dt32A2UU(AAN&V1lq$x==(X=RceAKQ{-ej2pI2I$L+ zKKdLY_|TkM%-~)rN%wb>47sMl(?0c*yaYycMN8tBuhX#2QI(um*qg_uIWNM==(=BwFu?~QVr zxMY$|xi)L+@}Trhwt9%9H%55ER|U^9tM^d7eVla_J`PoF9hcEZH%oAy11KIoWaOHR zT=v(k@bic98J^Q2}lO|QP5fr)&X>8bhXOW5}8Hk_ zl2qWaC+37%&@npaq<$~w@*(n))JFD=!Qor${?nSn>~48l>(r=dGeScyn(@{>YP>HJ zoi-CDhCOVRm@el?OP7#l=TLv`I3HKU6x*^#=uJ!4DFY67{0d~rhEWb``L%S8UEwa? z4dlPonwmZ#ZDYMDO)|=O2V;WiY^I}>eMajWVR66EV7L4G-MM8{<1$ zUh{j6G)M9D{=zDOO}2^MNyNbix{_~n!$!PCC|}F>4w^D+T@r)lDXV7vwTmhQo$l>R zI`hjx#de*uk5yfsc7h3fM_WWmgPwi)^)7buA+Te;N%@H=LiG0b_e%xXBXyhG;YD}n zR&V?s1{0hmA6!PL6Sf~vHM);2-dr25^0&?d#AJ82b|RCCe;~CSUN{%*4P1*PxrIkC zzS&*32IF?4W$|`J>K%9f-Sgvn<*QL>&120ogzPxItl^n6rPNI9NI8~;Oj(mq8TYGlF?CGlIr*YTP z=$d(79>^|)d1^PrPGH&hN2^`GI`U0m4Mjx!0f?N5fYR(k3sKK;UICwciI5mXc(q&Z zP+FON_+Y1-{El0vRU%)ILy;EpNzlN4<*}!-_|%{4zy$j-SwxlGLd1cx*TmO{0VOs$ zDT~cE4pOC|!ZvmiZclh0YF8Oeb6gj*oaesrQMebMat9myk4Sor@+oo3gX8CKfHEr= zN+1~UQVBrAJ>-KGeB+*U{9Dvk73+=Y%kGo@?!MRm?Rl$#z?ZVN%s`ujkp$vg)cwWb z<=;P54T^160{gRJ?4Ol&HQe;V3cK{9gg?IJyFGp~_J&@8UY(H=Oj1mP0)60m%gPPE zB#7Vxjj4Te)mQ_hQ-MBc9IP=n4l{w{d;zZ4-tNeX))Ux?e=$x!$eF(>*m(TSxUSGW zK5QKMVyV)cJLVgNcaR~NmRjSvLElLxF?GV5dS05g6M^9G`&BE>LQeEYpG7fMOm7IN z!{}%R;)$b248>!zETu?)R%c0(^2c|*CXf4(7HIpmU-4gi0puWM&kNk+ZL^~UBA4t1 ztm7c%Gp-}E&5y?|c0<3oYEDRO1LHb|pYimlzJZjyNM80`BLcMc{Z)I+=8~!W9!RLC zw)*1Ai?PwX)Jt2L`cOYu-YGMU79oakHSA5Tx9KN|J`RumC}2QePn^U4fCn5t{;W1# zMkc~2zqkZe9N0!MQ*tm-L+$Yq6x+SAAUusfhrz!$hr|7IA|~&_wiIjiG}CV6(peVH z;=Jww7+!GM7BFFsL(pVRlv8uAKlFb{Q_R%el}{FTB43|=hPAU=a^6R$3Ilh@dTDNi z+Hh&^r(}dlma=V>vX?y4bzSZK&UI|*!Lja5zj({+1u)Zt17*?~jmbWB$l&EES7$dP zyrVElJDMiGOti7=Ts=ynva-NB~~1*lBdo>)89WQJwiQde!|d^ z`kIu{QqzT;tI6701uZk}sQO0`54N?2{|#)vr2iM#MuGMdu*T@wZ*2izO*6u>^)0nf zZ#g-tp4N-BY9=TQM-9B$#Wb z|BW>72iEKHI(-u=Pl9#Y-k0fGhF!VSM zlN&XvrqtEL1uX2IR0Fnl6*?DguU8o9#vCqEi)H|*`Nj=7w*o%L_L@FqnB~DfXAa0% zE(vn|_L8_gih?cV(^!G4b8ooFy!reeiJ&aL0QZX(g)ZWU>$C&)s>}l46ULOJ9*lf1 z>PkPW;!c!-o19;sRBkltud=@1CR#_n12-;FGH3TrCvRJJU*0nx9pG%|H_wjHOSo%> z@ETqXi;|vr{TaGU$oDrVYY7*0-KQ{>4kuX1mdQzr+|~SChTos*LgRjW$k}yy_Nnz- zn=DIehdLV}+U|^&JqnlnzP2#S@2>B^6ZP-fNu^^R^A1cpJ}7)rGS%qU8JtVDpYzoX zbRss>#pCYYU^rVOUdoa{_6)(aFS4u28=Q{QsS+!4X?%OnoK>u~@Ir?;`&DnPYS>8I zwD&W?m+9Y(f|CowLN~nHcDWulxLLZMs8ONeTlfd7x`;B*WS15 zjivL{t|q`%{`y)*M9}(FWx*mz0ItqSs)%dKuzIm2XTtQcd*J(=mjEr{60Q*bhxNEt z_FKEI-};#`GaShM!;FqgUrB!Pg_GRWwyuGznxPl}=D_Z{l8bO`+kQnYN(A_u;h7tx z^6OKf>+#RydtxoB&1$34^&;xZ6=M4M&mQItlrMduZfAbi^SP-eju7NLbpd1jcfvS*t*rXn(yYC-Z ztJmzBbB-EgRMpE3{Lw(HOi z2Y98daC=XGZs>bu4@fsBn>BxEZONWymu_u)H(*R`9t}T?*6;Uk+t=@JGiwZjs+ht5 z%ITChWENXa{^oQ*$A9N^kt=a_r<~d*r(4hoWZSH19L=7U4Lq+2Ba&Zj8l&jl*+(ud&vj3 ziA01MKg}N|oW7r|r*z5^*B5p6{vtUG&i5TjQIb!Cfqi4=Qwl$cOwZY1QV0JNv zz5BOib`}-V+$fSeuf1y{zwxb^7leGlb{P~@N>Pd2s8!Z=I)1~Q?rS>L|Et{tbOHPB z+{HKEaFN=HV}YZ&wK}MHo^ekN+Y_~grsRGRrU(M$recwTi*9cMyXQ4sFCN`%*K;~L zw9gDDDt~P7)BcqDt%b4diK>NDJK(e7EFiu<_|FqID#m-(Y1^KyzWzug;@`x6_%_cH z{i$0Fk^!Qq)aQ4NgLKz0-wWY;)sYB1U=(P46U+y`Lhs}SDnEg=dQYqfcOp%^WZNy_q9(CVSZ(GPp#v6RU;_dcicF-^F=}Uqqkhpy! z>+3D2QS)E?ISPfVbcRKvZyx?w;cIfs1RmL3HvLu}kQ}6EX-9j_*A2s^C>uueOG9W% zaM&mCu_d3{uNJ`OA2ntDF%>7GbtNP_vf(Ti)B;R-_HNiOq_3-h?^L+uFzCPe=~slC zRQ76a{AK#h#u3xQHuq-iO-Hj<{xXr(x&5fH-TU9>r~+1=Obb* z6Zd-))m>|-;;!i9O_aqa(j_!#w|oH2m#v)b5TbD}O!kQH!+7=VMpK2$WC5%;)d()X z_ku5rLi{dY^9;l*j0q4yUV8_fWE!@a8FA%_RXQ6%W*x7QYxq23d45-J5V>HQpo0 zS6ucKfQD*(-;EM=h}Q6`5PKl1>udf}-UAV2`d9un$N@4SwTw2}qNJ#a{$-sGmG%oVIR$+Wr5$Bd z!@o~VM(rCAL5X!&=zaL7$Y{uiLBNJ9(l{+7U1F@|EU7{P*!QZ{Yr(I##RM&4$sZ&8 zxt`xpxEAlhmO3ObM-Rg<NcvQjP5E5R(0QZ`7>7odD=b)hQqts)O^n@hmw zaXvf2Pa3WloqV$81zQlmine4-V(?#A>?J1+FYfEmf6##6>f|JpIc|h5`#m&1YI8^KEI+kA#N=-+y|` z-_T4EgvfJ5Ie%&sT{8N45936w#AimIza;wZ4EuvPE{8VEe-j<(Ko-*JFMghqize2) zPLExX@4u*Z{zsJC`#eQq(n*%pJ}c1y)^hbJ7Q9I$Nr5$JkNilTz;^rVTyxoZqyXG* zi_%c6O@jtZ=*HU}_8=Hgx8&HWTd>~=ve&qnI$!UpJJ;GQ>6-YX@#k{$YVGz)co`RE zAMUaJQPILo+Rb@i$Mt55II^=G2wQP7ZQPQ7mS5cr(i4Db<1N-aZPQT}YNJ;PEA2_~ zxPFD$zK>>$%H1FvF>)+#+1Phnf=?t?M=a(*9DoBYl;OYeqidLUb5B)s3Q}aJHM+eN za&Wzp+bh%XqW#nfiWHB~caIX8u9#yhGWf4|xi}~pLaxAle|E1wgjC_B9YDWzeHnZD zLqpA5yH_L`mc15#{mI(SfN43m^WkP94z4a`iao6}X8$XhwApzixl}lB84Qh!tU&^i z$0V82!&YKPL5Y-m>yV5m?lo?`8rOS@fYOro5_+VD>#sGN^5iACa!{CKGUsOHoDmDr zM;!2?$2*^Mpl$OFXy8EYgIW+M_W|}fBK+I%lMp{c&IgLv#p(iK|MC`;kIrd+hmLwZ z_WPotdI?n;NY6EQ?6~lW3H^`s$CqsU~}Nl$#S`R zi!NevOz&o#J~!gp#nC2U^nVSs{B)x_#IqdoPm*EeN6axv*84KqfW!iYn=x3TgR3^R zzg$mf@ScIsqP%HbM6Zw$x#vTZ1H!9P$?BWj$4bwbD{lL(0-dU?F&JIXnl6Dr1@vvk z%Fg8MQsLR4%lVaYuTfq*&Yh@mHE_z48uN=L*0+3-5v(O#7Irz9L!Y9N_1V$slE<6} zB|e7*`7C$ID{A{~A2FjWDgMsZT~8CN-3+!{g|Gw}Rlz~al@I+Ay;It{SzlQ%eQS|(qD3;bJ z2;$6cBN&9hnhj#oiCn&Cw-|jLs_>x2GG|xY4)@8wA@Vy=&9lvQ?a~=S{(XKXWSHbUQUZoVsNb z!8hRGV^Tn48O#S`6ZPv+P!8I|hye?g7!VAHqL)w$%HN=q-o7&Wx096=$b&|9I0Ndo z-Cx}`l}+|)$!Mst83IGibDm(I%M|>27X5|*ObH3VUf@5wv_nZ)^^apQSFV^_2b#>Gnv9LC)mPBc`W%13S$X*2!K!E4mL00x*F0cuQZ{p!P3r9{#iS z9H>YkmL6FM3RoqZ-7&S$#p~cNL!t8@0lw(H-t9bmo=ZSx`Dms2Iorl{S`TZiL8>4LljVJycabev1-jLiZc~OH^JS1~kVa9OB zNr(7}cVF#Yq8_@7vL)cGTHx`Z5YtgZK7&L7ddm&F^+uCttJn?nG=6?VfM9+zJNl@1xsUY5HWC5u4 z-s8q(@Q=7Tx0oA#hAhVKpU&R>O~3!v_WvLE;{KtU5y8u~Gl8M8)VgQW?Dr|(XtE!`k8zi4~ zmmb1)>s3YCjgK3$HXu_>AsZSDke-IC4Fa~-*smnq_G%TZ(|~~L`RYOD1L?R?le9Y9 z`!%LPgmWOaKFB69Y&8Qh^rpV5?dqCi`H^JcjeGhtM-I>0Z8Yq>SZ*PLRstSmRG27Sro1(BmWOQnYB*>j{i#~mZVHy1UPZ7emlt|Bt?u0J(D@) z>L^HtP+xSeGcGL*I%nyX;B6M;N%5@5b*A;^XVW;2zxU?gl8cL|l*=LJuDb`h7(mC| zcc=jA4Qe$*)`=yZ85F|N(qCLD`F&M_@R2xQUFpA^iXC>j-`&Up)d$fSF?*G-5S9U^ zl9A3o~Fs%afZrOgUmupu|+dz= zZ=r4E$gL}yv;ng$cYA32MpsKIInjNJ>jmQ%SO&U2==wMYd_^AiX*aAOVav>FLrD3t zQGM^tx-f}5U2R=-oS$mtnTYb3PFjgE2_s;jX%jinEh`0xC*ZfLwrR!79(qoy#pp}_ zd}VFdw%Hrgq!SJM-GpRLhFE$gcw_R9)0^z4X~{8q1>a-=u4+met6@a2UfSjnF&0`? zZd=``*b^#97O5XwV?j+cRFJ*5|9m_)v!nX#sj}EVTjQQ=D+P$FS8Z_E?$^9A`zqI^ zJDuP0Y2hz4W#3``A10jt$>>AwwVxF-od+T{89shm911IL>bhKV- z5VPEt(Uv3O8@Vk(qb4C8*v2PFM;bi3XGYss%Jv1Bo3rAj|p^SnD%+^0+k z=TL<#p62-oQDKs9B=|QkzxqP_9$)oSu}>?@%J}n&Y7L?s3lUpYe0r!2R+v6$(Pbc# z*BB29p0Wl1v+7V4Np$jKSNnwD9seVO;8Ihnchot8CMuy|8dlraq0(##;pCtv{xxjO ztx!-i`0gk3)yDyh9laL;*Mr46tYh?RGviLq+iW$FQP$u35J*NFa6KDO3%VXKPVlsr zE%Ob7#EP!1Gk{#3pPk0Dxb}1@t~b1>G-vepIe}!;lLl}Lnfw1itsbiRxN2|P82MLS z+wtm~-x2}QBLVu7^YGm@??q+_sn@iTv7^Ex^zm6i&_B3qsaJfKtujvT?J4)gp-IV$ z;9)CLGObZhyYM_b{D9tuLVDwuEP`D4OKe4Zm#iIc_v3Q8!ssJ$?1MkYwq};EbQ2I zRm^&K8^rSeqDEJxz;@OH%TvmlFLxphP>q;Ls-ho#~*pG-a!H z27(FS9Rf$iWD2Ex&5=%jrN{x9{O#`y*|C6&bs7SxTe0oANXml-44L(H4PdYN+W+!7 z!6laO`nb93&2D)$sG?&oY4Y1Qo*bGoDTe;$ylOEW*1e-8UB zgC%Sl4%~o`1qY4fIl@JvrNhtuVNP5AmptH#0p)j$Qo>d|tXP{Ev*C=^yQ4Y=(dRRh zZQ0II_j#^*o&UYe3I;#zCx@Yfd?J50UV|H1?H)vl&5sysylfNcF~jVyXHf8e9#?^g zrb&T0NVcch>XpvV$mgG868Aq0*5`5SG4L=kb}C1&MIE8M3cpL06PnFJmR(ddZ(hZs zGbdYOY;qdB>)fXIcDv9knY-{q?-t!q9alHHkP5x$N8`0=E0;?H3lNM*u$QGF8N~Uf zz4hBN50-xPR~Fnb*xWfZz*&Fr)Aaq*SXZ?<6Wet1E1v({gtH`3!Rvc;IBHB08Q){S z&dg_0fs??WkVQqznHsse*uwx7_>AIJgO0VRYxEg(`eyMqeY$M6aK$G;)KgbKY7z5R z31os*H$X#pvq3)6dy1NNveX{qs7S$uXD`zZ=uqOf%n9;mULKf!y^L}gna zSm9<6e>*ROTqEP?>}Q$Wl&xB zhYg2>bv;A9nsAS!sC6DuZwLm=K=#W2A?BgCg?Io9`}jKIbW*eo_UtoKyXW2dLVY?y z`{0lgka}wVmI%VXwYhZW#x}>3NL0i-IT&`x7D35$SJSz$`*0IDHMd#fEynXxY^&s! z<340_aKYF=^w~1&Pg`J&(9Xq-`t&*sWI$~kox?3h?rQK=+A7a^DzC>sMdyLw^~QT5 zHVO>B<{7kLOy4DzGjG-8!7bWAT6f*e*Alo4QHJYIN8~q}X`#YP+J7NdYYa+Ei1?r+ zxeA=(!joU}*}FPiU4N>0$?HY6R<=>VWp(||^w=l#Ioi)maX67G%*D1$?x%y~?)Sk= zc>9JWE)cD#P$k|b_r@F0Hb34m9>o>+J^MyG9UcRppzO_+aoT&ow**mt+Lh=(sy527 zqc-|4b%Hp@d9v$xwDVeNF$1kEX;8~ASyu`lqPSKuFz4P)T7L*n)G97fu}}lU%~lnqLUf^cCby$! zHZx1S{0iXt`W#=|Nf z7I`9!u14j3)f|&0)w*;l!*-W{I?YaI&g2t!Q_k;6eKsde>3rVE?*KR7Fb7T(z21T| z`N7)^*UZP2l?rtT%5R=~DtvQ^GCsu5+f7S#CWcAa_xeuF;T;29O$Hj!!_bb2{UuC; zYvZv<@85uox*E1fwaXOpzu#=RU`g)2*-Mk|e!}6^j!rBba%yKE7YYFVBK)Y)F%EE% z-12{DnnqJrkFClqlp&_D7Z7x$F?(pywKI6i1e)2j@{EpV9Q(0^yKlEV(y=uRm)eU?Z2xxTa{KUu1Cbm~iW2{g7^T0UoD4FC zVm)f}tly+D)VIj^`80)YNSeq^4;#jJJw0jmnw?*=rxJ5OCeGca#6hu?Tz9nfs)ao@ zjhSPIr&SX*L74Uxjj}gKIJ=CnOplFhJ^R^Ksmd>yP==MI zt%YM^B7HJ}Xp&mw3r$~VF_HCI8nHUFR_mn0EDv=k}iKQz7BS_ z`yRWXo3_k(*zSXJtBWD!9D&5u{On%qwR@o1mYMl|3v>!|ys>JLDOG=>c(CKSS}l6C z7J@15>Bj)%j8$l@gD3ti)#|U(1CEX=Cy3bP1)Irbi4N6#^I&rp=k>lDpN&7FKZ!#u zmq#}mA6uBYlIkW0hbPxm#PWk~)tgJL{L~VVRvAeJHgdb4v$u0TyR^~@GZRRU+Yh!6#dGW zdGNg4-LO^jLADgajt$ge5jf*W*|^=@%h~Qb6EG$rbo-DZdR));er^&|e>n)HmAP^1 zT+5Alit;~Gsi)ZuH6AaE94}JF8(G8ga#3u_^_+)z_VMZQi!NB?4G#Oi7j9;p7{rK) zFmKnUP3^zo3){e#0Ws&8$e~~q*C0^_CoTgjTygsC0Thcb!dE`wq>OG0O z>pA zt)kDFhFairP=F~6u<485U;ViuUaBj>775J*J~1!q>qo7y$T-8h^R|;W?$JANw@1rb z^2}1pRPf~h_Q>D93~-2r_%ELXp=2`LR;&lfXy{kc`DlSgGqlrY(4>UIO}B}=4!w32 zz;h`>Sh{#h7?fxNv+<7@>7OiZF<YR6`_Y`C#Dra|co_a`YlW@`sSD>n0g>oX9slOmDA2$f`r z@kM_w~3kRjn=pAl%u%#SXPF zGA{2LRE$6#=r<8_c=~>%;q>;HlVOo};{!@GHw_}YG(4t)`Ty;`spP`ZFy4Fgo!X1( zcFUc2+YQ3L{919$x{Wr{%v4!mtXciL0q6rWqS-9cbYb)3ywOl`c~j|p#5N#;#EXN&9w=+EN`1ls7t%@i9m{uIwj%3mRTQOOCp0RLsQ=fWyfKKKI3=2qJSt=bDvTTXY0S3r`K!LK7xq2jPyC9pKjv*>=!MO9LS* z_~FFEi1V|zX4WM3b=h7OPZ&^2*d93EGj~YV?XO@rt}m9c>*suAdpZACGYt4onqg;@ zxC`H zNJ-2v`0ykH4e<0KiiO2t<@vhUijpywG zQoA^J`*R+57HaloS-13lVHJ-c6I+YOr-ZKW#tAT1E8M>dfy8k+ua4RS9rtf>1;~-n zYBp%58$w)MrXuRj6`XWR)oPs8bF%+_UTbDSuGB>)_(r`~k9azc&77pOsr`>r4e59y zv%3EzzwZH--n?5?iaXdi4T&`9j%)JqP_l2>(@>~!3y0U)C_*X_f-OK#F>Jj&lCTDD zt$}XWCa~C$H4S#+kf1LEsJ@b{vR!xwiXaBO=VE`-%k>6IpO3UicA(!)-mcTL-QZgo zi}Un9{`qi+A^evm_5DvQsn6{Zyd^iNitR`t!7_a$iEXJ3YPwkg?Y5$^)W2!@Oi`(q zi@fK0QpI3Iw?3rVOOVP+q|2|@#Ae$1MCwY!9D%>fK~9$BPPCJi{_qD2wb86&zVySg zPT4~Z=rq^0MzJxGZtd;!R+M%hkJZuL*sbqpwoL(WvKr5fZcTR_Z z52tIsL@e>o!xk*@+>S>21|*b>xLlICw+@H5n*5IifQI{ZRE8SL%m!6a|#%Cjeh|X4V(dD}pI@kgB5aK`1m%N0wCc(WTx};Zj-f zwEJ)8Abg|bn8R4OKZ1PkFN|lME8g)QI~3My2Y;1X|G20%e`<2&_J*!Z{(eoRKCAI( z&5;^%Rc6stWL>cIiR(R0^-SYv>ij-S%xaN-OP&(v=+48hhu4o6qSwd{9H(Ap7j0LR zhEF!Zn`m*FBgRT4xeaU}rI+;PdZ)dqk&V7OP4^%bBW5uwNstWw?Bf?#EgKypOn<&j zE`uJk?8%X4SMBR<<8;#K)#2eH(dz{lu|MkBz#x7b_SIQNQ%Z0B8UH$CA}q>;JW|MK?Unl4bK1@LZo#K)U;b)zcLj zOn;?Ea)KUO9^kvMf1L?DVW9uS99RLBs_VzW8kjP+Xik=`y!ptsG`-Aav409B>YYP} z(i@4BPnvH_PfvN9o+6D>fk-w7mh z;O?kd5C+Ac@0k0L45gjJIr-nVPP6~6?fds6lyBFsFg^Z4f5OA*e**6dYB;_#E`f)( z0*})ywzSi%mQ2@BY<(;ZC3|{W>J>;D``ra2bJUL;80R{*@(k?l657^l4-fs=LPcwS z6&YJ)-M?~|tgFF`1TN{%spUFkT7y;795k5k=>$8sC>l{mk0lreJ4D}LqzEOMPm@5H+egGGR$K^ zw5*L6ruo$1+1ahSxt{ZK7hNbRAhHfM#?-%$*XsZ^UQ}$83WZfHn*k<`*mfs~>$CBR zf?mPT#~YsDwAfM69t(7CkiE`w2#5`t;m&OZux_L$f?X1s*&X4;`M052{(o}dueI+v zx%wY!JM@Thg{(sd5Z5Y$8iZE)yQ6 z3~QMs)-m!cn@W9ELM}UdkE85m7i~ya|6|#z-tcoJ!#>2mZuwJX=R|#QG{GzXIhZjd zieLgR=5pMB>)9%~6O{ZB`OkyE@&JTw6{n79dT>CKyfQLV(={Wfu^6IPxFK1nhfFr8 zNsfq6Y0_rVzxUn2$vVZCk}R4n<1!EpFIe{Y zDjD;RSb%~14=V}L8v_Tbj@s5|+=swF_=q0)K4vym#g7Zp&`+-Uzzsk$l8X}Q^e|w@_89N(~qHK8R_t^Mr-Pxs{GZ$uPYgWS$}JP8Yif2Cg$4S|`YWo}FME zM7b~=`!eJ0pf+j81j+&!sLY$okE!XLiM`WmKxhZaL&jD?esrPObs{e5@@p%}xtb zk2^v3lbrrTKHq^W_G;83B7J&wKfq;J;z_&{>Lc&~ub_mn_pl$SR>hK)E~4EA-3-qc z11v995M!DVep!?AJu5zlF9nY*9PyDK+5F@{l*R}q;-5E`G{(*f{8R0sj9%5`N}2ig zT_ig%J9*f&_=KF4_xLR+A~Slh9?R({(OOyYKUoQi8 z9UI}r=XeLQ)H|d+<)UO3U#pQsVzg%EN@}ph%0j6D*veL>-cUkmTr>NVnG`!(9yOnA z!g{0@{~|Cy@kV}5X6CYUkPbyixBIQ%87ys#W{yrH7Z8keOwdVr7kv4`y&C)#ByI{n zvUt&cKsTH2=$GF3OLe(Snmv7ws8tiP-Pi>wXC5^;L!ErvO@86?}9gb%##)!N+ zt^Dfak>$H|^0eJ24ZDrAIm(~#OD^0Fd~wpATZHzM+ahc!}jA2(ZHA`F<=4~~^rSC5Hc7wqeXF2nGk0%cAT>*JPs6s@IV z16%DW!_ovp59pmh&y|$a%?4FYqzjqA_4nuED(@qgMjZ6uaEF^sh~{z<&xCUpwIiF5 z1B>bWulV=Y`FerA|jt#nax?l(?C=Xk@S{;w$X5Wd0njvsUB!W&YcF zZhM1wbGRoo!{)&Aer ztcWQ8E*M(F;=;MIgDm=OUDu)PC0eB0r;l?7+(hsuakkPAK~H0p0_(`)c- zk;<@U%8KkCx-S*!Gj>_>C;pNqvrM$^tkq;qJYD2r^{O`vqIlnwt#WXk?wepOg~`^& zH2J)93a_9+3JSssqItOXhf{Ean&(&H}1;^c1o?oW_N2 zNX;{YBwK=G%*rSjnImMx1|~vtC5lB(h3G#KKvG$7*|!Lz|I`J|fof??M&L>Hz-iHs zO(etHA5HXXlX9e9Uhm3w;L?WXzJM!w(jk~=u%eo$8ub{Ug1J1ZF+G2b_*`{$(6aI3 z_61*zEt;iwU;FLv^MLS(b?SHA&!hZT_S-IQqg$p5op7eU{r>^GIE^c-6-EiN@AJB< z3&r%bEx;%?EccQoq>Wj*mSdrN7cKQ_P!wO8pdKFvqYj1}6E@TWw6dUUPT$u=2 z$5T?RjW&B(P@OV7_1{c_O_49g@N7)IGu_IL*)RE?@Y!{LYXR{mf*wfE)vqK;5gxCJ z)CdPm-MRP!Pio3WCtPe@2K7yhovx%5D;|fjv`H&;bojcclx&*g(7vO+^g8}1F^!{~ zo-8rKZl(};7BhSrdfDpp*Ci*|{i9b))l8%GPwXKNdxREGiAa5B>fmC0ud9NAxk1P3 zr)h1B#ZVFsiz%m|I<&;;M}p){{ZrD?C(Qj6xGFH%QXV3=6ksGs@w-^u6FBp?ZiA>$ zGP#rj4!Hg?gX=)z(`#72AXBg^$W7*|fJ2Yq1tp%*awtO*%W_w3sc(Y$h#elo;Amn~ zS&8A5Y2*cTUSDpGia?#uBT*Dj-)?MQ$wCq>VknA003E+%uj_LWy+dlS4NX4zFfOU- z(!MFfk$0en(OcFA1i7Jnzsq;<>dEYvRv)(ll)VRd8Eokt%^(2ufWdaZ78th9{Yj9i zN{Yk9lox5TVxX>lMQX&8@w=bL(5ek$hdJ81b6=`2p|qR_QY(5$t?DDu#Wi3SwKz7{ zEb<)c5D_Lck$SEx{`?Q6#?yo=rN)`iCB{qMYisUkv|GZhg1aHZjC0ke{SLQH3#Ro` ztjB=?SmB;j7bmyGu>i$K<@8EzFA7Yf1tbu=!9zrkV9BZN(7bsXZS-GFDDhu4vc7d~>@nse9o+IlOl-;9V=o8bL5Ozr*XGax&NY?|X-a7v323X)N>pL$h0!_hvt9E<=}H zs>$*VR?Q&9VhL^dj581I6lr=ieP;1)79#;sr1@`aiiiZa=Jo&Ty>bdo#O~rKC$>Ym zCemV!C0QrZhy6~`lGOdkKxx4Tv4WC$$TtcrHcXp!hY$&A1ze+ zlUlyW)+yxQ+4YxE0IQC6rNn5D)X07mQe2wEBDuo4Bb4&SU$#$xF=vVuN4{UxIIKlc zOEILgHK5FjNr#i8n39csVHik{d*9F12R^_94Iyp&Uj-c#Ch#t-*ng>fC$&kqe{sRD z@NwC)XHlIDZzXZg?XV9`GWM|#054n`3#Io<1scYOw3=LPer|SjI}dp@-nRd2Drtw& zbd`vuSV`Agz!~2VQ2NPXW? zXW^!$rP&(^Pr~7`nlMo4@oMI2Ipg4|g`tlTD%M{{6kU`ZP&MgVvcQ5| zS)({grpjhIiYXZckyHrPkWezMFPT%a_d18Gug)_atBbKudmRYD-LCi3{G5JB=5d&y z8pp+Fj;xFWmT}XnedvnuhC3|9d5_@G6z}75jW_n3Td^rF``g44m9|yrDr={oM#nMo z4>2i>54K`mIrQw;tg#!3&PKQs=21F&qv(C;0BmdST_u3=eK*Jcr(e1u_f# z-UF)RKkxB%FBqkSMlC4s@;R%E72Lg6rX2!aMa>8(qRDi~_$#zyT{~NVsZ65P$3X*{MN-Qg4Aq$V#{vchU`pADK)SRgiCVHvBmm3lDtHkFA!~ddH{V%nZ(8@p8X!}o9uRn|aq&VfTtv(FN2N%w`CQc3DNut9_cq*?F^W)+* zH)CHLKeq5f@~&5V-Gtv?1?5{fj63!yMF;iYBpu;7;OLf@Au;J@A7gaZv@xvaO;tv3 zzty}_7!*&ua%3@MjrqbjiDs>bhkiqyE?h^c6U5%{##tNgd3-$Zz!zb*euGNo_|E2DUSW*Z z7ssrfXBL3X?=m*uL(gtmGB^6K@Hy0~GkJzu{|o@&)n$HL!?X3et)>aMqkjF!5MZ;1 z)JUrzgr`Kbky3r7KnSg*W4cbw5$bEf(J~~M}-*fz+zl7oD^`l$0T2=8Hc_McF z%AvhBSj?5J?2GWEOMT$fJYeE|jR!b-Vftg|PT~H|TDy~;Us~VBmxP5rr@SbZVlY#+?cEwUN)GtAs%~*w6*Pb z){F=eoHFh21MExg`4o#W_6$PxH7Y-{Kbev~0^5z`?LN|qURtaCdW&e|t-_VG`nj6N zfcSy^($Vi$WgaVg|4kH3Bbz|51aHPf3PHE3)Ni`wVXK_j(t zx>{N@RTLgmfe^J1Clob2u7X812z_sLn^zPkgRri4GuIt?=g=wP2U4hm?KnCh zC)i%#yllt*kfUQlTjxn4+UX@C)8K@R7`44T#|fh={CC z0sAAnu?^iI7EjeHUJF>1FHs}rF8@5BjO;pkjZs78 zkC9Rkx$pL>>lQ?E*f7g6w;}OOqafrS#|~NIg9m}7sRgBSz7R}((0s)gwqHpNbJg$o z6=+d?F^)nKissd9#j6Oj!4AvlV~QRJ>lc-$rr%<2XuV>n7UQ;yYP(N9toh#Z_|^!H z1jH)9-lYa#COU)JSe?@Ygb*JQ%~D(orzw%#D`vJ-eu!jBdCERUL5v}dU#?{?S5zqgK8IpeNLr}P zozg-xG0*Par)^po@EmF+)p(3u{?9Sv3s}fuw{N5M{M+j{@?U>)pNk}mobAjVz1{v< zli?}=<&+^@X7U?GFz*h^`!1kgoc(TRdWGjz7#E|ENAUDY>Fyl#qhE||lXs}Cy09+! zhs9)6{t)Hmpy1g3xg!)13QP;YK{mMEUC2)&_YGVeWl6ygtocWHaBT~D;K6S^CUzO7Lw>Z5`BT2P zs;(Z-=F-LnAy7JW;4ZcgEhI(jA+hcu{Z)Im*g~~`d}CSaXtnl*TY1y7WCoQeZg>LIg_^m$AriFfkaM*|XJo}qDH zzNAt+-p(vUC>{k51eR`O7`j?C8Ox6<9sVlHT(VLP#)(OtxOp}0DYe}O>5>1G%Y-Z2 z>-!VIQXrNGWB$0L33+UUkQ2(OTEY@vBVT7|X;)wKTE~xVA9b_hBm*c&aEXj1 zd)Kpmz_#;-;bk_{MaYjRu;4nNt0BmY?$AA01-|mLxM?Lw55MR)I_R=|GIf?l(T|#G z`A!V8+aI=f6nhq9Ya~Ntr@v+Y$frGxE<5_9Z=HFq3UON;Ql9-Ow#pv8+mJ=!IKMt4 zaD1k41Hy3sp>$Jf9K?mPeDjTT_>Ca~n~&jEU#?_dSN9aR4u{k+j{k?nP8QrSvHSUS zya~Jrsb7z>I!8>=5*gJJ>PT|nGLyK(Y+W|@R~gfzL`ot%g$=Yb&2;M5+0%+=ddhf) zl2zAercnt!4EtjOfg#gY=48;IO5En*6WJ%c8#>*0Ab-T0+>R%ft?cu%BL+YmhqZ`( zu=yj&QAr)iZdAvT(f{8I;K$y42cPHE_D7fLkL~!E?W?`V4?Yhi4t~5ph7ZEoNxvvp z@i@1yhbH`xcp;@u>Y@3#F8IwmQ7mMk1pi9FC8=Wt^*iPF*KhXfGdq5)`m>|#t^V4e zF-;FRw)z=i2HlkhIPGyfG#SrB-Mlb1aYNs%x&8Tuf#RrbL8NSP#eGA7ZZB%s*Ei@6 z!()~8@^fnsOM(U9clo|%Sl&mZOMGs-Y4$wWJ)L{plum@4U2)G6LUuYRHq|t~%crtQ zYaVNz&I)&G`s|;jRPR`8@i+N^#{cvUD(y4qn1fZJ(#i#M4`{Z5clOIMs?zrF*^Kw2Pav}Mu zl!m!hzMhALjPmax$JCm5teZ-6YE2)cM%~)uBbp<7s}u7^NH-^;Ly&J>4uFN7Sk0^| zdMR~Y5?MbyF>3Bjd~cN7 z$-X)4m0J*IrSAjeu!p3aL%qsZqT-l!3=`Z)NQxn-rk{+}A&Wc$k@ z3*7QwF{B}*Dm+%CddM@K2=0;9OP{F8nu7B8fch#QkV1MyMf83emw=W|VR|L4fqh~&? zlppZj{+^6}l6p(rB<0Ma@5YI-*0PEF9$^%`tMVDyg1-!BI~qHTOZs?{H*8x;=k-$43`=l=Z1 zKuUIgKGW8s3)Hhl$zI;9OR_WdNhUW{mWBURDH7PAg&k!{g(#6M>^0l6CQ4K0z6kjs=J3 zh3>qw?udkmt4`2vn`I;K??)2(5Q<2kV)c=x`*-*y_w^bw*39#q=UIDg>OSD)UE9>f z{&r>|&LQ;F__+UpyC`YX-Oi(@!UM`NE`JKn-)ZSYIr)a^cYf;IULR3C7`HT~B1}+C zz2XD~+Nn@Bc9CzuCGPy_P+|#7O9iHj`=f#RHvJa5EDzxzv=?rKC4C+S$+`dq#bUfu2$XWHlt<#C|w@~)E$V%V(jEsIoH4!udRLDPdeWxl+>WBtD z6bU>=Mh|(PY@q&JHIoivA?`r_z`i3~(u4N4J>0!1Wm+KK&3)zoNQWHD3 zwHp{vDb=-XBEXH*)FA7WY?R}CPc4L(8Otueu5@J8@rWUC-Y%AR{X37LA`|NU^y3{y zQ&ct15l9M4cKK$yhj%|Y(X3#?xbB)Q|5IAa?AMjv|8=JYU-}`-&_HSFvN)z#l?5lJ z18NjMek=xXLy^PMjT)xYjpDK7k=zg6+9E5D44j<8JRqh+%c@=}5*Y?2gUg$;vE1y^ z$C4avo5ABeZ;n6TQ|#sz6n;hZf6NxB?i$D3)3*8yNJGXqm|^fC*^t6;)E^95jXo~@ zG6s$xK-6chfBi7W>G{j&e)Do(q8a0)dh#MqKHsZ<4>FW`Z30Z8HX9r z|Hs!`g|*d1U8AK?w75%v;*GQa}F51D6VO4Do_wOYK|?x z#?p58av+dWxJ!Ky=@6_HdpM@;oKul8uU(Zavf*fDzn&N%3}!}i1~p`hHm<!?_8NJsHslW;RFFX+sNTZe`L`yo zhSr(oJSu;%zzU<4WJBK~hWSoNxE$GQ8x8)0*9MIdFD~T8QJr2~W+;q|1YKlSj6vM; zLIC+2Ew%L*zily8ZK|Sd+qlgPA*YL0^DV)DUrx&xsBw-}0bY4qyo!hcLI{F#KgHaR ze%w);hQCJx#oJt zoBk&?mTYY)5^TADEw2$#=b@%`^!AWT2(`0Vv`07U2$hTQ%s@vzY ztvg!v8JF+VW49A=?;#Sq;0BaWeAiW{;ez6?(_gRW{1MlMH1@~SX?!Zz9*lZB6Hit0 z`?cOJ*kIYX%{W#IvS}-TTXqTVCv~HM$-CSf5v=;mi-5LlAe?$cW3B1k!M;dDW6^cS zl;8w&s6cF%xn0EkUW2*@o39iq!GCT)*MCK>b|BoD-SJ3}dLZ%Tx}G!RvB)k*vuj+t zZvAB0(Ds0Cvu3&SDnpaQce(}N@EsG0?se*i{?JwqP+Y8(E8i@*=TYH7m-;fK|P+pnZy;AUffex&x z=!O3fzldvkT9MQ%iR_V+GHf6;Dya-4h`l^SB-Bi*ys7-DA=Kz!zPx0I^}V8y>hqTb zBruZIItn|qJGG;Z=_6_FQqe1kM$4H~5(jGdzl9NSITl;EzD)X8bJ6PdP3e56|87*_ zw;GQu>H%J>htq<~_(74%@1AKhV^G7(1l#_MQ3RG*;$r}O6!?W@6IJOWGTCpjC=Omyv^sYG@e==fJ(l^ zP>Lin*JrTrX1v9C`pH*^BWMjx4IOhy=_bD)Z!Hf>0ZhSY(`!r0;}!_^B7g$#LNu2} zNGuZA^)hiWBvLMXN2gJh;@9d~L@;!{#7 zzbg9d08vF<$?L@p^+uECw$tsbE7fN*wJPPQVBOH}+_iTvR$J=m5Uq&=5aKM1K|3jFQU}!5gwH{u((&r+(RiY`KR^p)VXwKu6jAJgQ6fe)?T&jn{sn> z6ZBo|ebMAZ`JOvo6?&qx{mQ`g+=YV@^TH-VyvtyBSXOYtMBlVZH`3ypJHYuDjshE$ zt3hS=x>Gk~kVBzzyP(#IfrKQ!(xOt>Dm0?b8j>FvAV~*QA`7GYlM7}%xL=R(bFJ^`Bfv#ukCE%62MscF4#b@D%6`%lU-T?(4Q$~d8>Oz(g8B&kXOEtnz9 zrvX~~;SFbtq~*hzSJsS!Y>%8Iuf^Pv>aYHSf9`(eO8-F{BZS&X>@JZ%hyBgGy=R>05m)zFz8+ zeT6FA9myhI5?Mrgnt%BtIupe@-+u1lbxo5WnoiN|>~t&8(x(ykFYH=#LhKpsY@i#5 zuOl^noy93}Lu-p8*wIRFfTi^S2nKo^LV?%~9>)*;WsAx)qTX)VtKpE z3P(HLcp||AcUKP2#bM6;^Mf{@>CA9uSO>61MMaW&W`xHC^^Fg(TQIJ~S@0bHWJ&OAOHKJRZ)HhOV*14T>LSGsXutXym#G0CGiPht)g6KbRv z!dQdl*Zc|%ugxjKzCdpMoEDYCQu5zm?R_h7B&-?jO5|O?eU`J*SC|;@$nFT%<*S%` z(6($pw!bDeSfkb^-|uQRfJGk?SSZ>jw%`+ODM}*4!`-)Rpu1}f{+jIdAGkD*a(r#S!hWYF*1j7F2O#Rw)7Rg3>k< zC6q(yuL#8q2g#RxV%EZh(ydV_Ensrq)$z8Lri4gr(dRjrpaL-=-E_N>Lcaua|G^3u zLT8{ue%+5~8|1`-Kv#{6V>yiScs%`4x6qjhly{_@=(8-@_qm8&+$1A2 z%)ln1P8~L6yjTnjLX8D4$jDn@zh_ID`JjE#DzK#1KfidRtahU=t=nN|IhO)3kWKg) zX%Db;sguqZf)MHtI<|&VG5o~t*3nL5y`=3Fnoq2VQl^W!*5zeQgFK7AI|<~3n(4Os zcX{y7B(3?W`uE#?tg?{3d6bQ*>^H#`*i^2ibcJVtw{&5~5tE)n&E;c3DHfZ0ZYO@w`OIp6PmoTJHHaAMU#ueokA4 zOuXe!97KGer?_K|?VxFEB_L@VBmftvS=%_5yEvshD=!#}vONye|J;2*gtdR++afbR z5ij^ShyUc>02qU#Vjl>T)G>N)JfF0A{oXj&;!0AQr=v&46nBU_r(pGzWD3&e**7>LVNWmn!;f+ovw!1?Pnc14p5iZ)q!@Si+em4OAit;YvYQ2|7 zW=5ycO$O6s|MGvRTK&Hbc14Z>c!QDU(sD!o2Bs6sv5g(V*HN)!eq@kK?!G52hx15} zGc~NL5!Uym{2%MECST-2o>3EW19Q>m0@$T;EtVvZsF~H*RZ#bwG#UBzZ1SV~{tU{! z&g%^0LB_S$qS-%9$RUvED_gQ2IRs(uyQ$`=C9`!(lbRx))L zA(xo$76PKH!0r(K(nZ~WFH~>{)}YmwdWQ#MdcCNXFOdG~&5p-)mmwV8aW;oQ3BUt*_DEqFOirnrQ3&N_!%oUZq%R zkkbbaZcLiAMMdn8B%Gw-foHu#vnHX9SW;}~SOcH5I7+SN3Ez-^;HoDMs^IdJb0a=^ zHk?bkrzN`8Wf5xe>6O+r3L)+^C5vRJ{dTGyV_q*_;|_=52Q7E=!5%_^OV49^$J_Bz zHBj?b)e?^ICXn0er4{$wxQfwatczWd`_f>g!As`9Mf?N94P_BW`%Y0kdQ>^(FM(@# z(64%v_PKOUx|MY}#h2SY8<&Vg+1*Dzy+!iMv#YU}M zncZ=}rbFZ_gsk;ay9wghg(KQ!AXn-O@z1Kv9z6Y{cImVjT?uSN0@f1{IynL<&1U|S zW{;85ERB6olV3CeQ(A77rrJdcCk3W4wRYIZ51{x&x7?VezC{#`iiwB#di8+$CHO{`5aTM!zDrgHFj`UEqSKE*US;l(*7SF!Pn181OKk2jU zD?G`LrTEeDKxw#Tw}F(^yx~Z-QBe>=M%FYck&c3~Ne?2P(9POm-*~JRH)O9WtQD*~ z+|Nnh_j{}d##waU&1E-9CQYGTn!ow--i7e`h>0rA>9e8^p7^Fiipl)dL~-OX`t$o`+y2hD2tf2UQPm%gkFe?px_Gts8-t{G zF#>z6tdgBgA2=sGZPrS)s5*OwzG_BeYf`eZRq{!QEgB}%Rx++0`d#eq!FrNBeJ&Q` z2jq=iBtJF7?=ZQ}#Y{cMjGld)!@ExqsYTqHS25y84v6k3{MV00&@_=2dH!A(mBq-j z@|8>H0u;G8c->{VtQXluDw%f6Cw0g=wMSgE@LvBmn!Jnuk~`H*?R5xm5l7> zn70ht^r0TJm8a~;$U15MSZcRk=RL#6Va*1(FDMDoW0Yo`gM%w|d+`VNz39ZbJu*^s zZhhsd+RtyquV;l76!JbjV|HHB6w&16()hh9CehFo*UmJuz!D7+SUA*7`zkkFW$>mN z^vyLt_b{R1;nz13m#8k~DKfEG3y<#GqT39WUOu>FllY0nL_14i|;GD4w zky0!8WkPm`$DxJslC=h*RBAxiXVlG{9(2&T@i66&*zkZ)0ZS`e%Uo|5Gc+3x&y4R$ z()Hp&2|*vcdM$kDy%3$lkul6%<%d)n|FKQ9lzmg$-~A{Z=vBN0P(&X|Mi{G}Xt4I2 zR{240pdijZ#s(l7&~^lV7MEXGy3bS;)3IKvx0IOO;ZR~D=&~I;VD(wJe95tVvNTr^ z;v8$uBqRp$ai5I%bx|u4S0D3^@OP8YqNbcuEdA1H^r`=P<+{!XnBXIeKU}HtXxL82 z^Ul^?qI;)KlFB845x1VeD_et^S~hmh0$;7+fVnmPRdIU<1caw6qus$wrGEe%(D$bcDjUU#np0Vwnx~h|K`wp|`vXpqSz^qq`%_MCR6M{7@K%`{W<-s&N;V z*yEuObO&|yN$(jJ$=0l7=IbI+a6v&Gx^RKIM8YEf40LAPA$rHjl3g{9d?gWO-@sMH z-_3JOs)V`Z8yB_Z*Ist0Y;a0$WR4b>Oy^dqJ?D}i@dBa}k?3-b2z-`T2?rd{l3>pJEvXN<4#qRaaC z{HQL!1*z*w#DP&Jh1s%B&%P;mWPH&zQ{+%7k>w{K1bX@|;kJB=AM~A>0;&fCjVHd8 zdG-c;64kZm{L~QLcF5n3J{a2<$tf1mKI5~6V|&+HkbaIeCO)6$3|#!X+L6XIqc;iS+sg(V4q*RPpjRYJ#qOHOd{*`^~E| z8HXeq%#<5BBkx{o5JjDG#zF(mjD658kBm%HdDI3m8RQ#CP8-^d1$f1ZPK9!VoCfW$ zhFwYkAJh6;J43&=Tv@X*EPezDwA3r34;lHsXT$Yn;9s}iqtBHDY5`s9!{_dS4;(7b z(Np~kk`@nnNM7^&rn_e<^4c{F3|}B@hq0g$FBGo8lKWK;HeJsgvrr$*Loc`z8mkb6 z$tVNydZ%`qY9rO16RECckn1N-+xaK5aoMJoIcB*}1QPFZN;?X7vQ?@@YE#8MNA?o% ztuWvG`{%2aw(tu5d1c<7U_XNpNI{&$sk*J$LLdh{B`{s2^^-|WD zQtd6KZu2gxM|(2VC&VT>muA0dX3h8?VP*m8d7eaB#Jes*(`WbG1E;PHW7Pq1ctQ6x zBJve=ps*8f>6P6JYO&}qX$B`n2RKvR>|{cp^Lr(V`1Tg3So<&ckkTCl&st|<7eQ$F zerA`KL!%-Elow@DIOGRLedXNxJ2xhz639yC)EN9_v1 zk94O5RKNm~S^QAfH0aj;Pp_+R`e%6(9BU##5@>HCYc*kH0kKnHOf?_|Is-S(5FA>BrPBR%*1uXEYYqgm_aPH3r}Qm=Q{u$B|WHX|1>t9>`8 zI9Kx);@U|>byT}dC>lt2!&)Xn=-KVG{_IC^|Hb~KMW}Dyiik-oxZ5c*&Fjd3iC=bjO1rfxFALx65958>fM zBQ>{}FNX(ivwm#}-CuBcb_5F@zT0omzfbp?W@X(42^N$`cnGJ^CanafE#W0t$-hM} zQ%UL$>=p_6v9w5GS-2EMcpLXPrD^ok?yHwBG95>C6iuJR34b@fpU0;D6GUViLM&8y zJ#`UlRy?^dDg$|RZvM2fj1h(CxTN@79Uj58Y@6*exmk2`OA`0hMl^*p9m-i&H#iy- zG--JtQBf~2DXqKz+aY7x?$OBR^+sCAuW5S#@I~RiDea+7zf9#>VBUhtgOGmz_k$nF zJVfhXlrrm$13pzzNwFdCC*)u&G8LfF0u#O9LRyxEX}A-&$RAl zza4$AkdbWQtZ|x=A(U@drOis;jG(zv>%uR7+d?p z%f)Gbi-+Ivc(V4i+E|-}dzo^v4M1Kbkl_Q7B6<%}11Cg;5%0P^ge3$m%SrAb%N*^5^XF4ommCVrXwWzoCwvgJTVsow6%5%Jl#LvWPZTuC!N_~Jyf>JdFZoXJdESU#lp8`W1U z2>6Bo>G*$pisWw*?Y`RSkDDSEf)8>N7C!S5V!K`+Z}bi^@d4P@`<^NL0qnDuYSV7T_{tN6*O=%x2LP2#!_tNfW}^|EalA_g&U>xUO7(Ph{Z zkkFz-`-M>+jh)x(?u}ct8fFmfelYNs`gM>-Gh>@snelU;38hNVJ*O3@j$$_0?g|%F zc%;5DX!mBkw|oGf-B)IQVMWLr@9WmWOBJ)g##8VvQirP{%wb8}`kL?b>6Nq8B9T<+ zF3bL34)(dqY@rM3-nv^eneET_J~y8>=B~n$Q1kN>>2;pCw>m%bNAY zgaQ3{f{1m`uiwW572-sH8G^v$MgoZA*5H3+?G-ZMGjG`HYOlXTbwRQmfeXqK_Wp^5 zT?k^|=3l*{6sn}hYFTLSL6&NtV}PGxom8CtUurvA=Xu4VMwp~@h|QwQTe%bU?%01> z{wA_UVvc+QkI|1STMgE%HrN{8+nCaMkPx#yVy#3^>z5p$+!+uX@oXqFe~*JpkV zuzY1f-aTD(^D~#3PJb1hYOZYNvA zQ`fiuqhYeM5Zon!B=Lppv#vw~P7|ODL?GuuB%&0D$=QFktwQaHnTws!odpQZTvA7T zY?2`d=+1MJbW5m~4{MlW9I?}GyfMP|FtW0Ykhq5l%d9La$Lb=z134wgp(FP(9f_+h z^l-agk($_jiuzWcSjMolbMYU@?Itrvvm=3=$lK$N$I121;N-t>_8-g#>K)!Pn1*rA zd7_`dWzR6qIWE;;jOx+#LV$3ui2J=5p7-BBW+0Ybk=FB-@=@Bg2Kg)7uvuucNtA7r zxAfQ#Ml@Q$l|yO>4c~e{{5>#nmPbO$Q8uOqLbHu+T*N2~3|!>xzabn#EJ@ z>!wo9GBX`)NpIcY{=yv^CN5P zt8eK45570s+xU&Nz~}?=f-d;S_`MSKUd7-&%?gTOShUBFS(fJ7-#RPn*6*-JqBe|Q zk`I+`2_V|zWP;q&OTFMwB44-KC`ObjNYe@v6WqLOyd z;3BQ>om}O{j8fyIcqb=z_HZZ30DEb#eoW+kfw9yg(^C!=a0X`78lb!R zUal5O;}y1Rs$coDKt+S20ZreA`?&N`@$EwDT>dBQw1qLb7ANc<{0=It9|BgV6 z5;r~9?^euCW#(a~pb*lQiEC$vlvuH#0OHXx+rZp9c=(X&mTWv7dm-}@_S&>^qoL2; z&SVSztm8l$fn(3)IVlF6*Xf@)7s0pOZKqz~+Ho0?hne_u-cXt!VVhILF~U5X@r;Kp zb||OpDp@@`220N(=C9c^QO-0Si|<}2^-$j3hF2Q)r@HbEG{^B5JYm==sRygUPlJ)dJXWbcdkhtB zurqPCF*h;WuoI6y>e$a-jx%xg5uT~NziRuQosQ7v`SMwJ_K^wK{8hgvG<-MGLDgz= zH_e5kA5~?z^_7!Wc6@GLvud&vi24WG%`*5&=HP&+Rn(x3Wh~^#sm-tcJ!HN)bf-gx zpZKPFVPsN1`=(c|a);Q@#~}RbAV0}4;^7Z#f6`4?rKR_W>pxrds|3@uG}Ts>s`}AL zcYa4^!;xGA3hH$nz~=mQCnmN%J;cQdxj-$~|2v8Z4E^PRD4mtvGbpK;a}1!U@2wrm z4ylcz5>v~cvd!XFSG1SM`JvW+WYbnWpyZCAsp$RV?H?LV6s7cJ80Oty#RHm3^PYdp5`@yqSP&A7a7mVM_B`xWR37t&q8?xl@}j~TN= ztQk50#^(WVcfW})7$rs0? zluhf%kLOSJ)IZ}a>TC7SP&o@LTF}5;&IHv?s%$=(8T#9i|M^Y=>btQ!8aXoIojOrD z8fcUFh+TP|q~Pme+js-WxjBK~rg~^Qt}c?>q<@KY^wN}FL^Qp^505ZC%je=+ z4F1)-|HQ)o3(j#w+J*?KS%mTa1X15Rv5)h4_6g{0De3hDLkeMeT$BvUFpk%_&JUUy zo?^6?;)s1~`?7~l#F1*h*CIr`Nr-iG$~5MKCN-5u_-*9C)~j3n&R948$I%R7djrwC z?X8crgh`v+r_^QB?UfXtnGO6R#DgM4=3Q^Q>fCN_E=kuW8PDe+m0EhpTcNNl`t#e0 zhrB@SCr2B{qGk=6^#$Sv#%OEc! zRtb@NQc!9>jKH5(?k8~GE zC|ZIuIrvVxo7FPzLH!Bt?ONe;JwjJT8}qP4Y{J-kP?%2ol(l0mqYY#4t_VmeT>=>2RoChk_CF;7|b{|Xk2szx4r`3zI6ce}{(+OOC2=G9T7pP?1 z_{4zXDSVW`tCjgUNUlkqal?OBL-4jS-R){$#T!rk>{TU9ER^-V2%e*L)Y{w;DCMunZl4 z^tH)XDE1n%ZFs3JN)Tf0VbFD`w(5^ZP;5D6-qz0E?dgf!x-)gDM_3;T;pYIQwU#2- zXKc4Zve%pg%%c+JeKuR4fE`Wh_SU;{VRPsuKGY8i4+k)IE`Uf0&6zyJ-~Uq2(xdrj z@g2-sF@2g1u`9o6T2;PGVV%DEoNm(4OftG)Cj!#9 z2(XT6x;#cEqYA{`jpmJ*L*uW$zJik&488q!?tNng!8J0hJ-Q0J*oSr2&FHoGRj(3S zho5EN(@hHNl&Z2vB~S9peJ;5fDIh2!@u2GPj^E?KWC&)iS@kmS|51Oxli-*nBh|Rk zf1KfX-VS@!)3%{asFTn~;U@F~EoLwk4f6InD*qzeY z_}K-@k2$y9p~tcFIBQixyuVu8z_rB+molu!gW-ds8*eK+c1vcd@kE`kienMs&&xAp zk4pu4Xb{BJo|4_QoH2Gfo{nS^ zg#E374FhIvl$9H=up%bR@Xy|Ce;XlF)t-hHWzcgbD6b>)egqVFR=inPO16gK==Hao z>z7Xu^;Ic~JA39*_oV)eLSdJ92nv9E!wkDYfb<1X~+%}dWLL3)90#(!kBXJ zc{*S(bW>{Z_gPO9CD&jAK_UyUp)aR-r#d0;ST74d)^i+m+sNaT2B4?w9w%PMKc`Ne zB#nlc(}-$E0HjHNwc3jri}I9>?dBS2c3T-JrBnCl+IR90jp6UJ#HY4Ia=Sg~^n94T zh_I8&jHUi+pudgs;u^Gq+xc_FXMIJh@AwvH*k&%-p#hI_>Z+O;cqGD+%1r_vd>^~i!?6re%fR(N%jYRM;=_W|2z@VN^u7+0ByK*YfRFW4t$9I zsXHgb?3(Ze)!I~p%gucM@*@M)Lj=XEK@B;?=Hn?jF+NfJyN-AcfLZ!g92FA&+#I&J z#UCyT_CU*c$Mn-d=ai+yjB@My4Gjy11miz!i4mK~dgf>6?Onb2+@x~mLtmy`&)qM+ zPCuH;BjC!r7vD~1KZKM$k!F(Wq2lFr%j*wzS1uDd9?V~>=?$C5z?cYAPU_OfGVT#Q z_<{QejWMPAL1V#%HaQhz$aQvZhc92abN9yih?u!;8O!e<4dx;buX28jF6R5A{0bQ} zTc1VGy>gDru{bKa&PS(e!Vm%efqoBEC6Nb9kwF$Q_x+6rEnhd7@e0JjcHTTGu`kyJ zQ#yCec2|Q*QO$l|gx0}UpkFK}w=upU8m61zka6e3viTKxl3l*7F)l1fM#|&YMVErA z{4?CCELm*9aK;y|{A#wqy0KA$q#xWPTsxko?akt=IiAy#17)ihG5F=oY2}8OJ>bg1 zO!s#nS#b*C!xQZl8vKDK=iT$s>2X@*@17kw(2$<|^%-C1sLKqrO`Egd_Qc+U@8LvA z?{uNahHxae;Zmyo*7p+0`lp2>nT?ZhB<+vi?r39< z?_PwYm#jSvHO{#9hb|PiWC-?c{eG+CEI3NOnf5-QU)ZNpUN}$D$Y&dsiFUlaCmUy6 z;J~t0i6pT0uYXBxpOuvH9yRDW}m}i zJ0k&u<;>+I4OWJ&h*=|dD|JE>0)6q>(=axTZ!2~%VC2V`;M&H z(nww=B7zV9SL@P%<3Vs=J|-vB?F!$Y=I%w@c8Yk9bZ8LnWte7lrgq>l9tx00zdO$B zm9d+lh)f5fz@}dMO7!H>h$(D*W`UFAN=0Wa-R6gp`&)O@Ht*0idUxfT&;+9*!F9L7}luD zG)Dpq33ZAI9`752(NC?nzA_W^?jC!u-;@e(WrVDey5B&YLTjUI4&(fF+7tQx7~rND z??T3CmkqOEsNLmlMQTiiU3W*{kx@Y}^mxL?6l0F{?c^mn04M68e>{opk`#OPEV&}f z>hLwolB+Du?Uvhx|M>=fA9a0UCe8u4rkKM*aNNiD-I!PBjeo1Az=}uv80zBx zzQ2WHOLIx&q7>?r<8nCKlsLVK7#2?BlbdArva=6zt^?5*T-6txGp2T8dB*9#5XW!Y zU2yBqAN}88@2WIYnz(Gw-O=H%iPvG z-KYWF%?QTys_Vg=X2?;S$ww?Fy<#td-rLAAjEDzqb@9zR)->}InF}GR0gmd)0!A@w z@hgVdzK!_~UW*=gH;L}6#_PDVZ&+Osw5&(Wl#ye?NFo|nnd1-LBx(NXm;Aa*eY$PW zt*f3B#Qxe9%$t=vbnEm zR`%~C_EhF2wXJNDMyG<*K*+c3-yWfrN8Gm=KBa*3%HWkj(1dR8_^LqxEb`<-4=cl! zrEt;bbn~e4!!0pT&jm~Wks}&7*5?|~es_An(V=ai9E~$3{^z>3^U6F3{S8Gk<3Q2a3#8I_=UF&(wH2Y^rZT^=V{~bEQqykS&al)Eui>Udh zdIYYsp6-djGFVdmLrIv&DfKZ1ApiVJ>{Dh$y3ZrU8+*di*(>?Eu23C8E$0r@!lhVyO@5yN znF!*XLk)fF=*x`#p7`f8Yv=jO`L=O=@|)oE>!g*cjfi(O@qv>Q3wUP2ifr(2PrJ|q z9<)65g}F%}UkdoU2us~-V5Xe*O55K3Y^OK$WcFca{4uG?bzQ(^O8dRRyW`vVXh9mB zA!<^Am21c+!TBqW{<`}bBM2%!n}Xm4m?gD*VZw<)-kOF`Tr)X}G1cFf3Evwhe6?1q zs=t+Pl}r_2g7C{q!}+>+{KXFRb)@{2uu##ebyp; z{s9AbAa@>z@$=pw&M$cq(CaCDfUukwIKgKWdT1}pu(znN?WNF-yd$8tg!-eMi?41cJ*$Yw=dOt9X)e7ey<{0u{SwDJ9#xR5bJcBYlsGdS4xh!f~PTj>=Oay@p&mIZ7;OPiRr`{<2n8 zQFXNWAW-)HLyVy)o;LtQF@R3Ply1bGW^U6irDRO2irG#}IbcqY;of%c0?nY-6u;ZK z>3^tDTC2psULdb=xAezj^I`ry|K+aU-sdVkAft*D7Bc_$_Ue1Y(Qb0pjS{zeBMe=i zj>eRZY6zCQ=@Aocm^2@2f!6MlSKG^&RVkddrGtDsH8i8;bE)Uj z_jve=_7T)1pezTLdfN<~U-}dU`5!fT8!ECFA|HO)XJta{?$M;`i9Z<+8$1s^lG%GE znZW1^(KL;trB z&+FB;mTTAfeauLFFy7w9SW8ibX&IK7@FED@X>Ftp2%?rbhQRWV^osPRK#HIRRA1HZPJ&LePu@jymwI3)UM( z=M;4$^jNiUswA*r4dDPev)!}8rxklleN#h!GJO`KlcW^|TELgE<{0g+v%ez;RralVuiOnlIT^vATRz?fbUBo7|LXd?QqCW+Sj4?iPC&I(}KkTQG05gZd!!A?BIa z)`tAt1MM-LeH7nD37xOBx|YwjlZQ?Got)Usi)FgcUYCp>JuKmY>=C>!;fRUUHr^)QpWHM+ln7!c|;@VQIPv~CxkOZBXnbL*^}?qxL8U0xET#tn=Yf^R ziVkw&$dfSr5#XzZmdhO11NmFbF2}EFzei$=ssgvq9Ck@!s=ACbJg&G9oMwM1K&^LPr~Da?ZG!m4p8jKI4-dxc7}ow$_&J_6=(!*p^`eqqRzL+- ztEB2U_ydS(s-pQ?9^36!j7vmeU0&&rZ~8Rg9cI(TJS5cpz3Bbpgy-gdpr7^|d4|Vr z^0j$xS8*DAc7t%ghXu^XJD%UfYhE8=x6PJU$UxdCbd`7O81?fncdrxYg7Sk=;0mjK zxS<``?i@2nYqs+ro`nI3X?;5BgqKpW+En_fyf_`f2+F`P!?}p zx$V|mtmZezFJpq=GYaRR0$EV3r#hcnPgYV}TA*a2eg4B(XmgZ4>F}uOF?7zn{pGN^Gn z)4Kgt2*5Jbi7C$gEttB)=24+6(0;$CRep@! zIZ5_7{F@FQ@Q4F_Yu~%bS9;xU3Ek1vAh$~{eQWql@Yy_39UoX`xQqENA? zZk4n+03(~Pq#@q>)8E&BJ$+j54;!C+TsCnoY=izpDDk|6L>~2mQ1dX!T9)|5vR2t5 z7|Z;CuRvbV;1hMdj{$#hU+n*Of3#Y_6~|jaP9j}Z*c2dFc!`wgP&Ri3JDx$jt`{vB z3B8Mc4Ln+|2cK>IY*`Cy@>h~wd#s{!Jh&2o>);Fi9B;>S9QttY*m+Z~^5M=oLG8ri z*ms?_|L?v(2Age>AOruYQEWs!qgV~%r+iQHEt9Jta&8Qv*8Q8c#F)SMB4&%!Yd0aO zmD4x=nR)lk76wJP0b2uMsehA7GOJSef3~ANCA7bMe7Nyp0lwP$v~slMb8C`~_NJgd zHE|XG!53K;fZcv}q2@MJjd?wukAsn|DtTH&e@7Xgj_sQ61X3OnX+`z#HpV&pN7}LM ztGA|RS$JEn?0=YosPTkAntIm)s9s4R|KU*fjjW}OSwDwO=let9C zlU7}O^(urY!c9!U=;fRuZHA-hQW_9SfjQ0HN@Oil7|^X z82Zqlz(mY+1|5BTeSX6*(av$}b~rrt`MJ$=a+*zd3&T94ltOT4Ghz=Lrf41Sylo}w ze->9Q{4;25=j1_q!l1}6VkL^n9~pg7h@8b~y2*lN-U;CAVTj`?^u(q6pd}!KcVnG& za4L2Oes>SCst6g@q=lA6P%V66C-ckKKlHE(Og#3srHUXY!3jf|p5zsrBg%MF*fbFss9gOUmezj8^(ep0O>Uys*usk+xv&L}n4zT08RqsoNb?$us$2qdYr<9IPU5ScNO~nW`W}0Nrbtx_X>#~NFh8vmL z*LSun^+2o#2Wm8gG8A^|;)4fy$l|oK?gPz^uiK1yt14&IBnSuj`)V zajVwBNh{8)Mt;#7krICV{G%sBa7!0ggnj++;lo0iZfS9T$B|(!(I@+f(QMPNeI=8` z3cxDi56MFaO|rKiGO5J;AsE`zGr?Ks*+LJH&(i>HsU&61ctoj9?$2$#gnfl>vZkG% zOTo&`H?B5vThgf2cJ2hr`8%}?e|mrS;5|AOk8|4KR6PcE7WYz~s_xkEON^k{z}kKE zmqp;yTk{p0I(Nt~7dy>zdTQXw34$B^f7`PKfeVM(Ab~^adA*+7Ux}jpFFN3IVNI5UP`jf7a6%{Gp>uUQLeRCslsV4|(F3R(79{-?mR2RKb1H?bZUJw6g+!Nshc8dVW)&YP50?q~ zr4PbzqF=}Av%@-dXjne7`46F=>vf?-_%rjpw*EbKKYafx=aAL-uT_{s$_%dU2`s7Ax#Xlxd{P@@LvJyV26X7?@TMrd27n zcQpHjM*B%G$;=X~jIYeNzW8^y{4y*4A5B;;TXyUdW564|kTQ|cq|o=-U%Id3)CAT) zTsG;hEL`WlIO78_*9t5x0#PFEO_E1CPy2#eLJr&EAHTuw5cKm=7x*;TFS}PUX33A* z%ouC>ni#z{C6Kqh4BIFq5$h{?DSioGrE#O9O#!>yZm!lCY_2lOn1xPhI4|tFl zoU#5E+O_R0bd6iG;R{SC)4cQbPtcg-IJ+C6U~?nA_G7QP%>VSPmA~l>KmVFfV#%KV z$C4R-TT`k);qbn-{({~=H0J*7CVY@YOfgK;f>Y!Jw2cz0`b=gLZ~TdPW!UleIZLOg z?zHja@S9FgmNdzuMCDuM3~*VPyjRxRUouFME?umopb~ngA@}zU!gacW1_!?5#-LX3 zZ#tAf&_i-Hdx9cMbfbEr{B^^y{YjcRno7Nmob&XmlX@0ISa}@ZkooW%;qxb7QcY4V z6TXQ(GGftGg*ado7}DlNKRyM4`CHra0^5Q~>>7r9WK-a;#NjU%!}kz}WfL(2^->>Jt<%*J|j84O6-eQbWgpG;i&MeUlfv2i zHs8WW=pOm| z58D<|o`-M_9j-+y(jY6`h9t$72NasPj=VG}KMYU>IRM*2?|IBInFozFoP^d5DX3_? z9+@?uL}qol-?19`hxjeBG;0I&xt-JQPP5}6=gc-?@aMHhZS$xyn;U`82hI!h#$&~{ zUaGEEz6mtkp~Ng+Mx$F>xV=`iyxOw(Zh0VJPCFY*nuLRCt(m*zSEL;q>0W{Z_718k z_8O!V!w6~?N2Ct}=d|f{-^reddi!K}^IB=Js5DPyBcRWxcO{XQYAit^29IJ{(L9fo zzrvtYgg;Hd{-Kc*2M-u*rvl7Z-6j3~^3_!5&^yaI{5Su43og^3Z<_NtAy&G?4$}P! zS4Bbp+Wp06TllJig}eEP!yZmucyi(?o2=D9Cv)=KQ)cND%N?Oz5$dYDtJCJrt#oV+ zH(Y}`aOVE)Mm`@&xij5T(sHESnIIArs#*OXMln;%mW2>I?KJFh`WP57|913p<2}u}7K4{8-J;=vw{k)0)p^x?C<7_#D+gw9Wmzg^mq7B|@@HAX zd%rwT1e{Xz!)GyPEvYsG9rQCX`&x!uzl5{2@xdB9?zf_ZECt;iqvh?;sRwU5@*8J{ z-blv9+Ns)Ro;7c`w*v7!CQ_SOo`gi0HO;M@NA{J7sz1+TnxL$-682S3#*Q@cA3Q`X zzYMt?Z>zk*l1b>w{&JgLi6JLGBVfq&cnJV(X9BGg>Sx_w;NGuL`=!S?K|TuhjBZC( zG=;4!+GstqL+VjbiW6@}3qX%E=WOx-6)kD70{_j^ty9tk(BGih0G%fM9Zs?8a@>pM zD{QQb%2Q&X$gM(#2dAq(6WM?BS}hr0ofjj36x$)~5L%7LdGlApl8A|*?T7p0Z$3^B z{Y^d|n4c;azx@!S+;$5$O6T9Z|K#BP%1{OIDX80Q6}#f~StAt4?>|QzQR9h#D4%rv z^&8;AEAz;>;zu$Wp{fY@!;VQ(f59nP=q$pqI+~of->nS(v?%DtufU1=PI|&g4|Ya9YjZFi45}%9 z42m1UtD{eS&DqF!FiIS;VP>_5f;La52EC|dRZGc#lvahJl!e7 zJeoH6yp8IA9BK%js*qoL+Phg3jX(yL_mrjl-yN*xSqPcak*TSa=HI-ivBWX#1`2K1 z>E18rUas{@2lbL5QO0N1&X+{dL6Z@}E|{>$O>tSl$ug9z?Y4U@ z-l&1nu~KL!l0;7}U$kHlahGhKtUsR9yc6HZ_YR!}uOP z%Zt=+ zNJL!b_Hu&Cjtu!Sjc+1?+9bmg?>--LKErjoJ{@*E;ju=4nW27UVsnPy7&EG1J=P9C zGvj;Xm6SprWX&?wg9@0GOW`PaKG%X&^h$-e&29Yc${UIo3A3H?^JzgqCgFybSgKpK zb)!q4zPxF$uCSZr^Z#^EG1zy zE!$OswW3_-)PH@{#<3ZqdfZCDP?fU~wFP|G~x!*_Y9K9FW471?+7=lV>ZKL(}Zb)%q;c04J@edpu!95x^?*|Z`>4^km?M|Ow+R|O$8>u#vMmn;@Ef)Zwf7O% zr5Jzzm5v+isC@^BDtjIL<=&QzZZ3?H}6dB{1uyS5tD#7Op`Zm-+}WU zQv54Zx7_pTk*xxgkLK;1td~{B*LhO@ZDi2X;Jo(84mKA?Sa$AgSOMM&OWQ}Q{r-4q zt9wyij?w{ms~=%yw&D5*k3q1@e1~#THW|=9OJ^o8#Pf})PlzajAo;tM4X-*(Z@7AjZ5 z*mP@l;0okTNY+pHB(5TE@OvU{!Ue={Ef4s?){bDT+1AnzUyf}~Oqmx_-|LtNi3WD6 zWv%oDlR#vz-3cV3Lb4%enfFh^6=lN?d_R`YXSn}OTMqdaO1ieIdzQU zR-7{WfMpl^kNH`i3R7cn&w9ja)d;n$C!*O?BOngj!!+URqT-T7kpjOm|3B5>p7YLS z2*u?x8C6Dvnl*no*W(umvg#&f=@0o+T5QpVlHAtR?H{HDm~2{kgN-P4aE`FyG#UV}n+Uax3ybQ76&7W=t}c-vXrCRzF2jcUy< zy(mvhRDvi(${sPIZJRpW^<+cJcRZo{4WxW)tHkjK?K@G#6OVG*h5>nk-eXTZqleK5 z@i8QmdNECa5bmzXZ4$IE7~?TlCT#~S=T3v%PrxftRD;_{kc zgK-wvpDFczqijm^IC~LN{{D?#3&hjqFbeMx87#R_9|7v>0O0+=l*VW&> zV*Hs*D12uIp=e@OxU0Z(@o0A+rk@=ELMKws%=y?Ds_KR1Q`1i4KQR9-SQ#m}fKbHq z4OOnxo{=8u1X3^&e?b*CDsx+RDnysoeq-6lZB|1hk-Y{Wejit0X7sbrNl zI+a6+*{3ee%T#_#ZhF{FlEQOyTul<6WS`je8ANVR=FXY2cf&j0G|vSr2%HtPmeI@N z0cgT%No|phRsz5EhrtR(q)-(79aqbOgIAQwYd-`QK7AXUO~I$rtfkMoPs>TKfu0bq zDsLnAl6}{w>GHD%-dyX5Ou)t_hP>M5IYX8NG%ojsj_QJsC7Lw414+MNa{5Mo?WaNc zju}_;2X?M~7m#VSv(*sY$(M@5p8E*(YC>1j&9hgo_@(BUng<~$^d&cX41E3qBKyiU z5<7eH{g0L`?w!nsywezUCX%AwZutL5i%`U-2_hCo*hk9mR*-6zb{EUkv9X4M?tdbm zSfkdCrE-bA|LGvC>_`A|QR^Y^wAI+Yr!*oUwd$e4wr4IV1jooI{!^0C!@FV^d zK~f<@*z?;lhp}K4dWhUpVY=uiZAvgUw5t9|l4rB~34EWV1zk{Ks}PQUHs>J9v!bhq z)?My7qm!88&yA%N%%sRfW{j-wi8b4mCwVkMZeDppJyt#IyS+B`uW26dTP{JU-m}FhG16n$ffJhCH z;sfS{cWpvsYFi$gnx92;9+jm$u&$xrW*9@PNY%3ZkYAjuMQUYI8#O{k#d07_Ntlj& z0Y$P<+MSi_EMcU}jy&s-6=BXQK7Go0#g<*RN-{rJe0qP-i*>0W&q_jUImEYdA@DQ{ zv(*)ELY3x;kXMCpbzSIP?jr3Xr}!kM`DmS1D~BplBTZ!L%(T@OekSsv&Mc76^CNxm z4F?f1PeH_|jGBSCZq(fi26fS9LpFk1Qp@`H)2oco7v=tsw>vqwzEx8Mjx&6DCl)*4 zKZT+^eL7^6UhA6~Uw8`My9rWX0{oYim9vYdYPMMg+RjP9mOF&X>lZ@}aVNoNH&PA? zm`oZ)SbpZT_h)?XLcg@t+n&pXIfDZ2&m zOJa+YI`E(<8P1PojeC*yyQHGv96QdM8`}`PZo(mapHQ`Wa1|p!(iuS1@>iKjF_~Ob zvYP@+ts2$PaR1ilF6Vk66o;1t^i!?%n_vmw@0bBIMa6@qu;?0GfNRVp9ZQL7pmnqg zz&7xQzHn0QM_ir&V4a|=$cp9he<;;vEK!ul>*cz$wW=OQCql4`K(GvjiJfAiZ$mB_ z-UvDO?5nFXpK-ay2?^DTDJpp$3p}L7#DJ%1u$)#G`F=8#(C6ll+miLw=NOGK3vmKj z{gLu2IsJ*(yG(=aq;?X3KP$+_djovi&ZEJXWwu=WP+tDCz%l<{<^b=7lRsyYLrX%< z{%wk$3?f8(8+Fvoo#g-+h1Idi!xNG6zPxH3ri4-G7VErohEy%R5XEWV@j0xw|GFVLN z5=kc$ptWa_QB}JYBZgbjodFSJMW_M`nK6BmiZa?PAFjncfNLv|ae{|hUDQA_H@ZEN zXjUZ}{iCk$&!Q9LQp82eAB`uC+v$okBvBr9BHu(7Bx=6zmV|@G&$Kl$B{X}1cclYB zFp;w54>Y*)5qcWAI*t^*og^rToFaU%h7|c7)7XBF_~fas$}+UDtjhaSBMCQ;V`j`F z9IXiPG8*SPm~)oPGUJyEAiHsqjTdh)JieAGe~~wgb6tN|x^p%9P@jGUv~qRV8@!qB zGN^5l<&f$-p2K;u_IOe1cDs~{PF8TckAbEbLcd75`v!U&*Z@@x$COeL@2Magw7K#! zlund;%EkBWpV4fTq4nSu)GR|qd57sqS6{-V{ZEsO)?d>k?8WmLnXfr(XbESx4Ml9D z*)>yw^9iN|E*NKx7!x=7j%4F zXIUPoX;SmiFM^%IxAcC@^`|yr+<1anPeP{@^+JOf`o1C$>z)4NBfPBK^Cau$j4`-i-*WRIXrLjMo zkJ^r=%@n}D7cSfl{jK}1!a!+xfI=#Td;0lh7v&U=G)?09LqhNH#~|(UvTwRGiT|;i z%sqQZ0+3~=*@!wuO64cs?FXK!1=jkl(g@mFTXpdP=>|e;K9hfYFPw8)5PoO;Qai3SVStMS>-`q zM{h-=ajoDa6bvAluA2dTsqFCf+?1!59gRGcUazcj-;Y`@~VT&*OfU2Mc8PZ#d|Mc*PB(UN= zlN0SxdXlIAB7yT=JTCL=9O&7K14V#UG^#4%YV-| zi@N<4Gv;O2Nv`?sLIQ({h2O;1K4EYF)v($nehYSGMW`X>Hw6S|yQ%bDs&A5sCefzI zT2mmyOgWSVDH+6B#AsOnV(V-%E1+2TzE2vS3{O_qlZxrJ@U}_d>z-y}Qq*~GXY_!} zM@Mr;`C5uBgQnO6Ct9~c=>D61F1w*UkJ9RZv!d!-gLN0#3ct2Wd8%|Lcoc$;clNS9 z@LeADkQpbKW0Uj`!-tdlcL?hEg8g)Uz)*lnbM%=VC4V4gB~$lO3RS3b0+{1;5oT;~bkt^C}t zLmhCt(yIqem#6teqQsMWlP z&`0MJ{=q&sygW8=3(Y0dRm?HF_Ux$yg3VVk0f%rXOQqtX11ll|ld(fH-_{MxIp$t7 zrPBk}_kVJdx!&<|Qe3R+574SQ!00lcsIFmOJ4Ri!{i4psEh4w_cSL-4~W;f2$+!Q zVt3vIl=&%;c8RW!2#er#G#(;SSgu~3zkaXQwCBCVkQLB)$#`=8dg!Q_N4+QCstBDz z^XyHPvb2y}8NF_MaZAJ(wokx~Orl~{Ndw_e>Ix}m*5i-497ogf$#2~sC&Jq$n+5Tw zpPW*F=HW*jzN^No!N2N$x;-wUzq*JKpz~9wZ$)RQF6o!*E*!tRf(aYU)pcbGO(kl) z$~m66{QCiI*#g8(fmh8Wu`VZm^>%jSstAA^Y(<9+ zXx`o(Q#;~@`8Q^YLS03Z=o)cBtw)47-+{CNi}K>~e?t7L+%ngF)m*v2hk(~HsGV)p z$vU{C;i3Ao{4YyzI!n>RQK#mrWC8iL57Gi2tI}?Yih=S8oQ)TEGCvLDOmAgN8uBgr zLBFbEq}2~U?9*c)iI5J~6kMw6&v-!Xt@22bjMuQz#!+kY<>Ly@)9$Dv_VB>kz_!E( zld0w#x3>S{uu(_OOC>+XE@q_u%P{U%&(GE!th@cDi}4+|~xJ>RxhFMM;HU!D@nFQNx2zW4`noU412ImNIlw5_@KR*ZT& z=C*$cAQ0Zxn%g($zz~&f924vD@dvz?$6zvh?%{BN!ciAFVCW)wIgVX-vQU+=`3{2K z$xQAkMn}mhT%+&HkK$2o0b;JhG%PZ5BQ&`cb#uUxnnF2Ip{Z;z(bINKfHfpy(vBqN<2)6qs zzabBgWf1SybnK|1nFNR*-n*|J^>P2zgl^BfR7Aj~m6^aTdwGNaKaTDM>8F0t z8O3a>C;-D3K}`cFw?tfDnkpTp@kp(jY5SOLT7~|rake=thwX{|N}7_nctzYW+d-NJ zdBgiTr*vl_VXcn$v%iF79Et?a7M+RLp_dsj4Q;?Qw7& zgmiW_?o#+_O9^0a4yH3KuMz)o&B7Ge`4VlG@Z5flGeqI{gUjCSg-0nWXeW19PMaZm zO#F-=UwSUOa(RFc9b&~#XM32yX<{}|$=qXNT9M>52fI=rzJhd-{{xSA1qe>+3U1H) zS&m;h$y_PUPYlIB=6Jzdx00!%XNIfr6f>|oy*2!7A<1K|t~I_P|NPwKh2>SVVj+Yg zLJMM&9o?9;RQ8;tQCE3hM-ad#qpa?Q+Mz}c_$V9o1QCr{tpKJu=Y9(rlvVZs>fi~u zc;DKNxsQ%V@pD~jOvvgA-1UCt`2dk(&uEE?HefkrJAu*bWK#$5Ywky+24RILDPcoOhWrW0r~q@bxcbt9XHPKSIgdjB}|0|9oleoeDDzl2y5LW$e9 zI==gfQN5HPa0E+K>4%=(^%!e7wN|S2$s}U%sLLo$Vi6ppd(r2_ho8n6P6Y^gi*a$b z%p17M9puKiviXS7k}@8U94jG-d`E%-9-d5K^?PJ%ogML89|ZmkNQ5+AVxY;1-w3ci zdCMNJ3L5HoB4(0~elK%!er^JcA|LXrK(>mt2mXx&ie;Ldzh?4|&RNk{J>022>ADHv zl{z>_b+jfvRsU*9d4SdeTL!JGDD~c5BfE}S&$Y0;<BSqU2Mx?mLk();j3DGZM5uv{)Z#E)(i_oSN8}!bh-g}Q;ugDD_z2U?6NNpR2 z+*|Z%r_4@(l_{Q0gF-rqM_&(zv%`K_`0<@TroSkFhM1jW5Dtp@kW}OCE+7h-M~9-t zW?jUIPRcg^!?O=xy|Z8hnD=aCE4S8%o#*RoGfWzm=;Gd~OcsXBM=wm5`LPks>FFoc zcrDcqEhc%Y~=8JKK*Z8WmTnxP0fd#O{35MlsTC z+pDn#-3zC7T_DU9!yav`d8b?u{bVj2=b5w!*dWXr7#nd>pYEz^o9`#FJtu?rvHIq> z`K0;O;o{q7ViP+5&c0uUSNS8;2y}k7Twp|aX64TTcW5Z2_|fbC8&v6eVaC9 z6p;grFRN~z9+n?oKk@MUy&f@}XEKgZ|0tnz1m~%Aia1-uZ%MkCFMI<$!oB0btH0h> z@D3}_4&0myEheB2i8<56HW}j6D;O0qENK2HS##L1%Uf%_zj^shnp3`|OGo4P^}k-_ zzu-3O5_?~|IlSzu`Zmr>GrJw3-b znCJo1`9P-%fLom@$V^-p-bYk=t~VG-^vuz=MXlCR5JMi417f9cEvRCSjSv`sn(jV6 zEEu^!OJHFKb6}-p&BWh6FXFJ~y%YYhPHU}voQ}&4G^NrgHFC~F#qkYwk&XH>*lv9f z-PuN$Ppp1D?Njpwm;*PBFOB=5Y}*QphbDuc?JJ}3VnpmqaD67cow_fhev-Xron<$~ zH<@1Bt>X;9sQS=5tW%ZFqAMBXNv#&3oeGrN3ncr)-&k>(?t$A53d?97*{0GCHBZ1D z8mPtpcAESWTMKKENp7XbtWA~nF%*cDGah|YhzbxO73Jq1R9 zqC~*qXDxnVAN4Tc^^qUbMg51N{#Ekfqij@j8A{ydm@Yqv%xpMg(0h+*Wc0f0N9f;p zm-f1iPmF!6vTOEfb`6JJ>`BzqlRg;-iC5zai$69Xw-?#Ve|}v@NKF?nc0BowN&D=f zI+d6(eZ;pQwUfnIS%J}gT3Z}05Eit2)T|S~5I&`fP0xlM^@EGOM2F0#Ne~>iWIuG> zfSIGWj^Sdgyk$!F<~cL}I+gmrgOd8AohRGy8(n!3`#Vo9vDMNTgv^iqw@|2?s%*Jh z^}s$69X2W!g~R&`<^{f_f5L&!w{LxvjU)h`v!pX?!;@rJVr7m3FD%_YID4xt^ne-}KV zsgp``S<^78Pud)~C_A@tLX%}kpjG#Pov-76rmN*3uULRIktHc(u0^C+S?<)QFWjVAp z{vGetMdTECZr-42jnzAr)sz8!Y-^eSg1-V`0VLEmd z`&Y`(`;<5R9+x__puSx!gU&9Zo6j%kJY`A%w@vq%1j>Ex$Vd`i%lKN}=EQw|T;85v zNEDeH9nM}Wc>=j2#h|wRA#+LL3_SsEo!kV>mDqjc%$4b*l|Gyd*;Kt@X++wTS2~?` z<{6WIfq6E&Tc@846MBoS&Lr!Z!?WXX22KnpM93#Xz8s>F`GeZZkl0PG07AKAZWn;2 zME_ik4H0tSQfkP$AFk^6^1%Etud5uYc|mpg zyfO;2?FedI#%KA_!!{@BF$%B>=EWE1FY4~E_GS;2+gbejtfa&T7$VKZN6&b}?MSeM zlc==Wh?D5bzJ+1o62a}tdLD{>81^KYb(cIoapMa{T3^x2^aoM{E%2E6*@rax7mCj$ zUPwLYi`c7Q`Ks-zyw1?LrKt=RkMEQYRIhLEb~C-PK2?Q0YTF2{Tv~yK@TQa-Eg^Ii z*(CZ%%*r-JgAcU;m0fDIiW+W%IS@*dw7;{`!EPrsxk?#m;vosK^{-=^nIozcd?>-)nPG7Y`X^ zpR*V+`NU*6tUvEzwq=m?X;@C?J?1MChe?dcJWS)<5A_)2^DFvWClb&o5A&R23JBiV zei0;MI{K3}0N}-`aNgNj_Wss4ogdtMECF&Bp@?5padX!gjdONls7ET=}-pTD5? z5%fR4;`Sq%fUBT2K4^wDrri)4fu}eHE8Bq5#?Of^yrh$+po2Z|N@!{NZ>AY#lo+l! zm2wV*mC-85m}HAorkVUSJtm)wJk>Sgvp_K%;7Nz{E7<$GeA!Te zi^e!ewSP!lbD5UH_erj~mp#crt>4)^(x1oUyp$BDn}#6eP%G;a&Y75twj%46s@s@z zZ%?&4_l#?|i8JEGL7Hwh7Mi=Z7CvwIj5wR1dTOQ;`F*soUBAsB-4JiPd`2xx&R>l- z&dAmNUqzPCTE%2Ds|tzr`n_q;ttbGE5PZUu${Jhg{KZKWl;(pWJkjT{Fo2y^K4)co(^)i@G}| z@);*teVfDV(6&&Ef&ZxmW*f{TtUXd6LF(@L&igy!W_Jmf0HPX@H`Ku|XZwfADruO$41 zSgE{=g?{r!6!Mc~?9#g5Q7!X;OMq+3(Mu__Xt6!fNp*oho*vC;^}|(t8-(A_sLj=5 z`R)J^ac7Wth$0LF4Ix`jb0Ldop^Jl0tS-hRo3U*1GK$N z_))toRyi_iNXe+z;GbLYd^}3{Wi6F7qzY&3OOF+Hp5e}dqD|PcpKX-id^JClzV9!4 z0BClb<=o#PY)F!}`3dLR;3t`E74-INc4BDr@0r24!#{VD%jt%ATEu0F=L$uP5@JGFtHpW*Zj_a1LH z+^Z;M{YM4u{5p)p0>e&%e|ere@|uh^CLy-cNSkJ^D4^dlNFN@U!{XT6YgCcHU~I zK+J8YK4QZJigSLWULObt*2+<4jM=rHk1?z6Br?|$Y3xI<9sYMwDFJG}B{-;CZISJ! zP2ErAhgh`#lK*4>lPX@ItmfZnOsVh6Z=ALw!v$|bcKha}E$5=-=`0IAbFZF% z_Lgg*VTs|4-@GJZsh3AZDcW0aX>!AG2LxA-itPIBQl@=c+a{{SUY_)3mOZ>m7p?NK zZP)wfM+(e=(j-?Yt}ro~vnK{s@qN_HUgW&o(HHHYd@?G5>cdPN=>W|K{eGh7ko;Z% zFTZBj!!Ko=c}!+`s$`O%kG{=}#iTc`FlvYX=_&bk-!Bso#oT~u9n`VfV^i&#e6%2% zj$LVq^2wpb1hz4Nksb}1lJar)ta#}w;3zeL+e2495xX<$-XUnrYmXO8XFT2QmKp0x zyrj*{H`Mzff?q^dN082oGDB)(MV3&xjL&gudT@u`@Wxw{yPTua-#>tgiUjl8mpw0- zO~^NXHg-M-zlZOWyOr6<@uVBas!x7-Vxz29Pg54x_0v=s#c7CinPnR;D;s~wmmD81 z^WlYl=U?{-_UH(oiyqH!@b(!`=sIa-qN?^{rUI~&Bl-Q*Ws-;Q4w%5J?&591IqeB# z1)XIpGFa8#n&eC=e`aa9^Vz)Hzb*mc)ULj!{u|W&*~wa_Vghe*qvLTMi}hW46QOgc~fem*~0Xvqi||YdE8F@%h;!skb|9GN?ZrIEd*>@wW-L+ooTZhqEx zEO2~7=(dM>+h!q_q>KDTeHZpWOd8HK6@y-0iB%_I8{WD9bMuruAwDa8k~NeOl=S+6 zRZ0z1=Imo=J%P)=lCwyCsCVtF(Cxe2-*_m-^|A3x?dtq4O+S8~rbj$7N&LyVcs(K^ z%5y!l-R;jL^-FlJYS8GI^PbG#m(pe`b4zLnnD{at*ME)+p+tT)?J}JtRCg$AB`+&@7qqW z!aBZa8N0F#(VfkQCR1ekN|!)HOx{E0v;_ES8_YAj)naRG7x1x-;gwsl#yh`SDPko| zzldjfm8O+^?lNsP>+W&~#r(PFRl$CyuoKDH!h+Zx#hQI+;{q*()0d&SDI`8p#8thq zBXG%CPfI}rIS*LkQ|I}04P7it&r?p3(heUD5=npZX;1aRIITkoFu7TbJQL|O$|qsF z+XxMW3z*8j=N=V@-_wWHJYO^a?3g19+kTE{Zc?h`50vjxiTt?fz@pWmyz|8AGV#mX zGCO9sPrLpiD&0Tc=Ng;tX^QzNa1M2PRlDf6exs@X!BKHMb|T^SD4v;r=K7s?s+z!;CZwuP|iB@V#9WEqO72xXibKEh@EHY%w! z2xFM^y%;*-8&JHFx69B?+vP3%H@cnOy~FF#^-bG*E3T;r4sXpVL^ul*$F|Fjob5cn z2td*M_fdON9$WCcUHP@54CrL$Yy5mMJrD+GfOnj{j??8^vMb;4r>LH;(dMNFD~0aZ z>(o=2NkT|=NFv>0yMVt@r?Y2=o6Rq!;}nyD*J`T~0d_sQjYYh<9bcaCvx)k5fq-(0 zOEw|`jcdKxPr$|+;3*J-9^;ZgI-Fc#!T(Vv1=42uUBkWgzwtvnOR=VY;hPP&m++&g z8GT(fGLb?@Z-ey)oB56o!|bKI*JE5~S&2}>lpn1h;dghw?!Ekl??}}nUn7d)9Dbn} z10U%dQr=9|vy0`DQD{-C&cN_7x>0$1ujUM-U*_^d{(5Ys1`IbA`#D?adJAKjZY8X0 z61|$<0qLzY`Bivll#OB{QZceQ9W$(Ew*BQp&Qx7n07LQ%KA@v>yNm0z~ zFj0E%7;T7Zg{z8F_#PCyyY)M5n<$0Gdss|z2BZNm8<(7QzSoi}qzPkpxyT#0+=lBA zo$fYbmIXPE3my5cUCwCt{>0f;U_yzv}lSI_2bM6?LFPORvt~_K$^5Ydf9%lr)QU z_BM0g-w@CIiloxZdCbNBP}=QfWp5GJ^`$YBB}FEIU}MSed{kqd>C%c1t0DHS9>>Aw z;YA~a9z%RSaLTeEcQ9isBM@WgymZa%&jzjNuVhXN6G3jx-QgEb|3=U;yUlkk!#Fkf zl1if+R8slwDt}F``}%5d)U@djZnDuUA({${5IG0rcx%k;iFpA-E@DGc8O<#*9cEW* zhqs^~f#tQ?jojzPQ(20~qE?S@t5JOagLUK+`e)|$6odHf?aXWYZ%s8YtR#IPuFzSF zJ3w8(*Y%&&{8LDcPJKexjVx?}Z?>jN=(*l^(dO*?nwQrgB2O`z_y_mq58xVJuNDHE zzaE)Ri-mtDEumQ~sMc_Zxrby_3+TPL58bPiE>)il`pmN&uD;c2xnF6N>bt(VR9a!W zb&a>k*ec4VUnrbsaj!(XdV|za;@ZIdDeq6#(!STgxtieMnr-Gc&ZASG;3m_9cQb-V zjiCyTCe#nEQx6Jc2q`%_t@iMD)xY>$)-v}=#&2GWBsk0)j&VXewkFlozAxZZ@q3rG zI{SQ9Cg>ldM||6$JdXr#^*cn@{lZ&b@XK{^|HlI{CRGY|-@0>&=SNog9Id_&Ho_ZM zw?G8LF7EH=v}%Iz?CP-Oa=gX*U`(i=Dq*qw{8>o+s%D=c3>yqo1hA0w(l&3@qwM# z4foOhdG0)Q%kBV})$+;BQ1kzwbwge3Blf4ZAw|?O&(tqQb+?~vZ%6Yi9ED|@{3i`i zUWh(29Qco9Dn^k=CMN;d{>6aI6yMPB=Ds@MVa=U!*M^Z;8R|P_`eKf00Wx;Rf9`&4 zx0F?uQ}+hNUW~in)SL>Wi~Dy#@uyuM^7<@y-v2$HN}K?dKC1(nBC8`nJALy$wCy=O zn)GGQ-UQiy`8^vZo|ImCxFi5s@vsbShct;mJ5XhY*y1JA$&h|pI$l>)40*a?x6M^FnHzsU9R0Do1EdfkxL`+cCrI z;=}zBG8F&jI@|IZm*F=$QPMpS&nL~IiPy`pl8dym-h~vofr-$-!xhi5n}Gj8*IWKY z6?T2!gp_n6Eg^!0NVkZ9ND3m|Al*4IfPi#Kcefzj3`2J}4n1_wFmyiSd4BHu#dBZR zAF$u-z4kiR@mt^DT3e>YPwzL`?mv~jTohD+=?TdAJpKZ5TnQseZhIw$NP9V&4!5F- z;XL}`@yzIYC=fW`ITa>@#GFkt~$^7erW#Z&t1$wklG}=D8t29?h zQyhQM>*Mbm`w%EUUGdN@#QFSU;oSm0UpcM9eZ7aX`OqV%PnBzCUxIL-%_?>R^ryw! znSZ-6I&^T84fuSXL!Qm>oZdbE7XRBL^~82($4SgW(X-9Ro9dkzyEm2Od%d2$I62}0 z(k2v{EyP!(ck_h)(Ctb+B2mM|qLwDTuQnXqJ{!ZQC}Q87YnYP&Xh}t~;R#%IMa}uv zb76ccpI_Npp;rjS;s77bnZWQr87^k0HU_ubv6~5=yJwMybT{ZTaNr~eM~>`sxdEu9Q?M^!E(W)Si=I*6rXIr5T5j${N{EG0|)21{s5Q(t@8Jp%A1plrwaflIGU$rTw% zDr6VB7gd)z!8RK)Ot^3Dmm4@eXnbL~CzTYJe}(lCADtB{S-^B{ONc&V68%N!gB64r zFMJJCL0q+PSbVGM@1m;xjZs&*X^K(g=MDX9`#f=(+$FOz*ozYpD8*(gD2$YhkHEUVpPTkZ}= zl^AJ!RACI?)@Bf{j%WXUR38@HA1G=QNyAj`hw*jEyOccKl2!pcz)lFn>52@L8F0t08;c!8!S=^QDn{@* z13$mT!)fuL%{KxuV*l^C9vzHCy@t69uh=WMjmh*QSYyeQH5-zrh%wZUm~30Z@vK_? zA{wGE)Q41?KDM^Ko*VexQQtm0WhNaL4)oPuxogsRm zYr(c3L?HmTqv9X$BXGyvsFeXDfsPD!&9NYA*fq~^!O?)xjT((nBrvuP;u){c>kow008#pmfBwRR05FFlYLSiaHVn6$=8JIa(WTGbBRALITL$; z1OEK>ajyk6_Jbaq5$?FdA;E41k0fkR^UT6u{$A2Z&S4hg6XoY99I{w~#X^01H_P)< zk#UGlux~k57Cyj8wY*KZIn_fOLRd3pcFX0L^eo4VK-`&j(!uO6W{F2v0^6H$%G_mZ zp9YL~4zMYqZPJVdZKGwuiLXNB^sGUp8GTK(S&x|9UfrqsXUh4WIUW289 z;`63D$6ws`KmF=2Gixf+J+@;7nVd~u#@AOK^~4m@9CIHGC~F)Qqbt-KQ`eHoKKtew zml-wuy(T_Pw}h#=W{JDsRLx*d4PGeqOuY3pI&fQysUNj_Io&8QLSCfj2}SPgy0m+aw=Ohh;h@rN zm#V<&XpXuuGAljv`GVi?mbyB*o2i)2FvsUmJMg;JdOuI|)>s4h&L_*Vd30;I1!T;O z?3mVku*AxYCS|QH+V_ePw@tHeq*^)@KQ8{2ywaylg4>qyiC)NET+21ESRO~d2Ts^V z)zY%_B|!M&Jg7$B>t@5vrfH{V@WnFD(#l!7ekNw= zc+vKXSf3fXbqA+Nn3pVy$3gy%HR1;U*VzcZusIA&xw4XsDjjX&zD1?%NhXf z*Ns{B{%2-C|9*frl}>T&L@I?XhC@upXx`Rjxah=VPs?&gBgmP~}IdyT?4KXkx(@i9QB#c-d7d!pl+-WOr;z=XH?(FQ+BUk+_b z&Z(UeV6-E8?NI{pE6g|nZ=h_>QPN5kM#mMz;Pe_j0OYpd>BM+&eTn;B<*qIusLGa> z(8nNs*U3&8DQ5n^Vo|lf!`em#)1XbsYJa@h_sqWQCevkEuNl)U7?M_HDhKq6f2SQN=tyrDYVCdd|GG{YQnuL`NaOa zvhM?jrc1UI_VPa?OtzzgvfKveIN^1J@Z;szQ&Fe+C4T`gAvbR+jO;^?>phnqn*ah7 zR$9OUQ(rU18kX#zW2j_VB6TSXq$m>zeK=Hc_Drn~ik9*eB7OThioy9E3^Q|xrY$;X zK$ZMS!}aNkRdDasAn@bVnHJlCI{E*j?#a%^=)!6Ygy))^}x}M+6Iq`(W&cf45^KQslUVl=1S5zP2jkJ#@ z$8S|O*2Nf-`-1F5kCMa;R;m=kHFiH^ec#3j z-@)kS$b4q@F!V#gk@sk8ObNV61M2L?)eiBFnh{ium#XP@vNoD_OH~yYwu|{I+M{jg z#D@BEhWI`;_VXlBz|2^b&rwAjC|!flj6UrV#(&?a)Y@pfT*G~_crx)Ho&q!x9wa5V z{tDMQ1o|&4zC&h3|0{p^+FJES1)66p(;?a+M=BG0^Yg0mtT9VoJL|iUdS49#!b|>& zGuFn=$6|F;=I3i3L8_Z*2f9MEVSnc=0Rnk_ca)^svGMA(WgxYwm9 z;q8wSeYs@E^nTpXMtn>ubAE1NGM?b#Okuh5re0prE=4Qqt#r1*Z>w|_H$m?ADkADi ze-c2?CgE%s=aeEL)|Mvz#~_{Ev@PtEjK+Nu|LsH+I#GFtbxuuvI!IZQQC14*T}SGa z&U9c53LcP3vG2x>N!yJO;)eb6#ER%_sC*?oSuc%B2*`p8M18P&K6Cv}Fj0TcuT^>( zxx4#LRmnL1UK<{_0oMg=mbcvl?SzdaLqbE5B$m)W607YWiS^eBnM(+->7L47>IW?l z3n(BabJ*Vj5Ej2dPWb<>e+gRZx|k)paTF^Uv{VoX6#$Jo0O%qg@^9A80V zxlDbp(Ia>X@tJocm&JWudSf{$6Q~Ar@{YwvHw)-Q zJE6*|ykw$SrZWle8$vF_V?11n_j&}BxX>CQF>|WceJVV|?)lVaLep8snQs(vatcXF<#fp0?9M$3JKkw?@bA!Q=zh|J-1`|}Z zP>Rdy(-`g}uw9Bw*B~y;RcSMTyEPO=Zs$t*yf~AsB58wtAn@a-@F$#9>ROi8z-zlD zu;0qtYjdCo>5I=Rxh4CKPFcYEKSiOhkW?GcOL?KA6GP>w*cMyGZJ5!}Y(Tgj(+)aVP z5M_^E+_=unxvzyZj@kos?n~^A-6@sFxjyaJ>J^ENkJOHL$qJVDhpRA}+e(nF19H;& zyz67_?u))!%xtyEZ2ujAZgSbipj$4JDyO`#Ry*zWEHtKWlP5z`XF}kIQB1U7oYu_m z_AUxnv63%rQAmTFono6y4Do^f#cB(&sedSKUFF~k;jQ{aS zuRi@v?C{xmTtBlOd?Oaw&^+IA`_CcHrr?a6wTV=M;{M^raZw#o!y$+|WGOAGuC1Y@ z`H}snX5X1*W@kLUA6Gn=lC%?-3s(BUD5r0u?$@J6ec)zqoqE@G^W%X24A^uEAqbe4DOEKt3lfDfK8Ja%usJ#O=o z_UZsB(6iHp(K*xbx)DWxk$Zi~rI``8co?V5fKMY?l;~6#Mm;=;ITBQ5@jXi~S^z3N z5s_}{ZW@=G|F*(x8P8OJ&i4IIP|iKYZu77`P3Bxm^_*-uGkyHaDyfULW6aNfSe}*6 z|3RvqRxIs3&JD zQC&HH94bdg(#$^p<7Mg*fiO{%fH(bW>8`j$uhO`C*tz~n)GmDfvYu{zAGoH%zcfJT zw{T+^+}U}pclhz3|B=+IE4L%kojnKS^GggW5B~a^?9iLzXXZ>uRqki*q)m^uY~Sviulsk;acsVriMHad#mD)hVphR-MS;8~ zSjv=eKC&i3GTslq-Ykz(M1&CBMdbnhx943Ltplu%AIJ|yl|ek8yl?F>&TD{Zr@8>X z?4{u7(01;zZDg%E5aQ~xkvo7Lg$z~N|0Y%`d*LU1{~}CT*L!j`*?JDhFL!c2-fs<> znpN<{DTTX(;zIkF&mgSF&RjBm$`AXk zB9Skrb@(+THXWhVGZ9{i;K*|GB8K|y15|*MO_i{lJKGSAA7Ur;v5!#y^o_t7rtDhT zXD99!BnA3hwG_PyL~|5XGVA{N*4RaF6?^Vx${{$ZFX=3#hHd<==d6rIyaugeU?|iHc|Ms4)d|AO|PKd(;z_*il;9rltwgz*2rF*|g z=Dg{4;W8<*p&!@YCx_>=D3BvcoL>J8JV);$1i}9;TFihT^z#rFzbw}b4gX=UZoa<6 z0<=2oma`pS_uW1=9>aPWvSu@R)jdOD=whVhGT>H@w1U}wbaX(rf{wjtm)UmzWz)L< zoczGE6QAqfLJmJm!&6>({UIIgt0a}!twQi#?=8g~PIGc+>2`l2plU}&E5;#3g27gc zBOao;MP}<`_Aq<^BlM=3ZM$~xUOXx-1B+CGv?;iTP?lRW2kJNX#A5ui$T-w8N0ZLGVH;VSn_8R z%Vr`AP78Snqob;S*TwwMlpCOIjSos7-w;(0`I_}4Z%#|xJ&uaF?`CP4uZWSH&y>+a zbi_()Vy=VX1lcJqWE;Ka zz^0dIBOFaRle{oVYmv4sJma#qJb`8MTUzD)SG=R?*fSZRHDEn=e=u$@GW+h?YJ=fK z;$8Va;AsD?WLcn&N&8ZeC;LC)-BI$oD|Q)lD#6eU*sj?CHlh1@J^iE&;OuR=R-`xw zoWYR~UEN1_YzF(XvxgD-VJSrDmLBh$X=t;j%=U|xeViY1JB!au+Egyi4E6P?HhSq% za`MT%L{~@EiQAa%Z0yJ~>Z1UcToUw!^fedPgrI&zr9`ta_boVVaDXgRGS7kopkd~# zT)_3~l%-`S1QE1Mta?Q54=qEom`qi>VcJt<_5oqcuY8x#lHI!Gf>Znk_vsgU${v>~ zOgDnmc26vcSLWS>>3Ya}s_&f4&RDtnJ+cU#qJ_q5WQC7@{3Kp()ua$##j2<2=8{Zg z@RjE`WReX{>O;bMww8b>}4&r9HhRM+j z4lfEgwI-CQ)a1nbG*Tgm3o+7~iAVfUmOuQ7Z+{s4+eFT|WuB$IB zWUi&XH?TP_aOHP%^IyGb#LUaf3;Lgn)c(JVl!y=W#~Vp49?k+w)ydza1q5E)SNvn* zYak2*%6AhfzvNAHC47f{N7~9MaO%1W)~m&uTpe;hnOl|?Z|h)V=9e6HS)LI}B0#tS z^-7QeZabKajDNfbT8k6zg5DiE~GG~8r-~tTo)h)4Zr#W*!Yw+ z#{+;?ud+EN=eD)cf&0sOf~2$LZ`0!S^qz;JRR@2PRE=18&qDb5*EQSvMiUw1{GE7Q zuVlUuUg1`RRI>1v$p8)V5=2c&f8T&WTDn}yZaXHtu2Lf<`&DgTQ5H)T2gZBcCn*+i zeI3a1+c+f3x-k*_Tsc!MoCVyvwz`vb)0^3t2B7c55=UEyn3;ZmJ3fwf9d+yxsT58H zRQEOdo}VwIgxR05-2~Xw)4T>7p6VZ7;4OF~<-00H1T9hlMe0yn-O{ndRLsAEg#(e% z>P+QNwtRZi2yvqCz*L!X-EcKI5@h9*b(l+$*%(*%wr#8ZLs4?c_s~bb(m6xom^LmZ z@s19iG63Y%`n1ui*<5K}-lwufEf~297Vht(*d^Hdt!jX)NxMHTtB!v`Z+G#L5*;gu zKsZYzRY5;^Gf?j>;3KYwy_VWo zi0On38z}35OIZl2%fEEVXcP&%ES6F8j&1p&NV>X_+D#Bk7C)~*Z2t+SCraBOH9E12 zfujF+RoEz06apENhh2~495*wsr}JPBV0PCTT{oXFzNASc;CPj}gmiBNNAB_H>D9)T>5=w4}Zu{OLHJ*FobR?KSa`?x00&C$S1BeKdV zEVGhyandmkj;VEySzJYK9bIfa^vy?W`Y(9B=meG{BVP7E zPkYm@m{%uGl@`-eXo!4&x<2x}ubvcq?suj?c+TzeZrZ`Lu9QK(@V`#@$jJm)(bG&Oe}uj@hB-K=&jN%M{G&VsPm6!1@efwl5$xAd`E6y zxpg-bmP%w2%^Ha%(AlSZgN1u%!saiYAxcCLe;t~?o;Nd|GkROU&fK_ER?-lM;T0lE zR^&ALQ#&2T{HU%X2_HB&1n@bxW$uF$u-rZ_Y?!gp8yKY^3Z3Is#SWv2eE%%)J#f< za|)7gq}{h9&a!TO|3|=s(8c~RLi;mZL{_P$2ZqOxchS{CG+bD28DUAQ?BAcy;B~8W z4NM`&zU%70UI4GsARz^42*M1^40a7WRMl77pp)J;kgpF)rxma1F~U`@p&7T%Iwv)0 zqwsOzD7v`%n4|;sf|_9S-_oJ~tW$uU|C(&ppbt0u%S}TiHN`sa_SVlPUY=rT9KMbNDQk-BZ>I>O4H zh2}Fi!LuFoly=6#tA7fhi9b>@U`Cp^*lz#T4eo|WDV5=m;$4Dg8D&WhsC@jLP}|#5 z0=ok=%4gsASl`z#UXJ2BtXt2T1i-5|D6?$v#Rq;jZJp~=b=?A=hnbIG#r?dDS|tVU z0P2h2GWH8WBtyopF?j$J+dTwec=4jyp@>oYWb&uZGQI6Ts?pjDFFb3wC0dB{x%pcP zuK7-Swf)6$u}rt=j5dE-p?;L)R7zF+E~RI)aP5eo8y8%Wh&d*NxAdgwP`i5&Ox4Dy zhHlZSaiCE~PE~|3C~~qwV5lZLnVnzGiY)$U2%W99xZtWhTneyjIov#>Z><40LqlAV z&R0@Xpy-6KWd-G@W>|!w=`5XghUrRk5LcdAb*|qb`U;anhBBGr0-G^OAqXt_HGu z|34*O|MU9Y<$JBQOV3m1(7H&NE)nu>_TAtigd2oWRJGc9V@~fd=PLb14uoRqTq**c zu@CnsIjCyf?s;=n%>N<(v5pzG5Ly)t( zad^)?Cr22Hse{cry9zsuNNK&eL?mG5Y~0Z{}S zvf@~ZHrUe`Jc%3AH0G{L)P$8WgPKrZWQ-ry}Z{kLQ3K<&L3ce08za3{`hb8_lR@^7L^+pc-- zJNgC*4&-L0Y5?~_6vNJ+iRB#py(nq*9vX6B9&WCGKwT>WG5;di^?!-rzfP;m8^9bf z0`{naRA}|HAXVO)+*Tr90Mr`0V* z{935$V5^Vh}XTW?LgunCLd=3Q|yHjj(V<@st2c;JC8V#+JWkB_%J&HTJ27xQou?Vh;Q#iGNI?^rfa3643cVI(K5>HO04gC zSVT*^hLT=F{kk%b_R!nfJ%cw#b$#2u^BC4h!Gy={52YuVdu4@K)vAI17&N6FyC}-0 zGM^`o^Ohj$%&bv?3MJ4f+3=deL)6_*!gv+0=@@uDuzv}&P|j?q%XXYfXybAu8yF{^ z?C&$$OGKw@MvFAqpIj0IR9Bi*4_^qEG=f|(QDXClXds>~+!kMxc*3Qe_b;igUYe1K zKH9T|!y5Uj_|)!fJQk<-`zMA~pR&|my%&c4#W%`Htt)YUpgE?!if&Hr9dKa^nOwHw zW)#}wseedxffQuizOFXfuAiI8JrQWu5Tostzxwj(63`Bsk~Kj7>quMX^Z&FF{*NuQ zmPp=dC{U7M^E5W+QhxvUVkh@N%`QA- zeeBWK6=q})33ZE$bg@}G4qXlDxJ+WgwFtPJ@H=Xy8E<6)oHEC5YZzQ6Ywiyu$pm9&1|MN{bUSl<%9)JJC?-+*>Lx(@+pbR~kh# zbtzMh@RIg!qqqW!qzCrsX&JCmc)64C^U@_J%;@gcsN*KjcJ;+tP9c@2Fe&q^A6w(E zVxF&)>_)s$EoH+yvg5Fh6s!Ehw|pzW(CGIwLT@|Ln?p@+dVdzZs(>db`8r|7@W@0W zzyeeNgQ-^Qy4RZXlkpXHc`lApnzd<2pj7wEpNjvg5UtIggL`BydMj71Zr&!mM)P_{X|CG^Qp0^QP`;hjgsO4cjcXWz85 z3ofn|JJS7F4++C`Vei$hrBq7N>#~KezG3sP^5#`aYqEGp-F5@seJB-hH2dXUy=U;6 z{}h+lZcEVBpi^c`jXv7wPzHjm7RG2GOF%~Yiz{m(aqRgAI=W=+496^#pCh~(*IPk!*j$4V z3A2x)^JnJpSC0p@QOkck#uF9;CNG9_mWI-hp!BL=C?9;eUmKt?u}RCy&sXI&&$_`2 ztOskp#^Lj@!K>X0I!6_t0L6r7>@zu{Dz#F2X1?m=>i3ZtRrzbBDMM^8?WFe^2!92$ z5-VO&M2$jivmdEVYUN)3QS-r#Io8k*X5nAu+v9FHaZYZegec+oLrkEzu3x9PkK%G@X^)iH;Ko)r55c! z{n^AN%dftQ6cm;Wb`d~qyxu4weKXv}&3sOIF0aM*DWqU=MO?bCIy7lQJsUReQ%}TQ znB2s}3z*99Q|(DYkSoxtL1wGrliwq=>?^XTR9FA%omI4`dk9es_Q{dd-Kop!*1VlH zNed(}yVHS2nfDq+#XnOVa2lSiHLdIHMtLGVZG?j{-8O>yhUENqV&=-%ULdDtusLD} z?#9H_Jd1Oli_?3BQ)4TJ=vOw{p?k6^iN$;~ERv_U-Ki&ZG_^q7(jqxxh)DwvdP|rr z^nrK>SwNk=x*_|lk1KkfnkQD!#Jp*t9=IqFTP2_xFLW6?eY+g+(Q#pz259iV;aK-@ zbso9s#pMlsy17E}1%lD-GRpK+0ZY~PUF)&U+Re{weuG@}i1saXHqs>wEQ1TEyLEhI zd#*~o*mvi#rk!1&d+kr*;Z$1O7g0_;vtXo};UJWu+?FMJE29$3P zakmz9jm)$Ef@(AuWbGX9STK0$Zt_ubHkU%t%1|I|J%Nrx){2aVzUd9!-}{-XdOUau z9JB5{G(KLEw*5X?Slv~I(u)n)JJAgw0GqSN6d((u}@_fjjH&$I{tlW&!m^2gJRiI7Kx0ORx}`RrzH#2+Tp zO@~*0aP606%rylTV4CrAU!^aVkH$27u4NW)VzQU>_DwyxjgCeZLLMPVHG++ue?l0{ z%oD~YGv$_~$7x>{o#Ab*5R|7#qYUY3qTyS`t@=(Q(&Q!*KltU&R=R~d(wYozmQSFH zg+G#T&DC8RUeG&KkWazSdSZ|D%^#Z@D;8@gn$!@ORbk(Lr;P|}gsU|vj~N|~3sfHc zvjZ(61^54JUtw_iuYE<2r*!+Cm(6F@;*st+J2ZF$tuun3f+jLlg)015NHBd~tK~MX zWyc55xb)KQs+sDYfS_N#&;3_~!^FyEH_$+%L189YVXE#%g+Yp@%~a6k+C$Qrb))8B zwnL1l^5Q@TR!I!dpjo;tP_Z(&1uqz|8mTN44UrEl+-#z-s>(gW#8uDO0WYJ?q@W`1 zjR`?9{%*3{f?v7uW?P)+=H0Q|N*6$SeX&I=n^H=&#ilE2p!MEHJSPEi-^dWdX3>|g zLXN-JH@OTLfWKudhCqui-0E+C(dxXNYp!$O_m$jGpsIn!2+t%mmah~Czanx=RglYc+2v|PQ)@HOt{S`R9_biW4#Lj{rQ+Xo@ zDgTnUy`2^&duE@zY}Y2s^D&3SEDDpJ?g1YUM9+4%g`x{P|1Oq`t;=o0c0$^M*wJ3( zyG0KmposI=99<9qq+ubIjEL<_C&$_h4h>?2pg zxQoLZ)ZRbyuv>A^;nfHoeXMrnyWK<19<$skadQt|@Rs1~-|6n}0TVN&AVr`53Hm}} zi3@A+_7S@A5{xghNv-pmjzwXwj8+wY<)=VjM}Q6)X9cwZ>lb*@l8rIE&7z-QD~XX}W;oPq zgPcD>UOjB}8KZXIfAih_>uyA}dZrLTecsE?OCem#<3<(wZgS_79xp6U^+mFBebYGvM10 zwBRrV+>)=km8UeGtEaz1gf`t$v~c{m!=Mz?T|5lTl~m`+j{r7g)MD9MI51eLE@UT2 zwCQQO{Osp55^^-%YCi~Ys&RZS>6d#^LM<~B!DVnxg+>f6v#3z?W$xVtoi=EVAm>4_ z^3e%RV*TM6g2Ba!J6%P!JChOmCROEkXKEPtRj z&D=)UkG?jrAe_I1k%mi#DMMsK!ND<`OjxcImU-@US{SR1%nZ-o?+_qq@}$E3**2L& zR6&o)t?>)VFJB}Kw~^^WH57hLusg#m!ZLs@p7;-d80XQM+=XsBc5H}8*iZ_2rN^f@ z3z+meZoU3R*iIcrO;}ZIS3W1IutZ>usNuuaO~-%npp)cUDRA#={ap7)rNKt2sR8Wk z%xC)d5haZAlwU&!t8vHqgUNDX(HUpqG>=w4G#22YR>Q|tZX-J;6jnK|MX}s5lz|Ii z#HS5q6@JzORxN_FtuW7$07NeG+{iZ@iu}M*RsjX=u^!E=>_nppQK;;vz%cSkKM5x~=Pn0_p#gVMG% z!U#X}Q4#`oe0L0gZpa4#AXYPU4vQEI{C<;7W>z~u(dUl7Zmg$~8WL23aI;MJe=tc8 z-8j$FV+ImTLQcjU^YkUvhsr7?H$p8%Qn-CLM-_#k6<#9)90S~vqC#7q{R|$xzKbap zRl#6kJHcbl3&3Jkw@llVFx?*@)3}!4>YL7u)@Y8W3Jex zYFZip0Ka3PvAom~(WarTTgGgNW`6FM!({aiw`=kGL z`b0Zmiqda>QX;z_nXJ>01Fy1J*u8B^jnxOg3UdY4(XL|3wgi&R7r$}52*hnX&JWFA z?8`|kA~%OxDZkX!7jKl&bWLyeLlU7HQnEeGlO}YToCT|7(m|6YpCIGLzEa^n`rc{DtO|>e z&l((IU`SN*kpy9RK4ErI$q!U{g%}0cX5GkE!WI{6guE9O92xkGAmI01;n}eDWbuv9 zC>}ZIqPP0n#{&-rr_mAgfssT1t&J%|VNNidw`dExIjcSf!|&fdc?X7g$E3K$VQIPS zI5{!Rs9-0Gs|{DZ@9vlLo}I#FLSGWhH8^r=+^i@V>y~_LaYiS<OGJjkP zOf;Y#y#OfjE9W57n*N5H!8{B!$~%)8mzIWVC$tDiugB-U3^!l(9;~mATngil4!h=WTC{fIt^Z!c5 zGZn%tIcLl;8ppf!F)6Q$HUR?v-8b3Jh$JJ}Y-GQATlJIANES=;pU(q9(9-V_e^pj* zCFl+NhEq9dXnqtuXPIDuXHibKCy3O{gZV{vBf=URtyi!@Ru%SbDd2Os4d@2rER#1O< z_jp@ShQi})2mbW7+qK2swOetUHcW~(9>arygEIGmsCz{@^LFEz2S=NQ?6_s{7w&qq z&|VYjF8)|xc#hK;o3tRD`z5H>vNfJ`k+bk;weg{UufJ)Q+1aP7p3to^SFRzh&C?x% zLiZjW-csjp+-}RW^m)$A?=}v-$y>J+&x{8KzHgy=X9MYKW3#-tKMWRQ;xI6OyjbYZ zkNlm4a^mWyBwd!a-lSui@AYX1NVJOij#l`dNbJ%6yq2nl{*qZLO0{AeRZ8YmPz5gb zaJq$bKxNU4r}*Uu+JgI?kqtdFWD|M-d)en%WrL(I=b`#5!yVVLlSu=*_xm^W2Ims4 zgxR}u!Z1^rsYQaC`|#lp!xF1+6|8T=*1AfZ8GehbP^q3q=Jpm4Sj8m&nC|-dM`UT% zB|NPpbkzlsy=xI{zk%oGqels;q{9(~UCQuSZnGvs@@+Zk9z@8#+ONpc$ zt}(a{PocT1srLO#Fa>k8+GpjgyeldiL1pK)+?+ko2q=uT>-p#v!XcO}ro?4@ujR!% zmC>!2y37<4AHjVsD~VuktZ}CQg?FiOxsv^OOx14gf+`7KPWH_@*}51-W(|RHJ|o(? zF2rnD5c}Z&$<9yEh+;`FHv$yOFAfTIRVzu6TyMk z#lNx=G&aTuk1@^4P+Lk*fC@a6!f3V`0Vzt^UNI{7h(z^=S9z6 zPY~5pugcA|Oh*zQ!8)yFaEVHO_~AO8Q{s4$3o(9m&(Y2$6td4 zSHCr~oehiV60pN{WG#9b0Fl20XPnVn)|Z!E5J8@L<_r3P#@i@QkQFaMF*039rlzMSHL}KwC7do^h z52)TX&(nQ6d}}a`^y%`vXz#hC3c#WXu>GT|I$wnJ_8o|NSLPrZc6UZ^cDFbXW`?Kf zYT}6IgPu}S+zAbe5N=C`L38Ub3*n72Gv1q>&&RB3LpTHTL}mu>X~|vxSlTIy18h&^ zI%y?$PJ;)`$2X3p!FZ5G_nbPp-sBs@6Cp5k$zbWKUfHNoHimF-1=$#H^Rf-gqU^=O zL{1@$LAVTjNfkxS@(|1fffi$bZ0z^@vBc?QrC(audFgyo4b{GxB)7Yc-^F?6Mq`nw zMQ2v|-afcDuxGYLL7Yp-c#l;{vfkh-X>mHim!F`0+3tZ^J^QC=ZAb@tUyNaUqj%`4iKbtu+4tFUM%i$pRyjV-#L6pDEsTgnT-T6(JnFT4ucVGFkt)1B_UT06VO zJqYjFR*LKQLm}_mc}+avO>3msuSB6XRdu4O7eVwH->&$M$8dCUB z`AC`dHjC;kQU}p#ELia~SyAGee_Uh0W-2K+)E|57P~0V7!@PF}CrAORTG1CyAoAFT zzK^eNG#AbBSl$_22k7175!H%r z+06X%$`;>#*X}^Lqs!u6%N?EV|3#qF?X1>1Z|8K5&`(Ru>&E6rq#brGBEaz7f@P(6To-Dv#3 zRnMe`UMwl*9(G3F@yhvOWy|@Vov0X29L*Qe{TL16JVxzWVr(*N7}ZmuI1ZmQPet$-GG>qrp# zadnpK2UkRXCl~qqvIpyF)}i%G{EbO#Y+nhdo@G>;ex$?_cxC> zqhed3Oyrt`oy(Wr{a3$c;y7jful_i;-lS=@Lw9hcF6T3z_GNQ?5b->Iz_o`gAaYi| zey(+DxbH;{Rk)yk25^zMm{^L+D;p1xK>M7>`jAaUu)BPw&RcJo3r00V{SY2!Tt6;E z7F9|T36m9qyNFLZK&4FEhL5#*9ov~=aUb$L{ZE-4S62auQbfOp?Nk4-?VE`k`UN?L z`*JcM;&kQ9YLu$FFgPL$?E~##K|3wjjHTTfJ1(@>H~wUWQFV(96ue@}+2CUvGz4oWBWI2}0;;)zQcTJcaSEAN+rJ2V5t<2tfWDG~;IU zS_Q@TBJw_dYr}jzkpy;2{1ac>|DaEm+vRHd@`h|UwjX`-8#Z9O)qR#nc}u)M)6F?X z&KrrUJ~pXt3r?~cAF>hXz0Hmkh+7gp<88VsT>B`%?9Rl00c~`*Zqvf5i@E+#yryrd zaKID-($!6Qyl+@2TJu4G9*|1{yjYDm)PGJn$Ab2MDNZnwF2wv9op#`8kK)ygN_w;6 zA%8YKwn#&R)M=8-fJ1)|urRRbRt{k>AtpdI)sgA?kJtPd&n4@(7li`^0qW{XZl6|~ zU8^i1`UF|%waE|bE7c=5sx4{fo(ol$=l)5}3w$F_zT2o1=b50OjsY4&b^6!k&Vo5C z@`Nh?A60Mt7IhzW3oDIu$bhs+cStjobc0Ga2uKbc!ywY#C0&9b-Q6wS&5%QP4fW3b zJlA`jbN+$v4>S9-W9_xql9-NK{mPjQ1gWB<;moyvF!+UB%g?t!fPY#WL8z@0VrrwD zakdeN=~Oxp;dCs&AncXpwLI#xjyR6-ei~{1yqYxT$zgg}(>Uq|0tJ&=wJZSIHV?@R zSKg}rN6styzsPw`RtTe>qZbknLGhv!Csl&{O3kyoz3^{ewpDIDJG-Ri{G+I^MCtD9 zjsA9i#ct`(gy}no3wvZU!R5sR)Xe3+G_ffW=o2t|e&#*=;_>CEb2LaNT)z|z=&a?n z53G}~xJh5vBj*#pO%QN|uL`VyVbavC_tWCnhDTe%KdF)2L>s@R1I!hEoxXHFIIP{5 zH>`qpc*Vh&;_a|B0nX>VLkB@3&Vkh`>IjDNP(heul-o8ElY2ES<2!x!A)#4h*{PLvH=S2vEB$>RUhcL%BV}h1~a8Z>^W^0wp#2Zwr~WEAjU2t{V{zV zE;5$B{-^c+jKdKw+}J%?n}5FjTlBq>Yx#8D<*o&?q`49DzX11`x+Ox6izuKonZxl? zN*00r^N?e){WN1^R2D>U;afmTDp5${M88sFMqZ3HwmS-CO7swh%154O{y#2QfnxNXc&6{JiL8ZhFj|=ycmL$M;dP&(2(20s8M&gSh60(#% zCX=B=R1oDryHV}^L=pGyobpRV4p-Ln>fnm)cZ0b?DO~5AW&91GqrxvIC zAy)ac;pDGT!35VNNA>QGmnZ5DH|920hqsh{DT2k^TS7ZhoQ*?_R-qT2`elt3-YA=e zoM5N?NeG?eij*tJO3Q-Nz|3DvZqsILk09&2jyR}`@ww|;R9uGM^~IDgIP+r4I8XyTg{I_&q=XBMcwPJ`u3gLbU@ z$KK>1v=cgnYUlc4l2{)w%X@b^#^qU>B!mpCaMMyDaN2~2k4viskC7FqYldMOYD z$HV}00hD3e4+=oDuwff5ZObB?cQyTwRPA#Af00i-_>m5~pB;Sx9)A%I3ml*G?+Tsl zw>jeJm!Rw(RR&MB24_4M$f|vOzBuhWH$BraD#aAJFf&mKJ%&C(Q+7aXLO#nBlVa^x zAS!$HW)KdwsGyjpas(=dQPeJ$h4mIKz31p50j_v_Ty0YO6wNoX`|Ow&uNF(u2weqa+4D>Ji6}FHSO4b0D4}qxUfXfwr*5s z>F2`D2O=MH7rRKCYRf&{4??%fc*Lm$u)w|?$NZ!t9Gc@DnGTbX_Zi6U+;4(Vy zCth?ey;=rqj{{=^!mh_dKG67q-2I$&C$w$Wg49`+V)iWGQkvlSXOjHu&)9uqB>rx8 z8XwyEO6>`zUOPV)^2@Ru?iti9)V~e{-*=>1tz86{{^K>ELU)YyMX(`ez?Wkl?U%de z)c2iVcFBD@9v}a=4(xD?ih>U!CFaQTjb@_o4_l8lCtSGPa)Q6jy&ms7>n3ZhnqOfj zO{G-ru_MF9wl#XAulH1#znm~ z*OQDywBN#>epe*|ongDLJM8N*Ou6{`z45KqW&)|AV(|l~bKW$lw|}!<34E;9G||4p z-tKWTw;yR+t6~``_4H}*?W?qqG%YXM&~p^`k#1TKXXT^8fchYSryOXyK4B^dG|Xli z`S1xbO>^*yC+iSZZA+Q0bp4?BoKzE!<25?Q%IND>;(h!aFt7m-S*&f3dWWVxP*T%t zl{-_U77^Wu<6bWdR7eCfZ7^86?JJN?0yA&Q9pL!T#l9+ zU6-WCv>vV-TDFJ1DD5K_$om*nHv<^pM_Cg?t4Qyz)@350KwTZX5&8rPt=c^sgrNH@ z9+g8Kz{;=Gpt9d|@`mK_{gE8f;p-&XNGAK}*X#08AI)6m65AD1$Dx2AFD&mR@jvJ# zuTaz6e)2;$$KA{}PAZK=6Wwg^9(AZ^w6uLVwX>L%qrY7I-of?-OSm!p9*aR(o(V)$ z@ik5LsGg)H)oFWNuN^U@>(?~l06+wS>{`JesXDntf8a>|pt6(j#?R@(Cxt2G*mO<= z{2;?K>Ey>YWg|5gBZXAr=#pCnN63$bPFrvuF|;f`7#Tjqe@RM8AHU5MJRk7mt*K7_ zJKWmP-f{Xww`q62ewq;->chh0Fr^c}I$7$OTVuO`lW!W1Q}I=Jh<17qwNBKEzcrG{ z8bh}X!ol-Vy_w&QfNtW?#ZzNwB?fJ|jMU6ffOF52FT+y^&*RreL3~d34mc5zVuswh z;Th+=JUffhvCu4?@vgbM8#ocAi>sC6hYKG3U8Eu z-e^wR!pD*1#NPCYoGUc03G2Z_j$4K>L;nU|+T#hkdG66pupfzAra2jjL(P8nYy*f) zMh28&79GMs8@qs3OtE`nOu9;BtxR9XKyGK5f0in^>ytt&KeX6#2-WA_QLs8dPS>OFZ-e^l%Dc~#i7BQ5u5pnc<3Q7G^oH&0=Xe+vAMId_4PLB znLW7ba;Oz~A;33esDag#^ruO(mT!!<*td{2={fQu`9o;&{fT|F4%n_J z5r{n0bjWEM>nO-kix_{eI#uChc~>px5&B*9bp;_hCHu9K?j3m_>VvFBZ)xIU4yaO| zvw_Cwnku@0Q!BclKyI-wcHs54M6|?r#R)o9rY{y!e=CaI_UG;3-1Hd)isn@Ek<5G! zvq8qO2D-Y};v)vtL6<3D?X}xuycbyZ(!Zlx--qS(dd6(<#jobMYz`wLWkN!vPbRC~ z?aGZpX}R0AVT451TF!*F%Ry>UrIV(U_l*ai^fA(x@Sxw23Z3nzDd3#WD*gv`hL(w? z0hA0%)^qWfEXzU4Eu>WDfvz^KzxZJkz#jaa!J^mU(w$jjftPFPN`ia1@q1Z5W9<*C zr%UJBex`Vlnbk3;hV`6lA|sijK1Boe-g$yQvNx6-4O>MW-1Z362e9sH^d3jtucW=9 z2-k0ZRlO%SSF8F9@_lsiELy4%yq_$gg%&Am|J=R!2RB$`r@rDhw1=FM3*AwV>bXOH z9|gO9=K^Y0^b>3^-_dJ)VV#*VZ^b4O69wnrAOGY`!#pw8cBku1+U&ET%*K1JH1i;*aa8#^c70`7%&!*(%K!-s+_Q~QrJ_F|3| zQC7#?Y@T-v4||-f&OJcbcLgc&5Y}j9v1Mj-$NDR~o)+>c)A`ZL7CryP0xL|~4wg(7 zmGt3BIeDYyC*jTDyinH9??1pnBuLv<|0H6e$YP=z`2vZDQ;#@wcU|j^>YYk5Oq> z?n%ouA}Yqk?oy&My1Hm12A!!P^o+_dRhsPM8F~R&CG}Bkq12gDlB;G34e_IyNJ;vd z5G_N4@-I90>kMo26YL;&Bo(-90&9u|*Q{!NrLna@OJ&Ebh&*8$hmk0Bg#p(v=aLRw zmuCFnyw3@ndePMsw@~1;7nQprx^S|e=WH?*3G699Owq2LRD&-q1`8f2$977uP+zot@Gsp%9aR~{cdFSGnVcr&KMS;lh+wt!N@G$~Z`>|@Lq=)E z#}|9iBE&vZQs&O^1|B-e2C_h&V1^j*B~TK5g3gTsLJe zttp)@8~d5`1GhxdL3ZO^i{uYV;YefkZxsa{$rE`#pg0I2tqSKW2&Qm1Q;rDzPN~Xp z^{XCU|8Y{#J$^2}OxhfPMpn;+4XGDd+_;R^k2Br->*D@O>~oKimRu45wYo}jNV22Q z5oo;Kh__$t;vVWf#+U(Mnj9iFC7EHr3?d44^woI2a7f53xhhm|*@FbDBhcFv_}r03i=J;q!Kdl$uz0 zZF8Sdu8(93N3`~SNYa#}G$)w2@!~$O>tWW>)g-)NU8$vC3BJDH<_Qx1^hC059uBby znD4`*KWs#Sk5@qz4>c+OKtXwdyw7q|^eD3U{wjc*j171KGZ4s7Z^qgBiy(_bQNeYKKU5Oo-xAPQ-Kd$mnF;PSv_)Tm$CWro*k}Z_;Kr%vr z!a5b8*(t+Vm5$XTK=(4WfC`fT*ukURRl1<{mVe$E9fkI=ekzv zg`E9L>VMH|wjLLix}R%?Z;}PjkPJ`qCYd;XUn+o*h9h71qhsSuDT%snDHjpday(aF z!u*zlgPw+n7?1k^#>Gp&b{@f+(fTn{6^wOjZ5Mjw*;q@TBr0c3EM2m45=Er(-+V|8VCw(!IIFuzx=eXt!jQwHhE+D+?8KrwBsYKK@>AE`$5m1qdaCz|aL_BdQ1oP( z=<~@*0dh5|x?Xv5HHTxwR)k|V?p-K;j2>PNVX$Q5TMx=VAXfDx6X^y0t{Ul80O)J468V>DBw3agkllcN}N&q?Ed2CidzB)J(HG$DQ7|M zFAGinw%IU#mezTV3SFHh{|t5M-)G>dZKnNRs>}qC@li{2wqExA0(YI){p z*s@8h=y}-1;klF6xyoM6nMw=SA$Y$vQSMbO-1_0mb%p{#ymW=5RT~?zl&C8+wXBG@ zjR2~*OwC}W_qBc_;aZUaLSdz+p)Rn37TOTY{76Mfs1RZ>Lud4ck`U)fmS{|bO2ErC z#xLt&um2Q!dS!UWvmH<3eKsfD?8AATxw_?Xk&~c*w}uPN5vi#h8W%3mtO(72m1IdW zxv(8gO2c|m{7sn)_{M+b%8f_U<3|?vYw6q+P&|m}D&25_lY`@3^rYu;-Mr}Jqc*}= zT5UOO-l(!gTW#49$Y-v$^3nYEIKA2zVmI#4oanTsvNlnJ;a^Hu>5v(B8H86uYAb~H zUxIv*JRN7G#nPMobKU=S>1yE3;#aEirCMepfu#>ESG+WPDj1vnc{4O$Y&4pN#ReWT zJ_>e914+5p1_Wa?vRp77Esg%TpniVS5f@6M&di#XxUX0Dx+INX{ znjzEoZ`M1fXM%BGXnFwU!I#-Go|()q&Oc{J9=kn zGVMDiUudTnk70$jqywdcHK8!l0`$7UDd9x*Mffmj&WAQ?plnOObiYip3Pl0MabQ(5 z2W2Sre4c$EE}M;E3Ef9hcZgQEP@Fn5iY&H&bLDzS=7*O$nQpR6{eS9A=hVhRO-b>s zYabR=GCr$$>EwhlP11<(*BQduk598q5G6+;wz_7gk)FOccX14B8BJ zie=i)8YNH``3A=GQBc!QSSXCCS-XZJ;T2*2RFF^!28-O8vBoF z8Tk7Hs^UQ5wn!Wui`336@}W3Ub{o z6A|Z_NyQ0<`(FgN-_+cs*j=q&sE0f;u~hJB0t~#6S`*xSVjeO z$8Z;rBH7az~_h&Fj{2(lsufoS{K5% z-&RWhu(0pSti8`MUlSEOVyb)$DTjw zqtK&I(r_ll5+n}$VaRcx!#Dr3Z>)@yUs3S(DV-bH@fAEYj%okR9f7N7>6t(Qz!%{) zmhEoCeEiC_Lc7JThOx*pP3l9gf0k4T4r$|X5>T1o4sea(U%Y{92L19P5>|`j$@MDp zoiQ;^zT_diX|khWsj1PXeVp$((3t2hGM#Pu^a^){NV1d1QofWyF@yLaeM!YwI=VS` zzF#gT8pbrP8(yN_EbEUR>0IN}uW(UA$x&Vv&z(ST_8tkDV5(n^oSbW^56_(7CU+w$ zdwm<%s!Yj$E6RBNVeR%vWc@yx-KgEH$!EicrfQa8P@V_3+b z!x|Ohc1*Uq_%T_{D>o+Lxq6X#A5({DzgPlw%3XT@>sR(JMxWJ+?@_1MYv ziNul{NP4BGsI8F+^g{;*+xPMOaL81%Hc<*WYYPKJLciGYU*rfpCZ56>hy)JgSR;Q^ zr6s9-k5^ob1aLPd%7fg)0z%WuGhLI_Ig!|Mh!~{Bw=l1`G+@?2Cs7$K{t{ifP)_!JQ2C-5(hOI=`71qa30)GLVRJTFSa* z?LFrU^`CY!%~k#2jOCER81$v2>}NMfRLYqt44pc$9%m0N3Y*VMGWfb%t%!kX7gh-P^1Rb^-m7o(=D0V z+U?}*W+230B;2^C4rG7K=)3`f+)n zIh`y^*|no-aL4qiio&WHvJ^c@3HWn!<4-2bK@-aJivfW%K)YVb*O=AMGMIbR;PvOT znCCyE|5TS7I-cx(E`}H@Fej3<9G8+({0!E_>t?4J%N5k5q&8GPnIMFT(jJHZCM6gr zXAE=YCMn?4%eZJ>p(!XhF45Q*bYx`_G53o22!;J7TVPoYq!>+568;4eVmDGSNlP$O zx@zJo=h=6UV2&N>E`iPt{Yqf^WX2Or<)y&cJZqFI4fh6EH~270ys93;-Mdmdm$@sw zlvK7GAUO3~@FmWj%Hg8WOjd{#}yfEf3EA!07`b zawvxsjZ42L(KV7|l8B&xjQ+Y74iV=lmPpG9!8b2~;aaX3SPtk#(w)Q|NY9X=LANBm z>!C6z5;i?W0rt&8_a;*9gH;{Y{QU2HOtA?~0rWU|*k;@zUl&64+NRT2qpm_RE0R57 zil2tPy~(MAj#=nAG^y(E&|d$>>X>lkgFdeLoGy+-Zg_om_lu5$j74n|_SSAPMyc??b*py$}5tsq%?*q%R$JG^XMhtv#bqyTlJNlkj!|%yqneIf77p zXO|#6CC?=HC;+1{CU!D}dgzoFs_9M4!3K=3hKnq0%TNe%M524LZT2%Cx|&wx3!Ka3 zt(QcVt47S&9@T?hXUIRvPU;Jp1BfTH$o+4lT`XaA|XA9))ezf2T4uw?rS z(41j&N0x9*FQr>j!0&(X)KR%OHVl7ud{Tpj+cBrHAy&o~P3H@jmNtbstNIKRh4G;} zWpAU;5amS6cssi-jp<xo7ObtOrK&x#>u45G+Zsfya$E}e4LC~28((6KIXcN4y-!PYQvLAxjsI$lgrU{dZUj$s zihq5B(OJyrfd?M<+odGqewXOk(N?a`fz%TN(jAI8-zuEDH;B#^R=N<(a2;VVT*D@? z*PwDW*YQi}Rb(oP&fNWvt5iI2@o)SQiqn9=KRIc5W^2WlDBsezeaKwjnLp`yP@Vj` z?qfKda*05z6(!0r$m6tKy%sLdBf?pUP!mB? zXuRGGFpFX{`+1;($qzI644J6Lq1vh#4sM+*6z&m{R+sz!fsiGrGn95hf8hnNgS{sl zhNB#MT!2opoY5s1XGu;(dytAbBr^+A0>0A?AuVSy_L3}$Qan8Bdf$SvGo_Y24jBxo zHC`k;XyoEHGn4VhN-$xrAvlixlVC$oe$3M}7e=CZXq~EK?mUVK@RdM6wl&N-p1~!A zSaj5#$6G-H0PRdbQ{-#w0J2AX139&(D;olL_5(LK2Flf!qe6r(9<4;l1-sZin<;}m zYVN^X;2Q%Q0lgigpMj|IXS5?Zokf{1(V@N@itr-fC$&p5dW|s;fL>k-t z{Xn$8Y5a0_Wph1*hA?t%PRp2v4n*R4SJ*fzpJwF(1fZTv0hIl6zN%kYqP(4G+^Qu8 zX!rq-i+nu;G{oYJ*(ax9H6eL!Dn&bWc8l)@#9i;GF{oNK$KANb43xTs+}6OCDi7x| zes<&Vv0ZJ*Q{J(@=(qJot3{xTXE)UaHM;2bfc4RC=I9U16v8q8fDsgQPLJMR66YursCwxf?=xmw zHpyrcBy@dxp5+X7NU`U}j!8dXq=8z$_L&~-Tf~AcR)wCZGz&-IfeR62b5uM#z z$bRX8BwseF8byUBzy0t|S(>0^w~VHA1reR6W%WM=9;JyP4sRI_M*XD^W$6ZOWC;#c z{+OPnK~JiuG_OS)z0WnrA91OCcV@@5GspK6oOGhnW3jwEjA3t|y4>$->*nVoa71Op z03;8n$4eMP^rn-^3_ zpE1F`ZZ-mQ}?NBT9(A*_#~>@C?a z$%DExPk~dZcG)+2gL=?P>^yvVG_lbHoA^cUpGB*BAUD2iU>i`fsV7<}0yLz+rWA-)jTlx(2 zR~lLvM`kGA2)v5!6Lt;v+^)`Q^0v9ejUur|u=12yD?`U1z4(!|FI`)nn)}iPp&*G@ zvNcJ|;%|HlCUP*}0!MB6+bw}XqlhZe0r&cmJEH^cmAzK{Ez!NelPQfvy*%bFvS3LU)SOY(l)x79Gy=j|Vja4&sE)LP}1&mJa z8D=k{Z+Cetve~}mgtVEE=ng}70my|UNoc3tWn}Ui=pP@kC8tUZ2B%+wblnWXxV2p8 zr$ttw&p@K*{(%sIZf&C?>ih!nC4P&xwrHbASrUgY9B_=c7?vW4agt5=GXf!Erf;U0 zc+F^3_zx|8;)EptgiK8*yxF$_8yG+X3k)>=h{l?4T!=KX_%6Qot@X}$ZPei+#luwl zP_yymtAU~*D-_JSsmLEBf#*L;a^vP~%OJ({bB#S2PGqP$m^vyfRKL*AzRxs26lZLg zJf`P$6Ol&zYe%SC`5=+7b;c@8KX*2*Q8~UV{Gs#1p$f)*dIe8f{JR8}-`~zQ(W-KM zTJog@u(vHT5*UXPSB0Ui(<1UnIirMQVSXl}q|}qa<5S`q@XR*~70#*^&p2}B30RA@ zTWSK<5Q7iUa@8DNosZ)# zr5v-I-Y+%Ue>6VozwR4FY@Ym%Hv|hhB4Y3{_pRdNjfbyxnp0i00xtHiY6tMGkA6_C z%7Rg-gEe^%8hb3;MlhilSB#Ciw}kA%!rSrl5jZ7*suO=^rVoc&#A+K5^J9M_+2e@F zUDGw--F{JWJBJb4&M$XXEbD2b36X~@9|CJj;TM1|P~M7>D)m;gExJ*%HAgLZGSodR z?VU&@asStT?02!p0~nY=MhEo3)*QAp$O!10J7g<=t(L>>(E(Z*SVK70z}0G@hk=5m zt-s)rV4@m05$4U-9lw^H`UhQMEODloh;>h{2p!9te3__;Krj= z0yy15T+V~AyhhJ|6X{fYC-EOiwKK|*Q)YgRz(&!kzaf%k5d+6C=AJ8790#lV*rhxx ziorjbUt&SN5qGW^Po8VUq|#LN%Jj+|R9@-Bvzuwx7H#fo_rSrLg^ul&)V~{Zi|~2G z*5Ot%>8NQ}=GW|&bR_bZ?_&kE&ig%b|Xf zJpK;wJ&m>)S_pe}Fx^sRF5OH-;1U^u0bKg8yRDxHI<%`#_^|0TI+iJ7b=vk&-gfqQ zd9&sB;_LHLXS|rzH+^&GZ~34m-Wno~A4-izfleju$_y3#G&YsLc8+m1M>dL(EXNg* zBFz`tP6i1rk>;CcoZS6zK^C^DtikNC%FY)FQgHD4j8Mt88qPo5cDqhxDK~B3nCaAa zY#oTDMh2#!xKV8g8hOS-!LQu@0VH!WDNZLz6QTb!VQCoeL@)gW=K!ye&KRFNmk+_{ zVw)kFr!ykmw0HF<}GiXy3t;)&|vq%Nnu0n@b(8q;l5!PjiPB67U5vhP>pVeU*ra<(&h{@ zVF1TQ5g|scH`hzCTPXi{4&15>J>^QTYPDTO9##WI8Y|b?MP8r9IbCmB(m+>Cjh#5} z<~`-bdxWkg8Jwexj0JX}#xv+g1-_!zQ0Wg_KZKLCEq+qo{1Psy?HY#blMBptaLmmS z&_og>1`Y84ixZGwEUVKn1I1=F8#&Y`SZEK7x@8UN`r@p7UkQBKUq84l9gq_@GDyA& zSFOWp2$|(~vRr9Ad>p0Jy)>TMWmTi!s4PA2V}e^d9X4u? zcYhO(wJeHw^V3eq!XJ#oXx=uZP2%5gU-FGl!>PtFTB>xE0cd>uL_Nnq@b0h3~nEc$FPR<*|T?$A&kR;}7_kTrbC!kD66@1j zA8`9_(^)Ny@!wvJddWm)%q|)Ltio7*^}QeGG5m!TyDQR@dGkzcFcGtf16KkU0-GS+ z3e4>$|C9sxDog7S>b!LtnZB8twZ324AMz3Rl}%&iU{AyT^qGr2plb>5xJg(sHJ9pp zv4<<)#5aX+BN4)bN#n9FvK4RFzjU<7>))aoAy>T;v2V4=AQlRIlc<<>E=hQddb&6M zoY=w6lj=0rOnkQn|KGs$P5cugLgjC;kUdc0|Iqy$rUqHtD||*tAu>_+wB%tWqI$Iw ziwk_#XH2QB4d4$F`XiNlK)iaCO(IuLlSCS*O0QYUO*=g~*DeBsHmQSO3#AC~>@L>k_ zW?P&LZk^FTPSkkPlr)7Panf^N_#itO2#&5Eg>evpDFv# zfq?60n+VIcTulyT6mZ|h$xJF^BZ~?0G3m1lt|Zyx+MU|!SBA)-cJe=uv0*}J^)2`B ziN>U>+DR8M{Ko+ZO=>IE`7*qS@nT+i$IT$1rHENE0ANzzF83m)KhZ^W-erP%K!7I` z4F_Qvu}X`5&*w+H?!*mK4QnPvFpbm33md^lyOioEe-=5=U}4*Y&9XzRyK^S@Kae!u zM~E_YH!YNdC*pK!;LP%l$P$!GH$TbZn`tmO0fEZ2Ed&=yT4~s&xDQu#C}N2fe*xAh z?60pBVT2H(M8)iDto;14O)5tw{u%4_lnvuH9siPG7=%lREx z%G#^%A1%kxRMB_IUG%zWd9)SNYpvO4tV;(w$u_TuUd;O>$;4 z-((9{KW8}#ER)oIb2qy9g@Iwq8joWF_^>#>6h_2&)U=mXa|*d_aetgOUO+Z4dX#HP zK90B@TcSh%ZGU>zsG@d8w7Ksvf{67pOshL?3Y2xX^H|`)w4Ps~s4J{<^mcI9 z*{Y*PC=tXPEAeVL0Fpnl_4O$Wh^!197%MV0%fS(!@*tnYsu-LwBE_YgScVMJ`9DU| zDQa+;1wA2nKrmzaZ!j$<9)1K0B0oaPd{wgL8s97^5jlI8V<=x4K`4H-LNxZ2`N0@I zm2z~kGx8sx1t`c*up*)9v>Bzb(#{Ia*E!f$YJJ!kF zu~SAuY`CBEgZn=7;VSgbfHI;HpkV2K4ZO>I@nkqJ4nW{JA zorSr#ejZqJ>eRn8t*xvxYB8TpYEHOK5uAoAJX!#7(dWgCM>hvcl2+tt!DP^`5+i_H zx)LY*IQ6AQRxuZe`7GEuvxcdU6T=Fzyk^S9+(OPQeK_x*qu(%2sQ0v8n3)|PeQBAX zBdg8?FC3HHOuKB|;5~PVSISZQx@sTW?e;vdZ|yV_j=3_Ooq| zCE$YBFGQ0+3VYxtccu9u;~QubXfOm(&Aft%8}~hFiNgYCHQ(~W zC(a`}>$RVrUcAMFcy;fQ@6FI>C{W+ z)Ih-?qmXCKZZDW&F`g4T0#>xb{s$mU;KryRe=*-!{gJihPF8a$s2W7tV^f_l0uuin zorC-g6B$lqUhOWqWUlSvZN!Z##Hp9Sru^)!9eqmC%pUfDa~4Y$u~T_lgFU42YZdHCnVol6TXr(`c6Y ziZG^D!?UNIqtFemyqi z)q}(R4%uC7&OEExtI@er>)PYFh9q2Lzk= zb$sE5D?NR~OYvia>s5ZGdZ*|3Ckf0w{qTlJtk*QLSP%Tre}AG~-aEQYl@eK}p`b4V zKRW?SuYTj`74CgFc&aE0iOS$JmJ{#*X$cX5Q%AOlQ2k)!)MtJuX6>rg!>*JfJ%gn3E9gZ-H*^2-Qz9ZXv zXnW+JPOyPqWj~~&_A0hbEd=wW)dqM2L?nwKaY0UXT5!Y}Jt8R}W1?)T<{+O!L|q|= z50o^)r>wq}s}ZPZ*iVc73Rh8(7D$Pqdz>pwn!_?bP<|Y3d546>`g3-Vn_UrJzJ{-X zugZ%^P2$J?U!*x@U!yleJ2-$k_DfBb)Y*D99k;j7S(HHV!t<5d%Z!m1)J7k8T`$I0 zXR_|;G)E=QV=uSI*jPgrBY1?sWqVE}#a=Q4B^)!kxr}=~v$vedLefEt%x)Rc+&($0 zXXZ;`{=&OIDpM{cON|G-1oOrK4lVTx?j+O>TnT_+yMOQ4gfgt! zjJ-<-KP{$Uxtbh#VbsE{2b(FV^{sP)=zcU0+!(~BHqIiwB{fF zdewwsy$g^xj=pJb^k0oEGBr*Ku7F~6uG}LvhOA3s2|uY*5Y(yyk6pbp#Ym0SPM81Q zY>-^}19c@FkQecD4S)c?3B0$Uh!i4N`57}f!X3`_jvj3==Y?6eBZSTT&oD#TU`4*i zIieNdu3>BG??*iSZs0p2zZn=19GE$qD+Zu5ME($ef%?Z*l5Hybl0r z@6+8gmud*$Q7WYUS_M?YG!n$vwVNzNjO4{Wh5C`Ew6n^cL3n0U8r6o^X6H!}91ALo z1wl_^vQsXMLupuy$LZ^jzmLzic-(u^M(?nX5!GJ|)2ctHXKbpC03uJFOIgdJZPERu zt7sX0XF=7+2p;g2T!ti*UJS0_mD1;D;XWRJq5j4QCf6gf@heQATN7X%8IjZC5wT92 z?Ur~R{C*RuU!5V7Z`idqGUiBNCm{>#p{9peAe{mKhXNeITg$(5o@lTGc)?5WTc;V}PskP>vi&8IrC|Bns2zElkL1t)-1}wk#C)-gwX$T4 z#myM5(YHxIkV*TdH&q%pg2x~a4SvhJR=|-EuzYb5fz}`wH7Jm{^QzmlC&c zxRkkNt6dbuD*Ex;(7qcdXlzWsVaDry|I@Q@4{Dc{e^Y*K+tDairN=GwyE2gk zRSUh|q{oO%Fai^=^UA*Stw7L-(;G3+w#ummXs2(4jt-~pUMR-UXP#afO2yxK4~jSy zxLw$w1C95V^Ja=d92SP!u|{`H(X~a1mI5xu5X;wk>8h<7!~T%S*YLO46C)zvP7; z{)$IoZpg{x=XSx;;0*uh4dcRdF9i`O=4%$cbw>ET9nFA+HiLqrD-pBjj*Gy;3(PX|PmQ@Sl| zMNmp4w_6ItvY%eOGR1mN90>dIh;}@MkkP#0KyK(^0RN)5wzk`S$ubCwbF0nkh{oOG z!f9iw$;5ilUcajodpzrLw-^r`WuvH(+v9kMi5puQz*Ac`gsk*aiPv}~a?oeU4W+}` z@}m*?uc{B+b>0*WwQQ9Y88C}J^!1KB=3di^3=j#qb)d>ohxM&&6kCZG2NT2=FDx3Y zJ6J9ztvAQ3DK2yMRlSqJUZdy%nI}B*Q1h9CcK|~5w1@rO%89;Bh^Q4V5J=;c1sT2@ z!xsO2TH?2#eWnq``9AUDX<<=k{jCYQcWp{DrPwA5TtRo?V1ySYu_?0CJhihg;GOO^ z7tRTtZeMS4AGC}l7LJIl;&8}lX#(-h@sVR@)Y3#ctnlX!UL^>SZH0aK)%#=();nO21+S@epi)P|)U?2I5$=e5N9)f2{zL*zN0!;=PUdmt>p_s_KuCOy&J{M(bVsx`UWnvqP}*lDQ24SN)`BFU~x`F;QGU2zB|rTB4oB z=*C;#!jFO&TP?tXf5Ji_*s*UPH`lMZQPXX(suDpOM?9^b0VX|onb^I?9T#~|hvJmg zjpv|UjhOUsgg65_uyP;-_n$~MO2SLF7RLL~pXJIgKSPBr6R4F_5yj~G3bcg%lm)H} zQmi`VU(jX0Xkvan5AV~TNpB>hAflNI6F7g3^`#=hKlEKNx+5%tkCfT%2G7v3uEtBBM$>G%XrB@Pb!ODMRGhJkqNxN8@*J$axkm!sIDeFsUt8F^st=a68swnb3 z$!hNLi}SldVh7wF675@G^qAgKF1#^R^lq!86t2zMy~m&E0&~Y7YHkpzTEsyDJYd~d zmNrDHB?Z}vnCnyP`>uKz(?J8}is}+1|CpTQYHD#ym(B>U#}CZn=uhHsckDikwy0NKc%?RjjQP*$r6 z&N2vyX7){+V8zlOVH-kc@U*bQ|Hs~&M??LFal<7-Dx#8P=_i!6l65drQQ0aYSxdI; z>ln;TN~tVUDNAOkRFbS?$ufh4Y%^qEhb$9@!7yVCWzNp67kedCz(O`2EqT z%=muqYrn3~b=~)kzIeuKL08J*NXm)5hxIKHaWk&7YC9J9*TW}&INq^if7M&hUK|;n zU#)E~ICsjLoXR0NQ&vGIB339Y;J%!N)G&>z?o~uHunmAeY;|T@k|~y=;Xy#XEL`D4 z_K?Y;43zq?kHXHEv2%0dpKk0`VMJfr6T_X=+NV=+;7*+$BBw|7EE*nvuC!$`e7ieo zILK1^OI(f6DeiYe)p{d058n^b74CU(#JSga^vf3x=HOyTA%gs7r3R)%yC33A-mLqx z#j;OmomhOW(cfz+92GBwj30>ICwBFE=BY*1Q<@2)?Eo z-Bf$~&J*k8Xp z{&|NwSvmS6v041969mH%qeST?_uPdwu3nz>qc?VSPNx(gm+(%@sU3YIE>rHtgD*Bm zR4N8FhCfoziNrU2>&>Ue1`hkzl3kw2_$z8WdSi6`jE#kS_~~Gec*d(jYWkbrCa1{g zj+nOjSBxmvye_jQo^W%kfZX{C=4|}ufKVtphb$I!#p2w?xPOEmO^vPAzbI5xL zj+6zF2N6!S9;@?TvwFHw&A<^}kNQnzJOh!64~8!ADK17ng0bQS4mj^#3cBax{9F+T zo!zBN?x_#%bO@E!re3!ri`wmMjXmo5pw0@k`UyCAp-IaB?Snuy%JS;tV79~J?BRF# z_}FxHxVXY5&jD55M#+&(6jxB_F=sKQ&v z=uM108Kx>HPIx*DFU-W56+6BQR3n~ralH1|Lv#nt59hSDjLT!e;Y5zm{MV zRbiZMAaGC;g_wactH4WXDoP*^B8yfuRVSTd=$>``_6@|t@zg(D@5*97%P$s z6tE7uMq*}vz0~5IeOl)`hW8o-gUWq%<*$!)2e9|1Ug zAKURxLhRefme0x z-_P&x;;-N1W0L^1W=#V`h6cau3$XqEtRg@>r*-mss2O0C$A{cA8VU>Zf7Uu%J3SJ? z_wNxVbWe1*KFYoL7iC;wd-UvU1!>pgW4!&xQ@PiqyUvoqo;_W&0j|)sXPp|-9Gnbr zCZQSjI=V)`zp`dSm(SY&7`&Xc)J$4g;YbP|;ZgCKVTr6HT#uhVx;$b17b8FqDm*RY zWroTCWVI4QH5W9Vy5^nk@UN%!MpP^=-$>G2N-*l9CKwG+FAJxDeVH1>SJIgVs$0$- z`Rm(#Te-+_Yp$jDxwoh$$ZP5`-W#`#1@6%Q%UJG28xeXJS*0E~S1$__A;{>aM#@o{ z|IOl*&@CO3e`|&}r}%MgR|iui6&3Y{?`7E3&Wc1}_;mV%YFqJNX5lHuR(i|kV>mSs z;F;ae55SI&zn}6y{-+}Atj=2372;?=@%k@4{2#w}hwp$k`*Wb?f-b%>H}4nH2)=*xfbAD*p$seC?{cy3vK{w<3v>)h(LCLA$b*z{>KT`@5Qh^uF2RLK8>ZM`Bf#)mr2@qKVquNIOGwqJM~}KBcQG!MMT$Is>!`kGYWAPZD9WKWlR58buV8TXQc9Ya(r z*p{5dI+}?3aZ*RmSCw+ot!^Q1b>fhQ+lU0d9q7VOI6i51Qwx8459lLDF<3px-k(8T7Dr%V^shQSt9$P z)E@^F2IAZ*31E>pzc)51e=?B+JJ=`GYa3(@#qCai>5MJUO;ror?+`JYM^T9BugAr9 zJ0{8nYCNloUxC%d)|{8I)9sxU#Nq}o{EUoO2OlW*)lS48TK0yZhsV8wDXwr?1<{cL%o&#%`Bly#=}Al zAvNGhQN#e$M3XWU(lMraT1!=F5|r&MC(wG{Oycye-dx!da+U(^$)Fy%wKYgz#N*qK zOmvGC)I9XJbal9Pa#&r5;P9zp!9?vZ)`k-4^Zpaz)} zu%>MvPagh@(^F@*)ZP%U4D}g$gVqY^FiuhTNHa#~DLLc2im9Zjs8&2m-Hn7t563u? zt#KodZjs&fzIQ9dKix@Vmk#7NF>LAzmsYDS!;W#cpCB94ZYeetMvK&T-H&4bd4&HP zyu+uke>Z>q`Nw0(*&F&w$j>wU`ECXYB`eSAbJrEf*J`G3KgVIA1}_Y|&WJ9wrR~ZW zv75d_b2!uC?f+1^-6AggNlbrhB~qkaVbBAtz+UHRZ&j}x&*@Pe+a+u0S&E}`9{McX z0|8UIhfCkU^ygVC%&Ec3ZGkftrx9W~XCij@3{^#-1Dk16y|p&qm2gQ1A9>mQ&TQ6P zO%?K&pW#L9ofP;J0?vf#ELS1O*Y$iC=YBX&>(qGOI+EZgs8oNB_%yT*S^U}Cr!uxt zkQ^l)PZ&~*ii{_hNxvc3%s8CTtlODrfMW{Myj4!}f9eX*90vI~FMo&_?^aLJ8>bx0 zHd)N-J4VdpS$Zq|T3VAk+P8kZ3mO%EtUhb1&bd&_bqX-+&q25Xhq52sBkd*I0KXt{ zEE?TrFfA+(!-VbW1$1S&qo_aeZVDK zK~a_TXQj_u6#Tb{f}R{El|Id_5&~yMfLEx#d$YP0qWYU~NyXE5^guC_4@Fv9vO}Hfrl%`lb?a~`x70(GC&C7)T6VhamZ&4P*t`c}v zq9sbCrE4MdXY*kYnNm8fag*NXhwP7}W9dDw??nWe&%YIGdHwHfoBq$MwNj>3Rb%1S zZ}q9TbokE5EzyWdbZxSA&9oybwNdFgOn>e^4@oOMbig>|JL9d`)7i>8Q#q3qc~An3 zelk!kyF?!KRI|vdylE+>E0F7`40*=Zo~as9;eWJ1vQM1Ai?yfgW(w!eLOfAm-Cjj|Q4 z-QXC98x4)5Sc54V0t

Iko#6!Y8;8PQNtSM3U>2!Nvnlh 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 literal 0 HcmV?d00001 diff --git a/docs/wiki/images/rocksdb-lsm-tree.png b/docs/wiki/images/rocksdb-lsm-tree.png new file mode 100644 index 0000000000000000000000000000000000000000..1764c4af84cc7fcb91adc86ba6a3bd478f951825 GIT binary patch literal 442562 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

+D=XP3V-7PU0Gx>%A9-exMA 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 U)CHwBZ(Lt$Pqo2SO0R?e4J~VI0ssI2 literal 0 HcmV?d00001 From 92219cf8b163ceb72a222642048ea5aef4206566 Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Thu, 6 Jun 2019 16:12:28 +0800 Subject: [PATCH 48/91] refactor scripts --- scripts/config_tool/create_genesis.py | 322 ------------------------ scripts/config_tool/create_init_data.py | 101 ++++---- scripts/contracts/contracts.yml | 220 ++++++++-------- scripts/create_cita_config.py | 15 +- scripts/release.sh | 1 + 5 files changed, 165 insertions(+), 494 deletions(-) delete mode 100755 scripts/config_tool/create_genesis.py diff --git a/scripts/config_tool/create_genesis.py b/scripts/config_tool/create_genesis.py deleted file mode 100755 index c2300fac5..000000000 --- a/scripts/config_tool/create_genesis.py +++ /dev/null @@ -1,322 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding:utf-8 -*- -# pylint: disable=missing-docstring - -import argparse -import binascii -import json -import os -import sys -import time - -from ethereum.abi import ContractTranslator -import sha3 -import yaml - -from create_init_data import dictlist_to_ordereddict - -DEFAULT_PREVHASH = '0x{:064x}'.format(0) -BLOCK_GAS_LIMIT = 471238800 - - -def disable_import_warning(): - """This is a temporary method. - We do NOT need bitcoin. We want to decrease the size of docker. - So, just filter out the unnecessary warning. - """ - - import builtins - from types import ModuleType - - class DummyModule(ModuleType): - def __getattr__(self, key): - return None - - __all__ = [] - - def filterimport(name, globals=None, locals=None, fromlist=(), level=0): - if name == 'bitcoin': - return DummyModule(name) - return realimport(name, globals, locals, fromlist, level) - - realimport, builtins.__import__ = builtins.__import__, filterimport - - -disable_import_warning() -import ethereum.tools.tester as eth_tester -import ethereum.tools._solidity as solidity - - -def replaceLogRecord(): - """This is a temporary method. - We will remove pyethereum in the near future. - """ - - import logging - import re - - def makeRecord(self, - name, - level, - fn, - lno, - msg, - args, - exc_info, - func=None, - extra=None, - sinfo=None): - name = re.sub(r'(^|[^a-zA-Z])eth([^a-zA-Z]|$)', r'\1cita\2', name) - rv = logging._logRecordFactory(name, level, fn, lno, msg, args, - exc_info, func, sinfo) - if extra is not None: - for key in extra: - if (key in ["message", "asctime"]) or (key in rv.__dict__): - raise KeyError( - "Attempt to overwrite %r in LogRecord" % key) - rv.__dict__[key] = extra[key] - return rv - - def getMessage(self): - msg = str(self.msg) - if self.args: - msg = msg % self.args - msg = re.sub(r'(^|[^a-zA-Z])eth([^a-zA-Z]|$)', r'\1cita\2', msg) - msg = re.sub(r'(^|[^a-zA-Z])gas([^a-zA-Z]|$)', r'\1quota\2', msg) - return msg - - logging.Logger.makeRecord = makeRecord - logging.LogRecord.getMessage = getMessage - - -def function_encode(func_sign): - keccak = sha3.keccak_256() - keccak.update(func_sign.encode('utf-8')) - return binascii.unhexlify(keccak.hexdigest()[0:8]) - - -class GenesisData(object): - # pylint: disable=too-many-instance-attributes,too-many-arguments - def __init__(self, contracts_dir, contracts_docs_dir, init_data_file, - timestamp, prevhash): - self.timestamp = int( - time.time() * 1000) if not timestamp else timestamp - self.prevhash = DEFAULT_PREVHASH if not prevhash else prevhash - - self.contracts_dir = os.path.join(contracts_dir, 'src') - self.contracts_docs_dir = contracts_docs_dir - self.contracts_common_dir = os.path.join(self.contracts_dir, 'common') - self.contracts_lib_dir = os.path.join(self.contracts_dir, 'lib') - self.contracts_interaction_dir = os.path.join(contracts_dir, - 'interaction') - contracts_list_file = os.path.join(contracts_dir, 'contracts.yml') - self.load_contracts_list(contracts_list_file) - self.load_contracts_args(init_data_file) - - self.init_chain_tester() - - self.accounts = dict() - - def load_contracts_list(self, contracts_list_file): - """From file to load the list of contracts.""" - with open(contracts_list_file, 'r') as stream: - contracts_list = yaml.safe_load(stream) - contracts_list['NormalContracts'] = dictlist_to_ordereddict( - contracts_list['NormalContracts']) - contracts_list['PermissionContracts']['basic'] \ - = dictlist_to_ordereddict( - contracts_list['PermissionContracts']['basic']) - contracts_list['PermissionContracts']['contracts'] \ - = dictlist_to_ordereddict( - contracts_list['PermissionContracts']['contracts']) - self.contracts_list = contracts_list - - def load_contracts_args(self, init_data_file): - """From file to load arguments for contracts.""" - with open(init_data_file, 'r') as stream: - data = yaml.safe_load(stream) - contracts_args = dictlist_to_ordereddict(data['Contracts']) - for name, arguments in contracts_args.items(): - contracts_args[name] = dictlist_to_ordereddict(arguments) - self.contracts_args = contracts_args - - def init_chain_tester(self): - """Init a chain tester.""" - chain_env = eth_tester.get_env(None) - chain_env.config['BLOCK_GAS_LIMIT'] = BLOCK_GAS_LIMIT - self.chain_tester = eth_tester.Chain(env=chain_env) - - def compile_to_data(self, name, path): - """Compile a solidity file and return the result data.""" - - import logging - - compiled = solidity.compile_file( - path, - combined='bin,abi,userdoc,devdoc,hashes', - extra_args='common={} lib={} interaction={}'.format( - self.contracts_common_dir, self.contracts_lib_dir, - self.contracts_interaction_dir)) - data = solidity.solidity_get_contract_data(compiled, path, name) - if not data['bin']: - logging.critical( - 'The bin of contract %r is empty. Please check it!', name) - sys.exit(1) - return data - - def write_docs(self, name, data): - """Save userdoc, devdoc and hashes of contract function.""" - if self.contracts_docs_dir: - for doc_type in ('userdoc', 'devdoc', 'hashes'): - doc_file = os.path.join(self.contracts_docs_dir, - '{}-{}.json'.format(name, doc_type)) - with open(doc_file, 'w') as stream: - json.dump( - data[doc_type], - stream, - separators=(',', ': '), - indent=4) - - def mine_contract_on_chain_tester(self, addr, code): - """Mine in test chain to get data of a contract.""" - addr_in_tester = self.chain_tester.contract( - code, language='evm', startgas=30000000) - self.chain_tester.mine() - account_in_tester = self.chain_tester \ - .chain.state.account_to_dict(addr_in_tester) - self.accounts[addr] = { - key: val - for (key, val) in filter( - lambda keyval: keyval[0] in ('code', 'storage', 'nonce'), - account_in_tester.items(), - ) - } - - def init_normal_contracts(self): - """Compile normal contracts from files and construct by arguments. - """ - flags = [ - 'checkCallPermission', 'checkSendTxPermission', - 'checkCreateContractPermission', 'checkQuota', - 'checkFeeBackPlatform', 'autoExec' - ] - ncinfo = self.contracts_list['NormalContracts'] - for name, info in ncinfo.items(): - addr = info['address'] - path = os.path.join(self.contracts_dir, info['file']) - data = self.compile_to_data(name, path) - self.write_docs(name, data) - ctt = ContractTranslator(data['abi']) - args = self.contracts_args.get(name) - if name == 'SysConfig': - args['flags'] = [] - for flag in flags: - args['flags'].append(args[flag]) - args.pop(flag) - extra = b'' if not args else ctt.encode_constructor_arguments( - [arg for arg in args.values()]) - self.mine_contract_on_chain_tester(addr, data['bin'] + extra) - - def init_permission_contracts(self): - ncinfo = self.contracts_list['NormalContracts'] - pcinfo = self.contracts_list['PermissionContracts'] - path = os.path.join(self.contracts_dir, pcinfo['file']) - data = self.compile_to_data('Permission', path) - self.write_docs('Permission', data) - for name, info in pcinfo['basic'].items(): - addr = info['address'] - conts = [addr] - funcs = [binascii.unhexlify('00000000')] - ctt = ContractTranslator(data['abi']) - extra = ctt.encode_constructor_arguments([name, conts, funcs]) - self.mine_contract_on_chain_tester(addr, data['bin'] + extra) - for name, info in pcinfo['contracts'].items(): - addr = info['address'] - conts = [ncinfo[cont]['address'] for cont in info['contracts']] - funcs = [function_encode(func) for func in info['functions']] - ctt = ContractTranslator(data['abi']) - extra = ctt.encode_constructor_arguments([name, conts, funcs]) - self.mine_contract_on_chain_tester(addr, data['bin'] + extra) - - def set_account_value(self, address, value): - self.accounts[address] = { - 'code': '', - 'storage': {}, - 'nonce': '1', - 'value': value, - } - - def save_to_file(self, filepath): - with open(filepath, 'w') as stream: - json.dump( - dict( - timestamp=self.timestamp, - prevhash=self.prevhash, - alloc=self.accounts, - ), - stream, - separators=(',', ': '), - indent=4) - - -def parse_arguments(): - parser = argparse.ArgumentParser() - parser.add_argument( - '--contracts_dir', required=True, help='The directory of contracts.') - parser.add_argument( - '--contracts_docs_dir', - help='The directory of generated documents for contracts.' - ' If did not be specified, no documents will be generated.') - parser.add_argument( - '--init_data_file', - required=True, - help='Path of the file for initialization data of contracts.') - parser.add_argument( - '--output', required=True, help='Path of the output file.') - parser.add_argument( - '--timestamp', type=int, help='Specify a timestamp to use.') - parser.add_argument( - '--init_token', - type=lambda x: hex(int(x,16)), - default=hex(int("0xffffffffffffffffffffffffff", 16)), - help='Init token for this chain, INIT_TOKEN is a hexadecimal number') - parser.add_argument('--prevhash', help='Prevhash of genesis.') - args = parser.parse_args() - return dict( - contracts_dir=args.contracts_dir, - contracts_docs_dir=args.contracts_docs_dir, - init_data_file=args.init_data_file, - output=args.output, - timestamp=args.timestamp, - init_token=args.init_token, - prevhash=args.prevhash, - ) - - -def core(contracts_dir, contracts_docs_dir, init_data_file, output, timestamp, - init_token, prevhash): - # pylint: disable=too-many-arguments - replaceLogRecord() - if solidity.get_solidity() is None: - print('Solidity not found!') - sys.exit(1) - if contracts_docs_dir: - contracts_docs_dir = os.path.abspath(contracts_docs_dir) - genesis_data = GenesisData( - os.path.abspath(contracts_dir), - contracts_docs_dir, - os.path.abspath(init_data_file), - timestamp, - prevhash, - ) - with open(init_data_file, 'r') as stream: - data = yaml.safe_load(stream) - super_admin = data['Contracts'][6]['Admin'][0]['admin'] - genesis_data.init_normal_contracts() - genesis_data.init_permission_contracts() - genesis_data.set_account_value(super_admin, init_token) - genesis_data.save_to_file(output) - - -if __name__ == '__main__': - core(**parse_arguments()) diff --git a/scripts/config_tool/create_init_data.py b/scripts/config_tool/create_init_data.py index 5443dcec5..ec34cf410 100755 --- a/scripts/config_tool/create_init_data.py +++ b/scripts/config_tool/create_init_data.py @@ -8,59 +8,49 @@ DEFAULT_CONFIG = ''' Contracts: -- SysConfig: - - delayBlockNumber: 1 - - checkCallPermission: false - - checkSendTxPermission: false - - checkCreateContractPermission: false - - checkQuota: false - - checkFeeBackPlatform: false - - chainOwner: '0x0000000000000000000000000000000000000000' - - chainName: test-chain - - chainId: 1 - - operator: test-operator - - website: https://www.example.com - - blockInterval: 3000 - - economicalModel: 0 - - name: CITA Test Token - - symbol: CTT - - avatar: https://cdn.cryptape.com/icon_cita.png - - autoExec: false -- QuotaManager: - - admin: '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' -- NodeManager: - - nodes: - - '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' - - stakes: - - 0 -- ChainManager: - - parentChainId: 0 - - parentChainAuthorities: [] -- Authorization: - - superAdmin: '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' -- Group: - - parent: '0x0000000000000000000000000000000000000000' - - name: rootGroup - - accounts: - - '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' -- Admin: - - admin: '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' -- VersionManager: - - version: 2 -- PriceManager: - - quotaPrice: 1000000 + SysConfig: + delayBlockNumber: 1 + checkCallPermission: false + checkSendTxPermission: false + checkCreateContractPermission: false + checkQuota: false + checkFeeBackPlatform: false + chainOwner: '0x0000000000000000000000000000000000000000' + chainName: test-chain + chainId: 1 + operator: test-operator + website: https://www.example.com + blockInterval: 3000 + economicalModel: 0 + name: CITA Test Token + symbol: CTT + avatar: https://cdn.cryptape.com/icon_cita.png + autoExec: false + QuotaManager: + admin: '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' + NodeManager: + nodes: + - '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' + stakes: + - 0 + ChainManager: + parentChainId: 0 + parentChainAuthorities: [] + Authorization: + superAdmin: '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' + Group: + parent: '0x0000000000000000000000000000000000000000' + name: rootGroup + accounts: + - '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' + Admin: + admin: '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' + VersionManager: + version: 2 + PriceManager: + quotaPrice: 1000000 ''' - -def dictlist_to_ordereddict(dictlist): - """Convert a list of dict to an ordered dict.""" - odd = collections.OrderedDict() - for dic in dictlist: - for key, val in dic.items(): - odd[key] = val - return odd - - def ordereddict_to_dictlist(ordereddict): """Convert an ordered dict to a list of dict.""" return [{key: value} for key, value in ordereddict.items()] @@ -99,10 +89,7 @@ def __init__(self, contracts_cfgs): @classmethod def load_from_string(cls, cfg): data = yaml.safe_load(cfg) - contracts_cfgs = dictlist_to_ordereddict(data['Contracts']) - for name, arguments in contracts_cfgs.items(): - contracts_cfgs[name] = dictlist_to_ordereddict(arguments) - return cls(contracts_cfgs=contracts_cfgs) + return cls(contracts_cfgs=data['Contracts']) def update_by_kkv_dict(self, kkv_dict): if not kkv_dict: @@ -134,9 +121,7 @@ def set_super_admin(self, super_admin): def save_to_file(self, filepath): data = dict() contracts_cfgs = self.contracts_cfgs - for name, arguments in contracts_cfgs.items(): - contracts_cfgs[name] = ordereddict_to_dictlist(arguments) - data['Contracts'] = ordereddict_to_dictlist(contracts_cfgs) + data['Contracts'] = self.contracts_cfgs with open(filepath, 'w') as stream: yaml.dump(data, stream, default_flow_style=False) diff --git a/scripts/contracts/contracts.yml b/scripts/contracts/contracts.yml index d062a9be6..6f051b369 100644 --- a/scripts/contracts/contracts.yml +++ b/scripts/contracts/contracts.yml @@ -1,62 +1,62 @@ NormalContracts: -- SysConfig: + SysConfig: address: '0xffffffffffffffffffffffffffffffffff020000' file: system/SysConfig.sol -- NodeManager: + NodeManager: address: '0xffffffffffffffffffffffffffffffffff020001' file: system/NodeManager.sol -- ChainManager: + ChainManager: address: '0xffffffffffffffffffffffffffffffffff020002' file: system/ChainManager.sol -- QuotaManager: + QuotaManager: address: '0xffffffffffffffffffffffffffffffffff020003' file: system/QuotaManager.sol -- PermissionManagement: + PermissionManagement: address: '0xffffffffffffffffffffffffffffffffff020004' file: permission_management/PermissionManagement.sol -- PermissionCreator: + PermissionCreator: address: '0xffffffffffffffffffffffffffffffffff020005' file: permission_management/PermissionCreator.sol -- Authorization: + Authorization: address: '0xffffffffffffffffffffffffffffffffff020006' file: permission_management/Authorization.sol -- RoleManagement: + RoleManagement: address: '0xffffffffffffffffffffffffffffffffff020007' file: role_management/RoleManagement.sol -- RoleCreator: + RoleCreator: address: '0xffffffffffffffffffffffffffffffffff020008' file: role_management/RoleCreator.sol -- Group: + Group: address: '0xffffffffffffffffffffffffffffffffff020009' file: user_management/Group.sol -- GroupManagement: + GroupManagement: address: '0xffffffffffffffffffffffffffffffffff02000a' file: user_management/GroupManagement.sol -- GroupCreator: + GroupCreator: address: '0xffffffffffffffffffffffffffffffffff02000b' file: user_management/GroupCreator.sol -- Admin: + Admin: address: '0xffffffffffffffffffffffffffffffffff02000c' file: common/Admin.sol -- RoleAuth: + RoleAuth: address: '0xffffffffffffffffffffffffffffffffff02000d' file: role_management/RoleAuth.sol -- BatchTx: + BatchTx: address: '0xffffffffffffffffffffffffffffffffff02000e' file: system/BatchTx.sol -- EmergencyBrake: + EmergencyBrake: address: '0xffffffffffffffffffffffffffffffffff02000f' file: system/EmergencyBrake.sol -- PriceManager: + PriceManager: address: '0xffffffffffffffffffffffffffffffffff020010' file: system/PriceManager.sol -- VersionManager: + VersionManager: address: '0xffffffffffffffffffffffffffffffffff020011' file: system/VersionManager.sol -- AllGroups: + AllGroups: address: '0xffffffffffffffffffffffffffffffffff020012' file: user_management/AllGroups.sol -- AutoExec: + AutoExec: address: '0xffffffffffffffffffffffffffffffffff020013' file: system/AutoExec.sol @@ -64,162 +64,162 @@ NormalContracts: PermissionContracts: file: permission_management/Permission.sol basic: - - sendTx: + sendTx: address: '0xffffffffffffffffffffffffffffffffff021000' - - createContract: + createContract: address: '0xffffffffffffffffffffffffffffffffff021001' contracts: - - newPermission: + newPermission: address: '0xffffffffffffffffffffffffffffffffff021010' contracts: - - PermissionManagement + - PermissionManagement functions: - - 'newPermission(bytes32,address[],bytes4[])' - - deletePermission: + - 'newPermission(bytes32,address[],bytes4[])' + deletePermission: address: '0xffffffffffffffffffffffffffffffffff021011' contracts: - - PermissionManagement + - PermissionManagement functions: - - 'deletePermission(address)' - - updatePermission: + - 'deletePermission(address)' + updatePermission: address: '0xffffffffffffffffffffffffffffffffff021012' contracts: - - PermissionManagement - - PermissionManagement - - PermissionManagement + - PermissionManagement + - PermissionManagement + - PermissionManagement functions: - - 'addResources(address,address[],bytes4[])' - - 'deleteResources(address,address[],bytes4[])' - - 'updatePermissionName(address,bytes32)' - - setAuth: + - 'addResources(address,address[],bytes4[])' + - 'deleteResources(address,address[],bytes4[])' + - 'updatePermissionName(address,bytes32)' + setAuth: address: '0xffffffffffffffffffffffffffffffffff021013' contracts: - - PermissionManagement - - PermissionManagement + - PermissionManagement + - PermissionManagement functions: - - 'setAuthorization(address,address)' - - 'setAuthorizations(address,address[])' - - cancelAuth: + - 'setAuthorization(address,address)' + - 'setAuthorizations(address,address[])' + cancelAuth: address: '0xffffffffffffffffffffffffffffffffff021014' contracts: - - PermissionManagement - - PermissionManagement - - PermissionManagement + - PermissionManagement + - PermissionManagement + - PermissionManagement functions: - - 'cancelAuthorization(address,address)' - - 'clearAuthorization(address)' - - 'cancelAuthorizations(address,address[])' - - newRole: + - 'cancelAuthorization(address,address)' + - 'clearAuthorization(address)' + - 'cancelAuthorizations(address,address[])' + newRole: address: '0xffffffffffffffffffffffffffffffffff021015' contracts: - - RoleManagement + - RoleManagement functions: - - 'newRole(bytes32,address[])' - - deleteRole: + - 'newRole(bytes32,address[])' + deleteRole: address: '0xffffffffffffffffffffffffffffffffff021016' contracts: - - RoleManagement + - RoleManagement functions: - - 'deleteRole(address)' - - updateRole: + - 'deleteRole(address)' + updateRole: address: '0xffffffffffffffffffffffffffffffffff021017' contracts: - - RoleManagement - - RoleManagement - - RoleManagement + - RoleManagement + - RoleManagement + - RoleManagement functions: - - 'addPermissions(address,address[])' - - 'deletePermissions(address,address[])' - - 'updateRoleName(address,bytes32)' - - setRole: + - 'addPermissions(address,address[])' + - 'deletePermissions(address,address[])' + - 'updateRoleName(address,bytes32)' + setRole: address: '0xffffffffffffffffffffffffffffffffff021018' contracts: - - RoleManagement + - RoleManagement functions: - - 'setRole(address,address)' - - cancelRole: + - 'setRole(address,address)' + cancelRole: address: '0xffffffffffffffffffffffffffffffffff021019' contracts: - - RoleManagement - - RoleManagement + - RoleManagement + - RoleManagement functions: - - 'cancelRole(address,address)' - - 'clearRole(address)' - - newGroup: + - 'cancelRole(address,address)' + - 'clearRole(address)' + newGroup: address: '0xffffffffffffffffffffffffffffffffff02101a' contracts: - - GroupManagement + - GroupManagement functions: - - 'newGroup(address,bytes32,address[])' - - deleteGroup: + - 'newGroup(address,bytes32,address[])' + deleteGroup: address: '0xffffffffffffffffffffffffffffffffff02101b' contracts: - - GroupManagement + - GroupManagement functions: - - 'deleteGroup(address,address)' - - updateGroup: + - 'deleteGroup(address,address)' + updateGroup: address: '0xffffffffffffffffffffffffffffffffff02101c' contracts: - - GroupManagement - - GroupManagement - - GroupManagement + - GroupManagement + - GroupManagement + - GroupManagement functions: - - 'addAccounts(address,address,address[])' - - 'deleteAccounts(address,address,address[])' - - 'updateGroupName(address,address,bytes32)' - - newNode: + - 'addAccounts(address,address,address[])' + - 'deleteAccounts(address,address,address[])' + - 'updateGroupName(address,address,bytes32)' + newNode: address: '0xffffffffffffffffffffffffffffffffff021020' contracts: - - NodeManager + - NodeManager functions: - - 'approveNode(address)' - - deleteNode: + - 'approveNode(address)' + deleteNode: address: '0xffffffffffffffffffffffffffffffffff021021' contracts: - - NodeManager + - NodeManager functions: - - 'deleteNode(address)' - - updateNode: + - 'deleteNode(address)' + updateNode: address: '0xffffffffffffffffffffffffffffffffff021022' contracts: - - NodeManager + - NodeManager functions: - - 'setStake(address,uint64)' - - accountQuota: + - 'setStake(address,uint64)' + accountQuota: address: '0xffffffffffffffffffffffffffffffffff021023' contracts: - - QuotaManager - - QuotaManager + - QuotaManager + - QuotaManager functions: - - 'setDefaultAQL(uint256)' - - 'setAQL(address,uint256)' - - blockQuota: + - 'setDefaultAQL(uint256)' + - 'setAQL(address,uint256)' + blockQuota: address: '0xffffffffffffffffffffffffffffffffff021024' contracts: - - QuotaManager + - QuotaManager functions: - - 'setBQL(uint256)' - - batchTx: + - 'setBQL(uint256)' + batchTx: address: '0xffffffffffffffffffffffffffffffffff021025' contracts: - - BatchTx + - BatchTx functions: - - 'multiTxs(bytes)' - - emergencyBrake: + - 'multiTxs(bytes)' + emergencyBrake: address: '0xffffffffffffffffffffffffffffffffff021026' contracts: - - EmergencyBrake + - EmergencyBrake functions: - - 'setState(bool)' - - quotaPrice: + - 'setState(bool)' + quotaPrice: address: '0xffffffffffffffffffffffffffffffffff021027' contracts: - - PriceManager + - PriceManager functions: - - 'setQuotaPrice(uint256)' - - version: + - 'setQuotaPrice(uint256)' + version: address: '0xffffffffffffffffffffffffffffffffff021028' contracts: - - VersionManager + - VersionManager functions: - - 'setVersion(uint32)' + - 'setVersion(uint32)' diff --git a/scripts/create_cita_config.py b/scripts/create_cita_config.py index 032634ef5..f8d42a4a0 100755 --- a/scripts/create_cita_config.py +++ b/scripts/create_cita_config.py @@ -10,7 +10,10 @@ import sys import tempfile import toml +import subprocess +import time +DEFAULT_PREVHASH = '0x{:064x}'.format(0) def update_search_paths(work_dir): """Add new path to the search path.""" @@ -239,14 +242,18 @@ def create_init_data(self, super_admin, contract_arguments): create_init_data(self.init_data_file, super_admin, contract_arguments) def create_genesis(self, timestamp, init_token, resource_dir): - from create_genesis import core as create_genesis prevhash = generate_prevhash(resource_dir) if resource_dir is not None: shutil.copytree(resource_dir, os.path.join(self.configs_dir, 'resource'), False) - create_genesis(self.contracts_dir, self.contracts_docs_dir, - self.init_data_file, self.genesis_path, timestamp, - init_token, prevhash) + if not prevhash: + prevhash = DEFAULT_PREVHASH + if not timestamp: + timestamp = str(int(time.time() * 1000)) + + process = subprocess.Popen(["./bin/create_genesis",self.contracts_dir, self.contracts_docs_dir, + self.init_data_file, self.genesis_path, timestamp, init_token, prevhash]) + process.wait() def append_node(self, node): # For append mode: use the first element to store the new node diff --git a/scripts/release.sh b/scripts/release.sh index f3c09758a..3dd58de27 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -31,6 +31,7 @@ for binary in \ cita-jsonrpc \ cita-network \ create-key-addr \ + create_genesis \ cita-relayer-parser \ snapshot-tool \ consensus-mock \ From 0b84a40b23783990faf9c3f2b72b901691611a8d Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Thu, 6 Jun 2019 16:13:29 +0800 Subject: [PATCH 49/91] new genesis tool --- tools/create_genesis/Cargo.toml | 40 ++ tools/create_genesis/src/common.rs | 59 +++ tools/create_genesis/src/contracts.rs | 721 ++++++++++++++++++++++++++ tools/create_genesis/src/genesis.rs | 235 +++++++++ tools/create_genesis/src/main.rs | 71 +++ tools/create_genesis/src/miner.rs | 51 ++ tools/create_genesis/src/params.rs | 361 +++++++++++++ tools/create_genesis/src/solc.rs | 52 ++ 8 files changed, 1590 insertions(+) create mode 100644 tools/create_genesis/Cargo.toml create mode 100644 tools/create_genesis/src/common.rs create mode 100644 tools/create_genesis/src/contracts.rs create mode 100644 tools/create_genesis/src/genesis.rs create mode 100644 tools/create_genesis/src/main.rs create mode 100644 tools/create_genesis/src/miner.rs create mode 100644 tools/create_genesis/src/params.rs create mode 100644 tools/create_genesis/src/solc.rs diff --git a/tools/create_genesis/Cargo.toml b/tools/create_genesis/Cargo.toml new file mode 100644 index 000000000..607f596ec --- /dev/null +++ b/tools/create_genesis/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "create_genesis" +version = "0.1.0" +authors = ["Cryptape Technologies "] +edition = "2018" + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_yaml = "0.8" +json = "0.11.13" +serde_json = "1.0.39" +ethabi = "7.0.0" +ethereum-types = "0.5.2" +hex = "0.3" +tiny-keccak = "1.4.2" +libsecp256k1 = "0.2.2" +clap = "2.33.0" + +hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } +pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } + +core-executor = { path="../../cita-executor/core"} +evm = { path="../../cita-executor/evm"} + +[features] +default = ["secp256k1", "sha3hash", "rabbitmq"] +secp256k1 = ["libproto/secp256k1", "proof/secp256k1"] +ed25519 = ["libproto/ed25519", "proof/ed25519"] +sm2 = ["libproto/sm2", "proof/sm2"] +sha3hash = ["hashable/sha3hash", "libproto/sha3hash", "proof/sha3hash"] +blake2bhash = ["hashable/blake2bhash", "libproto/blake2bhash", "proof/blake2bhash"] +sm3hash = ["hashable/sm3hash", "libproto/sm3hash", "proof/sm3hash"] +rabbitmq = ["pubsub/rabbitmq"] +zeromq = ["pubsub/zeromq"] +kafka = ["pubsub/kafka"] +privatetx = ["core-executor/privatetx"] +evm-debug = ["core-executor/evm-debug"] +evm-debug-tests = ["evm-debug", "core-executor/evm-debug-tests"] diff --git a/tools/create_genesis/src/common.rs b/tools/create_genesis/src/common.rs new file mode 100644 index 000000000..23302c4aa --- /dev/null +++ b/tools/create_genesis/src/common.rs @@ -0,0 +1,59 @@ +use ethereum_types::Public; +use evm::cita_types::{Address, U256}; + +use core_executor::cita_db::{journaldb, kvdb, KeyValueDB}; +use core_executor::db; +use core_executor::state::State; +use core_executor::state_db::StateDB; +use std::sync::Arc; + +pub fn clean_0x(s: &str) -> &str { + if s.starts_with("0x") { + &s[2..] + } else { + s + } +} + +pub fn string_2_bytes(value: String) -> Vec { + let v = Box::leak(value.into_boxed_str()); + let v = clean_0x(v); + hex::decode(v).unwrap() +} + +pub fn string_2_u256(value: String) -> U256 { + let v = Box::leak(value.into_boxed_str()); + let v = clean_0x(v); + U256::from(v) +} + +pub fn public_2_address(public: &Public) -> Address { + let hash = tiny_keccak::keccak256(&public.0); + let mut result = Address::default(); + result.copy_from_slice(&hash[12..]); + result +} + +pub fn secret_2_address(secret: &str) -> Address { + let a = hex::decode(clean_0x(secret)).unwrap(); + let secret_key = secp256k1::SecretKey::parse_slice(a.as_slice()).unwrap(); + let public_key = secp256k1::PublicKey::from_secret_key(&secret_key); + let serialized = public_key.serialize(); + let public = Public::from_slice(&serialized[1..65]); + public_2_address(&public) +} + +pub fn get_temp_state() -> State { + let state_db = get_temp_state_db(); + State::new(state_db, 0.into(), Default::default()) +} + +pub fn new_db() -> Arc { + Arc::new(kvdb::in_memory(8)) +} + +pub fn get_temp_state_db() -> StateDB { + let db = new_db(); + let journal_db = journaldb::new(db, journaldb::Algorithm::Archive, db::COL_STATE); + StateDB::new(journal_db, 5 * 1024 * 1024) +} diff --git a/tools/create_genesis/src/contracts.rs b/tools/create_genesis/src/contracts.rs new file mode 100644 index 000000000..a97c955d7 --- /dev/null +++ b/tools/create_genesis/src/contracts.rs @@ -0,0 +1,721 @@ +use crate::common::clean_0x; +use ethabi::Token; +use ethereum_types::Address; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use std::fs::File; +use std::str::FromStr; +use tiny_keccak::keccak256; + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct ContractsData { + #[serde(rename = "NormalContracts")] + pub normal_contracts: NormalContracts, + + #[serde(rename = "PermissionContracts")] + pub permission_contracts: PermissionContracts, +} + +impl ContractsData { + pub fn load_contract_list(path: &str) -> ContractsData { + let f = File::open(path).expect("failed to open file"); + serde_yaml::from_reader(f).unwrap() + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct NormalContracts { + #[serde(rename = "SysConfig")] + pub sys_config: Info, + + #[serde(rename = "NodeManager")] + pub node_manager: Info, + + #[serde(rename = "ChainManager")] + pub chain_manager: Info, + + #[serde(rename = "QuotaManager")] + pub quota_manager: Info, + + #[serde(rename = "PermissionManagement")] + pub permission_management: Info, + + #[serde(rename = "PermissionCreator")] + pub permission_creator: Info, + + #[serde(rename = "Authorization")] + pub authorization: Info, + + #[serde(rename = "RoleManagement")] + pub role_management: Info, + + #[serde(rename = "RoleCreator")] + pub role_creator: Info, + + #[serde(rename = "Group")] + pub group: Info, + + #[serde(rename = "GroupManagement")] + pub group_management: Info, + + #[serde(rename = "GroupCreator")] + pub group_creator: Info, + + #[serde(rename = "Admin")] + pub admin: Info, + + #[serde(rename = "RoleAuth")] + pub role_auth: Info, + + #[serde(rename = "BatchTx")] + pub batch_tx: Info, + + #[serde(rename = "EmergencyBrake")] + pub emergency_brake: Info, + + #[serde(rename = "PriceManager")] + pub price_manager: Info, + + #[serde(rename = "VersionManager")] + pub version_manager: Info, + + #[serde(rename = "AllGroups")] + pub all_groups: Info, + + #[serde(rename = "AutoExec")] + pub auto_exec: Info, +} + +impl NormalContracts { + pub fn list(&self) -> BTreeMap<&'static str, Info> { + let mut normal_contracts = BTreeMap::new(); + normal_contracts.insert("SysConfig", self.sys_config.clone()); + normal_contracts.insert("NodeManager", self.node_manager.clone()); + normal_contracts.insert("ChainManager", self.chain_manager.clone()); + normal_contracts.insert("QuotaManager", self.quota_manager.clone()); + normal_contracts.insert("PermissionManagement", self.permission_management.clone()); + normal_contracts.insert("PermissionCreator", self.permission_creator.clone()); + normal_contracts.insert("Authorization", self.authorization.clone()); + normal_contracts.insert("RoleManagement", self.role_management.clone()); + normal_contracts.insert("RoleCreator", self.role_creator.clone()); + normal_contracts.insert("Group", self.group.clone()); + normal_contracts.insert("GroupManagement", self.group_management.clone()); + normal_contracts.insert("GroupCreator", self.group_creator.clone()); + normal_contracts.insert("Admin", self.admin.clone()); + normal_contracts.insert("RoleAuth", self.role_auth.clone()); + normal_contracts.insert("BatchTx", self.batch_tx.clone()); + normal_contracts.insert("EmergencyBrake", self.emergency_brake.clone()); + normal_contracts.insert("PriceManager", self.price_manager.clone()); + normal_contracts.insert("VersionManager", self.version_manager.clone()); + normal_contracts.insert("AllGroups", self.all_groups.clone()); + normal_contracts.insert("AutoExec", self.auto_exec.clone()); + normal_contracts + } +} + +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct Info { + pub address: String, + pub file: String, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct PermissionContracts { + pub file: String, + pub basic: Basic, + pub contracts: Contracts, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Basic { + #[serde(rename = "sendTx")] + pub send_tx: BasicInfo, + + #[serde(rename = "createContract")] + pub create_contract: BasicInfo, +} + +impl Basic { + pub fn list(&self) -> BTreeMap<&'static str, BasicInfo> { + let mut basic = BTreeMap::new(); + basic.insert("sendTx", self.send_tx.clone()); + basic.insert("createContract", self.create_contract.clone()); + basic + } + + pub fn as_params(&self, name: &str, info: &BasicInfo) -> Vec { + let mut tokens = Vec::new(); + tokens.push(Token::FixedBytes(String::from(name).into_bytes())); + let mut conts = Vec::new(); + let addr = Address::from_str(clean_0x(&info.address)).unwrap(); + conts.push(Token::Address(addr)); + let mut funcs = Vec::new(); + funcs.push(Token::FixedBytes(String::from("0000").into_bytes())); + + tokens.push(Token::Array(conts)); + tokens.push(Token::Array(funcs)); + tokens + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct BasicInfo { + pub address: String, +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct Contracts { + #[serde(rename = "newPermission")] + pub new_permission: ContractsInfo, + + #[serde(rename = "deletePermission")] + pub delete_permission: ContractsInfo, + + #[serde(rename = "updatePermission")] + pub update_permission: ContractsInfo, + + #[serde(rename = "setAuth")] + pub set_auth: ContractsInfo, + + #[serde(rename = "cancelAuth")] + pub cancel_auth: ContractsInfo, + + #[serde(rename = "newRole")] + pub new_role: ContractsInfo, + + #[serde(rename = "deleteRole")] + pub delete_role: ContractsInfo, + + #[serde(rename = "updateRole")] + pub update_role: ContractsInfo, + + #[serde(rename = "setRole")] + pub set_role: ContractsInfo, + + #[serde(rename = "cancelRole")] + pub cancel_role: ContractsInfo, + + #[serde(rename = "newGroup")] + pub new_group: ContractsInfo, + + #[serde(rename = "deleteGroup")] + pub delete_group: ContractsInfo, + + #[serde(rename = "updateGroup")] + pub update_group: ContractsInfo, + + #[serde(rename = "newNode")] + pub new_node: ContractsInfo, + + #[serde(rename = "deleteNode")] + pub delete_node: ContractsInfo, + + #[serde(rename = "updateNode")] + pub update_node: ContractsInfo, + + #[serde(rename = "accountQuota")] + pub account_quota: ContractsInfo, + + #[serde(rename = "blockQuota")] + pub block_quota: ContractsInfo, + + #[serde(rename = "batchTx")] + pub batch_tx: ContractsInfo, + + #[serde(rename = "emergencyBrake")] + pub emergency_brake: ContractsInfo, + + #[serde(rename = "quotaPrice")] + pub quota_price: ContractsInfo, + + #[serde(rename = "version")] + pub version: ContractsInfo, +} + +impl Contracts { + pub fn list(&self) -> BTreeMap<&'static str, ContractsInfo> { + let mut contracts = BTreeMap::new(); + contracts.insert("newPermission", self.new_permission.clone()); + contracts.insert("deletePermission", self.delete_permission.clone()); + contracts.insert("updatePermission", self.update_permission.clone()); + contracts.insert("setAuth", self.set_auth.clone()); + contracts.insert("cancelAuth", self.cancel_auth.clone()); + contracts.insert("newRole", self.new_role.clone()); + contracts.insert("deleteRole", self.delete_role.clone()); + contracts.insert("updateRole", self.update_role.clone()); + contracts.insert("setRole", self.set_role.clone()); + contracts.insert("cancelRole", self.cancel_role.clone()); + contracts.insert("newGroup", self.new_group.clone()); + contracts.insert("deleteGroup", self.delete_group.clone()); + contracts.insert("updateGroup", self.update_group.clone()); + contracts.insert("newNode", self.new_node.clone()); + contracts.insert("deleteNode", self.delete_node.clone()); + contracts.insert("updateNode", self.update_node.clone()); + contracts.insert("accountQuota", self.account_quota.clone()); + contracts.insert("blockQuota", self.block_quota.clone()); + contracts.insert("batchTx", self.batch_tx.clone()); + contracts.insert("emergencyBrake", self.emergency_brake.clone()); + contracts.insert("quotaPrice", self.quota_price.clone()); + contracts.insert("version", self.version.clone()); + contracts + } + + pub fn as_params( + &self, + normal_contracts: &NormalContracts, + name: &str, + info: &ContractsInfo, + ) -> Vec { + let mut tokens = Vec::new(); + let reference = normal_contracts.list(); + + // Get name + tokens.push(Token::FixedBytes(String::from(name).into_bytes())); + // Get conts + let mut conts = Vec::new(); + match name { + "newPermission" => { + for a in self.new_permission.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "deletePermission" => { + for a in self.delete_permission.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "updatePermission" => { + for a in self.update_permission.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "setAuth" => { + for a in self.set_auth.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "cancelAuth" => { + for a in self.cancel_auth.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "newRole" => { + for a in self.new_role.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "deleteRole" => { + for a in self.delete_role.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "updateRole" => { + for a in self.update_role.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "setRole" => { + for a in self.set_role.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "cancelRole" => { + for a in self.cancel_role.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "newGroup" => { + for a in self.new_group.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "deleteGroup" => { + for a in self.delete_group.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "updateGroup" => { + for a in self.update_group.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "newNode" => { + for a in self.new_node.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "deleteNode" => { + for a in self.delete_node.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "updateNode" => { + for a in self.update_node.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "accountQuota" => { + for a in self.account_quota.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "blockQuota" => { + for a in self.block_quota.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "batchTx" => { + for a in self.batch_tx.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "emergencyBrake" => { + for a in self.emergency_brake.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "quotaPrice" => { + for a in self.quota_price.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + "version" => { + for a in self.version.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + } + _ => panic!("Unexpected permission contract name"), + } + + // Get funcs + let mut funcs = Vec::new(); + for f in info.functions.iter() { + let func = keccak256(f.as_bytes()).to_vec(); + funcs.push(Token::FixedBytes(func[0..4].to_vec())); + } + + tokens.push(Token::Array(conts)); + tokens.push(Token::Array(funcs)); + tokens + } +} + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +pub struct ContractsInfo { + pub address: String, + pub contracts: Vec, + pub functions: Vec, +} +#[cfg(test)] +mod tests { + use super::ContractsData; + + #[test] + pub fn test_contracts() { + let contracts_string = r#" + NormalContracts: + SysConfig: + address: '0xffffffffffffffffffffffffffffffffff020000' + file: system/SysConfig.sol + NodeManager: + address: '0xffffffffffffffffffffffffffffffffff020001' + file: system/NodeManager.sol + ChainManager: + address: '0xffffffffffffffffffffffffffffffffff020002' + file: system/ChainManager.sol + QuotaManager: + address: '0xffffffffffffffffffffffffffffffffff020003' + file: system/QuotaManager.sol + PermissionManagement: + address: '0xffffffffffffffffffffffffffffffffff020004' + file: permission_management/PermissionManagement.sol + PermissionCreator: + address: '0xffffffffffffffffffffffffffffffffff020005' + file: permission_management/PermissionCreator.sol + Authorization: + address: '0xffffffffffffffffffffffffffffffffff020006' + file: permission_management/Authorization.sol + RoleManagement: + address: '0xffffffffffffffffffffffffffffffffff020007' + file: role_management/RoleManagement.sol + RoleCreator: + address: '0xffffffffffffffffffffffffffffffffff020008' + file: role_management/RoleCreator.sol + Group: + address: '0xffffffffffffffffffffffffffffffffff020009' + file: user_management/Group.sol + GroupManagement: + address: '0xffffffffffffffffffffffffffffffffff02000a' + file: user_management/GroupManagement.sol + GroupCreator: + address: '0xffffffffffffffffffffffffffffffffff02000b' + file: user_management/GroupCreator.sol + Admin: + address: '0xffffffffffffffffffffffffffffffffff02000c' + file: common/Admin.sol + RoleAuth: + address: '0xffffffffffffffffffffffffffffffffff02000d' + file: role_management/RoleAuth.sol + BatchTx: + address: '0xffffffffffffffffffffffffffffffffff02000e' + file: system/BatchTx.sol + EmergencyBrake: + address: '0xffffffffffffffffffffffffffffffffff02000f' + file: system/EmergencyBrake.sol + PriceManager: + address: '0xffffffffffffffffffffffffffffffffff020010' + file: system/PriceManager.sol + VersionManager: + address: '0xffffffffffffffffffffffffffffffffff020011' + file: system/VersionManager.sol + AllGroups: + address: '0xffffffffffffffffffffffffffffffffff020012' + file: user_management/AllGroups.sol + AutoExec: + address: '0xffffffffffffffffffffffffffffffffff020013' + file: system/AutoExec.sol + + PermissionContracts: + file: permission_management/Permission.sol + basic: + sendTx: + address: '0xffffffffffffffffffffffffffffffffff021000' + createContract: + address: '0xffffffffffffffffffffffffffffffffff021001' + contracts: + newPermission: + address: '0xffffffffffffffffffffffffffffffffff021010' + contracts: + - PermissionManagement + functions: + - 'newPermission(bytes32,address[],bytes4[])' + deletePermission: + address: '0xffffffffffffffffffffffffffffffffff021011' + contracts: + - PermissionManagement + functions: + - 'deletePermission(address)' + updatePermission: + address: '0xffffffffffffffffffffffffffffffffff021012' + contracts: + - PermissionManagement + - PermissionManagement + - PermissionManagement + functions: + - 'addResources(address,address[],bytes4[])' + - 'deleteResources(address,address[],bytes4[])' + - 'updatePermissionName(address,bytes32)' + setAuth: + address: '0xffffffffffffffffffffffffffffffffff021013' + contracts: + - PermissionManagement + - PermissionManagement + functions: + - 'setAuthorization(address,address)' + - 'setAuthorizations(address,address[])' + cancelAuth: + address: '0xffffffffffffffffffffffffffffffffff021014' + contracts: + - PermissionManagement + - PermissionManagement + - PermissionManagement + functions: + - 'cancelAuthorization(address,address)' + - 'clearAuthorization(address)' + - 'cancelAuthorizations(address,address[])' + newRole: + address: '0xffffffffffffffffffffffffffffffffff021015' + contracts: + - RoleManagement + functions: + - 'newRole(bytes32,address[])' + deleteRole: + address: '0xffffffffffffffffffffffffffffffffff021016' + contracts: + - RoleManagement + functions: + - 'deleteRole(address)' + updateRole: + address: '0xffffffffffffffffffffffffffffffffff021017' + contracts: + - RoleManagement + - RoleManagement + - RoleManagement + functions: + - 'addPermissions(address,address[])' + - 'deletePermissions(address,address[])' + - 'updateRoleName(address,bytes32)' + setRole: + address: '0xffffffffffffffffffffffffffffffffff021018' + contracts: + - RoleManagement + functions: + - 'setRole(address,address)' + cancelRole: + address: '0xffffffffffffffffffffffffffffffffff021019' + contracts: + - RoleManagement + - RoleManagement + functions: + - 'cancelRole(address,address)' + - 'clearRole(address)' + newGroup: + address: '0xffffffffffffffffffffffffffffffffff02101a' + contracts: + - GroupManagement + functions: + - 'newGroup(address,bytes32,address[])' + deleteGroup: + address: '0xffffffffffffffffffffffffffffffffff02101b' + contracts: + - GroupManagement + functions: + - 'deleteGroup(address,address)' + updateGroup: + address: '0xffffffffffffffffffffffffffffffffff02101c' + contracts: + - GroupManagement + - GroupManagement + - GroupManagement + functions: + - 'addAccounts(address,address,address[])' + - 'deleteAccounts(address,address,address[])' + - 'updateGroupName(address,address,bytes32)' + newNode: + address: '0xffffffffffffffffffffffffffffffffff021020' + contracts: + - NodeManager + functions: + - 'approveNode(address)' + deleteNode: + address: '0xffffffffffffffffffffffffffffffffff021021' + contracts: + - NodeManager + functions: + - 'deleteNode(address)' + updateNode: + address: '0xffffffffffffffffffffffffffffffffff021022' + contracts: + - NodeManager + functions: + - 'setStake(address,uint64)' + accountQuota: + address: '0xffffffffffffffffffffffffffffffffff021023' + contracts: + - QuotaManager + - QuotaManager + functions: + - 'setDefaultAQL(uint256)' + - 'setAQL(address,uint256)' + blockQuota: + address: '0xffffffffffffffffffffffffffffffffff021024' + contracts: + - QuotaManager + functions: + - 'setBQL(uint256)' + batchTx: + address: '0xffffffffffffffffffffffffffffffffff021025' + contracts: + - BatchTx + functions: + - 'multiTxs(bytes)' + emergencyBrake: + address: '0xffffffffffffffffffffffffffffffffff021026' + contracts: + - EmergencyBrake + functions: + - 'setState(bool)' + quotaPrice: + address: '0xffffffffffffffffffffffffffffffffff021027' + contracts: + - PriceManager + functions: + - 'setQuotaPrice(uint256)' + version: + address: '0xffffffffffffffffffffffffffffffffff021028' + contracts: + - VersionManager + functions: + - 'setVersion(uint32)' + "#; + let contracts: ContractsData = serde_yaml::from_str(&contracts_string).unwrap(); + assert_eq!( + contracts.normal_contracts.sys_config.address, + String::from("0xffffffffffffffffffffffffffffffffff020000") + ); + assert_eq!( + contracts.normal_contracts.sys_config.file, + String::from("system/SysConfig.sol") + ); + assert_eq!( + contracts.normal_contracts.auto_exec.address, + String::from("0xffffffffffffffffffffffffffffffffff020013") + ); + assert_eq!( + contracts.normal_contracts.auto_exec.file, + String::from("system/AutoExec.sol") + ); + + assert_eq!( + contracts.permission_contracts.file, + String::from("permission_management/Permission.sol") + ); + assert_eq!( + contracts.permission_contracts.basic.send_tx.address, + String::from("0xffffffffffffffffffffffffffffffffff021000") + ); + + assert_eq!( + contracts + .permission_contracts + .contracts + .new_permission + .address, + String::from("0xffffffffffffffffffffffffffffffffff021010") + ); + } +} diff --git a/tools/create_genesis/src/genesis.rs b/tools/create_genesis/src/genesis.rs new file mode 100644 index 000000000..012a488fa --- /dev/null +++ b/tools/create_genesis/src/genesis.rs @@ -0,0 +1,235 @@ +use crate::common::{clean_0x, string_2_bytes}; +use crate::contracts::ContractsData; +use crate::miner::Miner; +use crate::params::InitData; +use crate::solc::Solc; +use ethabi::Contract; +use evm::cita_types::U256; +use json; +use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; +use std::fs::File; +use std::io::Write; +use std::path::Path; +use std::str::FromStr; + +pub struct GenesisCreator<'a> { + pub contract_dir: &'a str, + pub contract_docs_dir: &'a str, + pub genesis_path: &'a str, + pub timestamp: u64, + pub init_token: &'a str, + pub prevhash: &'a str, + pub contract_args: InitData, + pub contract_list: ContractsData, + pub accounts: BTreeMap, +} + +#[derive(Clone, Debug, Serialize, Deserialize)] +pub struct Account { + pub nonce: U256, + pub code: String, + pub storage: BTreeMap, + pub value: U256, +} + +#[derive(Serialize, Deserialize)] +pub struct Genesis { + pub timestamp: u64, + pub prevhash: String, + pub alloc: BTreeMap, +} + +impl Default for Genesis { + fn default() -> Self { + Genesis { + timestamp: 0, + prevhash: String::default(), + alloc: BTreeMap::new(), + } + } +} + +impl<'a> GenesisCreator<'a> { + pub fn new( + contract_dir: &'a str, + contract_docs_dir: &'a str, + params_path: &'a str, + genesis_path: &'a str, + timestamp: u64, + init_token: &'a str, + prevhash: &'a str, + ) -> Self { + let params = InitData::load_contract_args(params_path); + let contracts_list = contract_dir.to_owned() + "/contracts.yml"; + let constracts = ContractsData::load_contract_list(&contracts_list); + + GenesisCreator { + contract_dir, + contract_docs_dir, + genesis_path, + timestamp, + init_token, + prevhash, + contract_args: params, + contract_list: constracts, + accounts: BTreeMap::new(), + } + } + + pub fn create(&mut self) { + // 1. Check compile exit or not + if !Solc::compiler_version() { + panic!("solc compiler not exit"); + } + // 2. Init normal contracts + self.init_normal_contracts(); + // 3. Init permission contracts + self.init_permission_contracts(); + // 4. Save super admin + let super_admin = self.contract_args.contracts.admin.admin.clone(); + self.set_account_value( + &super_admin, + U256::from_str(clean_0x(&self.init_token)).unwrap(), + ); + // 5. Save genesis to file + self.save_to_file(); + println!("Create genesis successfully !"); + } + + pub fn init_normal_contracts(&mut self) { + for (contract_name, contract_info) in self.contract_list.normal_contracts.list().iter() { + let address = &contract_info.address; + let sol_path = self.contract_dir.to_owned() + "/src/" + &contract_info.file; + let abi_path = + self.contract_dir.to_owned() + "/interaction/abi/" + contract_name + ".abi"; + let data = Solc::get_contracts_data(sol_path, contract_name); + + let input_data = string_2_bytes(data["bin"].clone()); + self.write_docs(contract_name, data); + + let abi_file = File::open(abi_path).expect("failed to open abi file."); + let contract = Contract::load(abi_file).unwrap(); + + if let Some(constructor) = contract.constructor() { + let mut params = Vec::new(); + match *contract_name { + "SysConfig" => { + params = self.contract_args.contracts.sys_config.as_params(); + } + "QuotaManager" => { + params = self.contract_args.contracts.quota_manager.as_params(); + } + "NodeManager" => { + params = self.contract_args.contracts.node_manager.as_params(); + } + "ChainManager" => { + params = self.contract_args.contracts.chain_manager.as_params(); + } + "Authorization" => { + params = self.contract_args.contracts.authorization.as_params(); + } + "Group" => { + params = self.contract_args.contracts.group.as_params(); + } + "Admin" => { + params = self.contract_args.contracts.admin.as_params(); + } + "VersionManager" => { + params = self.contract_args.contracts.version_manager.as_params(); + } + "PriceManager" => { + params = self.contract_args.contracts.price_manager.as_params(); + } + _ => (), + } + let bytes = constructor.encode_input(input_data, ¶ms).unwrap(); + let account = Miner::mine(bytes); + self.accounts.insert((*address).clone(), account); + } else { + let account = Miner::mine(input_data); + self.accounts.insert((*address).clone(), account); + } + println!("Normal contracts: {:?} {:?} is ok!", contract_name, address); + } + } + + pub fn init_permission_contracts(&mut self) { + let normal_contracts = self.contract_list.normal_contracts.clone(); + let perm_contracts = self.contract_list.permission_contracts.clone(); + + let contract_name: &'static str = "Permission"; + let perm_path = self.contract_dir.to_owned() + "/src/" + &perm_contracts.file; + let abi_path = self.contract_dir.to_owned() + "/interaction/abi/" + contract_name + ".abi"; + + let data = Solc::get_contracts_data(perm_path, contract_name); + let input_data = string_2_bytes(data["bin"].clone()); + self.write_docs(&contract_name, data); + + let abi_file = File::open(abi_path).expect("failed to open abi file."); + let contract = Contract::load(abi_file).unwrap(); + let constructor = contract.constructor().unwrap(); + + for (name, info) in perm_contracts.basic.list().iter() { + let address = &info.address; + let params = self + .contract_list + .permission_contracts + .basic + .as_params(name, info); + + let bytes = constructor + .encode_input(input_data.clone(), ¶ms) + .unwrap(); + let account = Miner::mine(bytes); + self.accounts.insert(address.clone(), account); + println!("Permission contracts: {:?} {:?} is ok!", name, address); + } + + for (name, info) in perm_contracts.contracts.list().iter() { + let perm_address = &info.address; + let params = self.contract_list.permission_contracts.contracts.as_params( + &normal_contracts, + name, + info, + ); + + let bytes = constructor + .encode_input(input_data.clone(), ¶ms) + .unwrap(); + let account = Miner::mine(bytes); + self.accounts.insert((*perm_address).clone(), account); + println!("Permission contracts: {:?} {:?} is ok!", name, perm_address); + } + } + + pub fn write_docs(&self, name: &str, data: BTreeMap<&'static str, String>) { + for doc_type in ["hashes", "userdoc", "devdoc"].iter() { + let file_path = + self.contract_docs_dir.to_owned() + "/" + name + "-" + doc_type + ".json"; + let path = Path::new(&file_path); + let json = json::stringify_pretty(data[doc_type].clone(), 4); + let mut f = File::create(path).expect("failed to write docs."); + let _ = f.write_all(&json.as_bytes()); + } + } + + pub fn set_account_value(&mut self, address: &str, value: U256) { + let account = Account { + nonce: U256::one(), + code: String::from(""), + storage: BTreeMap::new(), + value, + }; + self.accounts.insert(address.to_owned(), account); + } + + pub fn save_to_file(&mut self) { + let mut genesis = Genesis::default(); + genesis.timestamp = self.timestamp; + genesis.prevhash = self.prevhash.to_owned(); + genesis.alloc = self.accounts.clone(); + let f = File::create(self.genesis_path.to_owned()).expect("failed to create genesis.json."); + let _ = serde_json::to_writer_pretty(f, &genesis); + } +} diff --git a/tools/create_genesis/src/main.rs b/tools/create_genesis/src/main.rs new file mode 100644 index 000000000..a85051360 --- /dev/null +++ b/tools/create_genesis/src/main.rs @@ -0,0 +1,71 @@ +mod common; +mod contracts; +mod genesis; +mod params; + +pub mod miner; +pub mod solc; + +use clap::{App, Arg}; +use genesis::GenesisCreator; + +fn main() { + let matches = App::new("CITA genesis creator") + .version("1.0") + .author("Cryptape Technologies") + .arg( + Arg::with_name("contract_dir") + .help("The directory of contracts.") + .required(true), + ) + .arg( + Arg::with_name("contract_docs_dir") + .help("The directory of generated documents for contracts.") + .required(true), + ) + .arg( + Arg::with_name("params_path") + .help("Path of the file for initialization data of contracts.") + .required(true), + ) + .arg( + Arg::with_name("genesis_path") + .help("Set created genesis path") + .required(true), + ) + .arg( + Arg::with_name("timestamp") + .help("Specify a timestamp to use.") + .required(true), + ) + .arg( + Arg::with_name("init_token") + .help("Init token for this chain") + .required(true), + ) + .arg( + Arg::with_name("prevhash") + .help("Prevhash of genesis.") + .required(true), + ) + .get_matches(); + + let contract_dir = matches.value_of("contract_dir").unwrap(); + let contract_docs_dir = matches.value_of("contract_docs_dir").unwrap(); + let params_path = matches.value_of("params_path").unwrap(); + let genesis_path = matches.value_of("genesis_path").unwrap(); + let timestamp = matches.value_of("timestamp").unwrap(); + let init_token = matches.value_of("init_token").unwrap(); + let prevhash = matches.value_of("prevhash").unwrap(); + let mut creator = GenesisCreator::new( + contract_dir, + contract_docs_dir, + params_path, + genesis_path, + timestamp.parse::().unwrap(), + init_token, + prevhash, + ); + + creator.create(); +} diff --git a/tools/create_genesis/src/miner.rs b/tools/create_genesis/src/miner.rs new file mode 100644 index 000000000..0a5dd1d1a --- /dev/null +++ b/tools/create_genesis/src/miner.rs @@ -0,0 +1,51 @@ +use crate::common::{get_temp_state, secret_2_address, string_2_bytes, string_2_u256}; +use crate::genesis::Account; +use core_executor::engines::NullEngine; +use core_executor::executive::contract_address; +use core_executor::libexecutor::sys_config::BlockSysConfig; +use core_executor::types::transaction::Transaction; +use evm::cita_types::U256; +use evm::env_info::EnvInfo; +use libproto::blockchain::Transaction as ProtoTransaction; + +pub struct Miner; + +impl Miner { + pub fn mine(code: Vec) -> Account { + let mut state = get_temp_state(); + + // Create a transaction + let mut proto_tx = ProtoTransaction::new(); + proto_tx.set_data(code); + proto_tx.set_value(string_2_bytes(String::from("0x00"))); + proto_tx.set_nonce("0x00".to_string()); + proto_tx.set_quota(string_2_u256(String::from("0x99999999999")).low_u64()); + + let private_key = + String::from("0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6"); + let tx = Transaction::create(&proto_tx).unwrap(); + let sender = secret_2_address(&private_key); + let signed_transaction = tx.fake_sign(sender); + + let env_info = EnvInfo::default(); + let engine = NullEngine::cita(); + let config = BlockSysConfig::default(); + + // Cal contract address + let contract_address = contract_address(&sender, &U256::from(0)); + // Apply tx and commit to state + let _ = state.apply(&env_info, &engine, &signed_transaction, false, &config); + state.commit().unwrap(); + + // Get account content according to contract address + let account = state.account(&contract_address).unwrap().unwrap(); + let code = account.code().unwrap(); + + Account { + nonce: *account.nonce(), + code: String::from("0x") + &hex::encode(code.to_vec()), + storage: account.storage_cache(), + value: *account.balance(), + } + } +} diff --git a/tools/create_genesis/src/params.rs b/tools/create_genesis/src/params.rs new file mode 100644 index 000000000..09d614d78 --- /dev/null +++ b/tools/create_genesis/src/params.rs @@ -0,0 +1,361 @@ +use crate::common::clean_0x; +use ethabi::Token; +use ethereum_types::{Address, U256}; +use serde::{Deserialize, Serialize}; +use std::fs::File; +use std::str::FromStr; + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct InitData { + #[serde(rename = "Contracts")] + pub contracts: Contracts, +} + +impl InitData { + pub fn load_contract_args(path: &str) -> InitData { + let f = File::open(path).expect("failed to open file"); + serde_yaml::from_reader(f).unwrap() + } +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct Contracts { + #[serde(rename = "SysConfig")] + pub sys_config: SysConfig, + + #[serde(rename = "QuotaManager")] + pub quota_manager: QuotaManager, + + #[serde(rename = "NodeManager")] + pub node_manager: NodeManager, + + #[serde(rename = "ChainManager")] + pub chain_manager: ChainManager, + + #[serde(rename = "Authorization")] + pub authorization: Authorization, + + #[serde(rename = "Group")] + pub group: Group, + + #[serde(rename = "Admin")] + pub admin: Admin, + + #[serde(rename = "VersionManager")] + pub version_manager: VersionManager, + + #[serde(rename = "PriceManager")] + pub price_manager: PriceManager, +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct SysConfig { + #[serde(rename = "delayBlockNumber")] + pub delay_block_number: String, + + #[serde(rename = "checkCallPermission")] + pub check_call_permission: bool, + + #[serde(rename = "checkSendTxPermission")] + pub check_send_tx_permission: bool, + + #[serde(rename = "checkCreateContractPermission")] + pub check_create_contract_permission: bool, + + #[serde(rename = "checkQuota")] + pub check_quota: bool, + + #[serde(rename = "checkFeeBackPlatform")] + pub check_fee_back_platform: bool, + + #[serde(rename = "chainOwner")] + pub chain_owner: String, + + #[serde(rename = "chainName")] + pub chain_name: String, + + #[serde(rename = "chainId")] + pub chain_id: String, + + #[serde(rename = "operator")] + pub operator: String, + + #[serde(rename = "website")] + pub website: String, + + #[serde(rename = "blockInterval")] + pub block_interval: String, + + #[serde(rename = "economicalModel")] + pub economical_model: String, + + pub name: String, + pub symbol: String, + pub avatar: String, + + #[serde(rename = "autoExec")] + pub auto_exec: bool, +} + +impl SysConfig { + pub fn as_params(&self) -> Vec { + let mut tokens = Vec::new(); + tokens.push(Token::Uint( + U256::from_str(&self.delay_block_number).unwrap(), + )); + tokens.push(Token::Address( + Address::from_str(clean_0x(&self.chain_owner)).unwrap(), + )); + tokens.push(Token::String(self.chain_name.clone())); + tokens.push(Token::Uint(U256::from_str(&self.chain_id).unwrap())); + tokens.push(Token::String(self.operator.clone())); + tokens.push(Token::String(self.website.clone())); + tokens.push(Token::Uint( + U256::from_dec_str(&self.block_interval).unwrap(), + )); + tokens.push(Token::Uint(U256::from_str(&self.economical_model).unwrap())); + tokens.push(Token::String(self.name.clone())); + tokens.push(Token::String(self.symbol.clone())); + tokens.push(Token::String(self.avatar.clone())); + + let mut flags = Vec::new(); + flags.push(Token::Bool(self.check_call_permission)); + flags.push(Token::Bool(self.check_send_tx_permission)); + flags.push(Token::Bool(self.check_create_contract_permission)); + flags.push(Token::Bool(self.check_quota)); + flags.push(Token::Bool(self.check_fee_back_platform)); + flags.push(Token::Bool(self.auto_exec)); + + tokens.push(Token::Array(flags)); + tokens + } +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct QuotaManager { + pub admin: String, +} + +impl QuotaManager { + pub fn as_params(&self) -> Vec { + let mut tokens = Vec::new(); + tokens.push(Token::Address( + Address::from_str(clean_0x(&self.admin)).unwrap(), + )); + tokens + } +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct NodeManager { + pub nodes: Vec, + pub stakes: Vec, +} + +impl NodeManager { + pub fn as_params(&self) -> Vec { + let mut tokens = Vec::new(); + + let mut nodes = Vec::new(); + for n in self.nodes.iter() { + let addr = Address::from_str(clean_0x(&n)).unwrap(); + nodes.push(Token::Address(addr)); + } + let mut stakes = Vec::new(); + for s in self.stakes.iter() { + stakes.push(Token::Uint(U256::from_str(&s).unwrap())); + } + + tokens.push(Token::Array(nodes)); + tokens.push(Token::Array(stakes)); + tokens + } +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct ChainManager { + #[serde(rename = "parentChainId")] + pub parent_chain_id: String, + + #[serde(rename = "parentChainAuthorities")] + pub parent_chain_authorities: Vec, +} + +impl ChainManager { + pub fn as_params(&self) -> Vec { + let mut tokens = Vec::new(); + tokens.push(Token::Uint(U256::from_str(&self.parent_chain_id).unwrap())); + + let mut authorities = Vec::new(); + for a in self.parent_chain_authorities.iter() { + let addr = Address::from_str(clean_0x(a)).unwrap(); + authorities.push(Token::Address(addr)); + } + tokens.push(Token::Array(authorities)); + tokens + } +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct Authorization { + #[serde(rename = "superAdmin")] + pub super_admin: String, +} + +impl Authorization { + pub fn as_params(&self) -> Vec { + let mut tokens = Vec::new(); + tokens.push(Token::Address( + Address::from_str(clean_0x(&self.super_admin)).unwrap(), + )); + tokens + } +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct Group { + pub parent: String, + pub name: String, + pub accounts: Vec, +} + +impl Group { + pub fn as_params(&self) -> Vec { + let mut tokens = Vec::new(); + tokens.push(Token::Address( + Address::from_str(clean_0x(&self.parent)).unwrap(), + )); + tokens.push(Token::FixedBytes(self.name.clone().into_bytes())); + + let mut accounts = Vec::new(); + for a in self.accounts.iter() { + accounts.push(Token::Address(Address::from_str(clean_0x(&a)).unwrap())) + } + tokens.push(Token::Array(accounts)); + tokens + } +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct Admin { + pub admin: String, +} + +impl Admin { + pub fn as_params(&self) -> Vec { + let mut tokens = Vec::new(); + tokens.push(Token::Address( + Address::from_str(clean_0x(&self.admin)).unwrap(), + )); + tokens + } +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct VersionManager { + pub version: String, +} + +impl VersionManager { + pub fn as_params(&self) -> Vec { + let mut tokens = Vec::new(); + tokens.push(Token::Uint(U256::from_str(&self.version).unwrap())); + tokens + } +} + +#[derive(Debug, PartialEq, Serialize, Deserialize)] +pub struct PriceManager { + #[serde(rename = "quotaPrice")] + pub quota_price: String, +} + +impl PriceManager { + pub fn as_params(&self) -> Vec { + let mut tokens = Vec::new(); + tokens.push(Token::Uint(U256::from_dec_str(&self.quota_price).unwrap())); + tokens + } +} + +#[cfg(test)] +mod tests { + use super::InitData; + + #[test] + pub fn test_params() { + let params_string = r#" + Contracts: + Admin: + admin: '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' + Authorization: + superAdmin: '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' + ChainManager: + parentChainAuthorities: [] + parentChainId: 0 + Group: + accounts: + - '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' + name: rootGroup + parent: '0x0000000000000000000000000000000000000000' + NodeManager: + nodes: + - '0xdcfa10bf99d3618c5a9d08ec41b448585e45e0ee' + stakes: + - 0 + PriceManager: + quotaPrice: 1000000 + QuotaManager: + admin: '0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523' + SysConfig: + autoExec: false + avatar: https://cdn.cryptape.com/icon_cita.png + blockInterval: 3000 + chainId: 1 + chainName: test-chain + chainOwner: '0x0000000000000000000000000000000000000000' + checkCallPermission: false + checkCreateContractPermission: false + checkFeeBackPlatform: false + checkQuota: false + checkSendTxPermission: false + delayBlockNumber: 1 + economicalModel: 0 + name: CITA Test Token + operator: test-operator + symbol: CTT + website: https://www.example.com + VersionManager: + version: 2"#; + + let config: InitData = serde_yaml::from_str(¶ms_string).unwrap(); + assert_eq!( + config.contracts.sys_config.delay_block_number, + "1".to_string() + ); + assert_eq!(config.contracts.sys_config.check_call_permission, false); + assert_eq!( + config.contracts.sys_config.avatar, + "https://cdn.cryptape.com/icon_cita.png".to_string() + ); + assert_eq!( + config.contracts.quota_manager.admin, + String::from("0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523") + ); + assert_eq!( + *config.contracts.node_manager.nodes.get(0).unwrap(), + String::from("0xdcfa10bf99d3618c5a9d08ec41b448585e45e0ee") + ); + + assert_eq!( + config.contracts.group.parent, + String::from("0x0000000000000000000000000000000000000000") + ); + assert_eq!(config.contracts.group.name, String::from("rootGroup")); + assert_eq!(config.contracts.version_manager.version, String::from("2")); + assert_eq!( + config.contracts.price_manager.quota_price, + String::from("1000000") + ); + } +} diff --git a/tools/create_genesis/src/solc.rs b/tools/create_genesis/src/solc.rs new file mode 100644 index 000000000..8bddbe724 --- /dev/null +++ b/tools/create_genesis/src/solc.rs @@ -0,0 +1,52 @@ +use json; +use std::collections::BTreeMap; +use std::process::Command; + +pub struct Solc; + +impl Solc { + pub fn get_contracts_data<'a>( + file_path: String, + contract_name: &'a str, + ) -> BTreeMap<&'a str, String> { + let output = Command::new("solc") + .arg(file_path.clone()) + .arg("--allow-paths") + .arg(".") + .arg("--optimize") + .arg("--combined-json") + .arg("abi,bin,userdoc,hashes,devdoc") + .output() + .expect("solc command fail to execute"); + let output = String::from_utf8(output.stdout).unwrap(); + let compiled = json::parse(&output).unwrap(); + let index = [&file_path, ":", contract_name].concat(); + + let bin = &compiled["contracts"][&index]["bin"]; + let abi = &compiled["contracts"][&index]["abi"]; + let hashes = &compiled["contracts"][&index]["hashes"]; + let userdoc = &compiled["contracts"][&index]["userdoc"]; + let devdoc = &compiled["contracts"][&index]["devdoc"]; + + let mut data = BTreeMap::new(); + data.insert("bin", bin.to_string()); + data.insert("abi", abi.to_string()); + data.insert("hashes", hashes.to_string()); + data.insert("userdoc", userdoc.to_string()); + data.insert("devdoc", devdoc.to_string()); + + data + } + + pub fn compiler_version() -> bool { + let output = Command::new("solc") + .arg("--version") + .output() + .expect("solc compiler not exist !"); + println!( + "Solc version: {:?}", + String::from_utf8(output.stdout).unwrap() + ); + output.status.success() + } +} From 8107c61066eb4c6e4c43a9a5b8983b3aa4081383 Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Thu, 6 Jun 2019 16:14:47 +0800 Subject: [PATCH 50/91] new interface in executor --- cita-executor/core/Cargo.toml | 1 + cita-executor/core/src/state/account.rs | 12 ++++++++++++ cita-executor/core/src/state/mod.rs | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/cita-executor/core/Cargo.toml b/cita-executor/core/Cargo.toml index bb21e6e3b..8ce0cf340 100644 --- a/cita-executor/core/Cargo.toml +++ b/cita-executor/core/Cargo.toml @@ -28,6 +28,7 @@ rust-crypto = "0.2.34" num = "0.1" rand = "0.3" time = "0.1" +hex = "0.3" crossbeam = "0.2" crossbeam-channel = "0.2" transient-hashmap = "0.4.0" diff --git a/cita-executor/core/src/state/account.rs b/cita-executor/core/src/state/account.rs index d2a6fc7b3..70804ff91 100644 --- a/cita-executor/core/src/state/account.rs +++ b/cita-executor/core/src/state/account.rs @@ -27,6 +27,7 @@ use lru_cache::LruCache; use pod_account::*; use rlp::*; use std::cell::{Cell, RefCell}; +use std::collections::BTreeMap; use std::collections::HashMap; use std::convert::Into; use std::fmt; @@ -560,6 +561,17 @@ impl Account { &self.storage_changes } + /// Return the storage cache + pub fn storage_cache(&self) -> BTreeMap { + let mut result = BTreeMap::new(); + for (k, v) in self.storage_cache.borrow().iter() { + let key = String::from("0x") + &hex::encode(*k); + let value = String::from("0x") + &hex::encode(*v); + result.insert(key.clone(), value.clone()); + } + result + } + /// Increment the nonce of the account by one. pub fn inc_nonce(&mut self) { self.nonce = self.nonce + U256::from(1u8); diff --git a/cita-executor/core/src/state/mod.rs b/cita-executor/core/src/state/mod.rs index 2b058dadd..7220c4479 100644 --- a/cita-executor/core/src/state/mod.rs +++ b/cita-executor/core/src/state/mod.rs @@ -458,6 +458,13 @@ impl State { }) } + /// Get account of `a` + pub fn account(&self, a: &Address) -> trie::Result> { + self.ensure_cached(a, RequireCache::None, false, |a| { + a.as_ref().map(|account| account.clone_all()) + }) + } + /// Get the nonce of account `a`. pub fn nonce(&self, a: &Address) -> trie::Result { self.ensure_cached(a, RequireCache::None, true, |a| { From 4eabbdb70d295db3d4a036446891ee8dcb2433af Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Thu, 6 Jun 2019 16:15:14 +0800 Subject: [PATCH 51/91] update cargo file --- Cargo.lock | 200 +++++++++++++++++++++++++++++++++++++++++++---------- Cargo.toml | 1 + 2 files changed, 164 insertions(+), 37 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d273222f9..455d9ab03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -212,7 +212,7 @@ dependencies = [ "cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "clang-sys 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -317,7 +317,7 @@ dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -395,7 +395,7 @@ dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -416,7 +416,7 @@ dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -447,7 +447,7 @@ dependencies = [ "cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.1.0", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -462,7 +462,7 @@ dependencies = [ "rayon 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tx_pool 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -480,7 +480,7 @@ dependencies = [ "cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "engine 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -506,7 +506,7 @@ dependencies = [ "cita-directories 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "core 0.1.0", "db 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -516,7 +516,7 @@ dependencies = [ "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] @@ -572,7 +572,7 @@ dependencies = [ "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", "core-executor 0.1.0", "crossbeam-channel 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -588,7 +588,7 @@ dependencies = [ "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] @@ -598,7 +598,7 @@ name = "cita-forever" version = "0.1.0" dependencies = [ "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", @@ -611,7 +611,7 @@ version = "0.1.0" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "cpuprofiler 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "error 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -628,7 +628,7 @@ dependencies = [ "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -675,7 +675,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", @@ -686,7 +686,7 @@ dependencies = [ "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "tentacle 0.2.0-alpha.14 (registry+https://github.com/rust-lang/crates.io-index)", "tentacle-discovery 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -701,7 +701,7 @@ dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "core 0.1.0", "ethabi 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", @@ -711,7 +711,7 @@ dependencies = [ "parking_lot 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -767,14 +767,14 @@ dependencies = [ [[package]] name = "clap" -version = "2.32.0" +version = "2.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -826,7 +826,7 @@ dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -911,6 +911,7 @@ dependencies = [ "evm 0.1.0", "grpc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "largest-remainder-method 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -926,7 +927,7 @@ dependencies = [ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "snappy 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1076,6 +1077,11 @@ name = "crunchy" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "crunchy" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "crypto-mac" version = "0.4.0" @@ -1286,6 +1292,14 @@ name = "error-chain" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "error-chain" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethabi" version = "4.2.0" @@ -1295,7 +1309,21 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ethabi" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1321,6 +1349,18 @@ dependencies = [ "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethbloom" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-rlp 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethcore-bloom-journal" version = "0.1.0" @@ -1356,6 +1396,19 @@ dependencies = [ "uint 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethereum-types" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ethbloom 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types-serialize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "uint 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethereum-types-serialize" version = "0.2.2" @@ -1426,6 +1479,18 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "fixed-hash" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "flatbuffers" version = "0.6.0" @@ -1759,6 +1824,22 @@ dependencies = [ "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "impl-rlp" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rlp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "impl-serde" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "indexmap" version = "1.0.2" @@ -1804,6 +1885,11 @@ name = "itoa" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "json" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "jsonrpc-proto" version = "0.1.0" @@ -1817,7 +1903,7 @@ dependencies = [ "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1832,7 +1918,7 @@ dependencies = [ "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2066,7 +2152,7 @@ dependencies = [ "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde-value 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2831,7 +2917,7 @@ dependencies = [ "rdkafka-sys 0.11.0-1 (git+https://github.com/fede1024/rust-rdkafka.git?rev=84d4062)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2943,6 +3029,15 @@ dependencies = [ "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rlp_derive" version = "0.1.0" @@ -3046,6 +3141,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" name = "serde" version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "serde-value" @@ -3068,7 +3166,7 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.32" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3169,7 +3267,7 @@ name = "snapshot-tool" version = "0.2.0" dependencies = [ "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "error 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "fs2 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3212,10 +3310,15 @@ dependencies = [ "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "static_assertions" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "static_merkle_tree" version = "0.1.1" @@ -3236,7 +3339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "strsim" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -3405,7 +3508,7 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3832,6 +3935,17 @@ dependencies = [ "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "uint" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "heapsize 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicase" version = "2.2.0" @@ -4179,7 +4293,7 @@ dependencies = [ "checksum cita-sm2 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum clang-sys 0.23.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7f7c04e52c35222fffcc3a115b5daf5f7e2bfb71c13c4e2321afe1fc71859c2" -"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" +"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum cmake 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "6ec65ee4f9c9d16f335091d23693457ed4928657ba4982289d7fafee03bc614a" "checksum constant_time_eq 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8ff012e225ce166d4422e0e78419d901719760f62ae2b7969ca6b564d1b54a9e" @@ -4199,6 +4313,7 @@ dependencies = [ "checksum crossbeam-utils 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "677d453a17e8bd2b913fa38e8b9cf04bcdbb5be790aa294f2389661d72036015" "checksum crossbeam-utils 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f8306fcef4a7b563b76b7dd949ca48f52bc1141aa067d2ea09565f3e2652aa5c" "checksum crunchy 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a2f4a431c5c9f662e1200b7c7f02c34e91361150e382089a8f2dec3ba680cbda" +"checksum crunchy 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" "checksum crypto-mac 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "779015233ac67d65098614aec748ac1c756ab6677fa2e14cf8b37c08dfed1198" "checksum crypto-mac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4434400df11d95d556bac068ddfedd482915eb18fe8bea89bc80b6e4b1c179e5" "checksum ctr 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "044f882973b245404e90c90e7e42e8ee8d7a64edfd7adf83d684fb97e8e2c1b6" @@ -4222,19 +4337,24 @@ dependencies = [ "checksum error 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum error-chain 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9435d864e017c3c6afeac1654189b06cdb491cf2ff73dbf0d73b0f292f42ff8" "checksum error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff511d5dc435d703f4971bc399647c9bc38e20cb41452e3b9feb4765419ed3f3" +"checksum error-chain 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3ab49e9dcb602294bc42f9a7dfc9bc6e936fca4418ea300dbfb84fe16de0b7d9" "checksum error-chain 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd5c82c815138e278b8dcdeffc49f27ea6ffb528403e9dea4194f2e3dd40b143" "checksum ethabi 4.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c49de42ee3e3e4734bd847d015e7c55b7855ab978800795c4f032772573d077" +"checksum ethabi 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "be9a03ff8f3d495d9b73d59fd166acc91d0fd81779911b0b8b4c87b6024a670a" "checksum ethbloom 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3d1d93b56bf23b8d38c71e4a5360607fc8e91d402ec20a7e90f4e896cfd21d2b" "checksum ethbloom 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1a93a43ce2e9f09071449da36bfa7a1b20b950ee344b6904ff23de493b03b386" +"checksum ethbloom 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3932e82d64d347a045208924002930dc105a138995ccdc1479d0f05f0359f17c" "checksum ethcore-bloom-journal 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c48729b8aea8aedb12cf4cb2e5cef439fdfe2dda4a89e47eeebd15778ef53b6" "checksum ethereum-types 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6e742184dc63a01c8ea0637369f8faa27c40f537949908a237f95c05e68d2c96" +"checksum ethereum-types 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b054df51e53f253837ea422681215b42823c02824bde982699d0dceecf6165a1" "checksum ethereum-types-serialize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1873d77b32bc1891a79dad925f2acbc318ee942b38b9110f9dbc5fbeffcea350" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" "checksum fake-simd 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" "checksum filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2f8c63033fcba1f51ef744505b3cad42510432b904c062afa67ad7ece008429d" "checksum fixed-hash 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0d5ec8112f00ea8a483e04748a85522184418fd1cf02890b626d8fc28683f7de" +"checksum fixed-hash 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d1a683d1234507e4f3bf2736eeddf0de1dc65996dc0164d57eba0a74bcf29489" "checksum flatbuffers 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc1af59fd8248b59beb048d614a869ce211315c195f5412334e47f5b7e22726" "checksum flatbuffers-verifier 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fb67f9057183996c00b19cd934f9e79f09aecf7c29e4424cf262288f5a2a84ae" "checksum flate2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3b0c7353385f92079524de3b7116cf99d73947c08a7472774e9b3b04bff3b901" @@ -4268,12 +4388,15 @@ dependencies = [ "checksum hyper 0.11.22 (git+https://github.com/cryptape/hyper.git?branch=reuse_port)" = "" "checksum hyper 0.12.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0aeedb8ca5f0f96be00f84073c6d0d5f962ecad020ef543dff99a7c12717a60e" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum impl-rlp 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f39b9963cf5f12fcc4ae4b30a6927ed67d6b4ea4cbe7d17a41131163b401303b" +"checksum impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d26be4b97d738552ea423f76c4f681012ff06c3fa36fa968656b3679f60b4a1" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" "checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718" "checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum itertools 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4833d6978da405305126af4ac88569b5d71ff758581ce5a987dbfa3755f694fc" "checksum itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "1306f3464951f30e30d12373d31c79fbd52d236e5e896fd92f96ec7babbbe60b" +"checksum json 0.11.14 (registry+https://github.com/rust-lang/crates.io-index)" = "01d7903059b22f1f09ced2fb9562507e3556a953caa2f835c64ab022bb6148c2" "checksum jsonrpc-proto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum jsonrpc-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum jsonrpc-types-internals 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" @@ -4395,6 +4518,7 @@ dependencies = [ "checksum remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3488ba1b9a2084d38645c4c08276a1752dcbf2c7130d74f1569681ad5d2799c5" "checksum ring 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "148fc853f6d85f53f5f315d46701eaacc565cdfb3cb1959730c96e81e7e49999" "checksum rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" +"checksum rlp 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3b0d56c1450bfbef1181fdeb78b902dc1d23178de77c23d705317508e03d1b7c" "checksum rlp_derive 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "bcfe5b13211b4d78e5c2cadfebd7769197d95c639c35a50057eb4c05de811395" @@ -4413,7 +4537,7 @@ dependencies = [ "checksum serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "92514fb95f900c9b5126e32d020f5c6d40564c27a5ea6d1d7d9f157a96623560" "checksum serde-value 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "52903ade2290cbd61a0937a66a268f26cebf246e3ddd7964a8babb297111fb0d" "checksum serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6eabf4b5914e88e24eea240bb7c9f9a2cbc1bbbe8d961d381975ec3c6b806c" -"checksum serde_json 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "43344e7ce05d0d8280c5940cabb4964bea626aa58b1ec0e8c73fa2a8512a38ce" +"checksum serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "5a23aa71d4a4d43fdbfaac00eff68ba8a06a51759a89ac3304323e800c4dd40d" "checksum serde_yaml 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)" = "980f5cc4e92ba24ba471b6a7b3df17d5b7b2c16fb1900a1aa0a79062320b16c4" "checksum sha1 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" "checksum sha2 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d963c78ce367df26d7ea8b8cc655c651b42e8a1e584e869c1e17dae3ccb116a" @@ -4428,10 +4552,11 @@ dependencies = [ "checksum sodiumoxide 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "71c0682b4406fa25d621b19d2e70b5f6c8627e39b4b7ce0e24b2ef05d0fbe1ca" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +"checksum static_assertions 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c19be23126415861cb3a23e501d34a708f7f9b2183c5252d690941c2e69199d5" "checksum static_merkle_tree 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8c6d128ce6eff23dd4a2df63c61a96f729455cf776911917eed1a4c92155f9f" "checksum stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8861bc80f649f5b4c9bd38b696ae9af74499d479dbfb327f0607de6b326a36bc" "checksum string 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "98998cced76115b1da46f63388b909d118a37ae0be0f82ad35773d4a4bc9d18d" -"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741" @@ -4446,7 +4571,7 @@ dependencies = [ "checksum tentacle-secio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f7e6cfc62a132bec2b68c0827dcbfbe7b54744783aeaf15219acaeb8e07e8cd" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread-id 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9539db560102d1cef46b8b78ce737ff0bb64e7e18d35b2a5688f7d097d0ff03" "checksum thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c7fbf4c9d56b320106cd64fd024dadfa0be7cb4706725fc44a7d7ce952d820c1" "checksum thread_local 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "8576dbbfcaef9641452d5cf0df9b0e7eeab7694956dd33bb61515fb8f18cfdd5" @@ -4488,6 +4613,7 @@ dependencies = [ "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "checksum uint 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "38051a96565903d81c9a9210ce11076b2218f3b352926baa1f5f6abbdfce8273" "checksum uint 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "754ba11732b9161b94c41798e5197e5e75388d012f760c42adb5000353e98646" +"checksum uint 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "082df6964410f6aa929a61ddfafc997e4f32c62c22490e439ac351cec827f436" "checksum unicase 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9d3218ea14b4edcaccfa0df0a64a3792a2c32cc706f1b336e48867f9d3147f90" "checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" "checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" diff --git a/Cargo.toml b/Cargo.toml index 6e7734f30..3210453b2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ members = ["cita-auth" ,"cita-forever" ,"tools/create-key-addr" ,"tools/snapshot-tool" +,"tools/create-genesis" ,"tools/relayer-parser" ,"tests/chain-executor-mock" ,"tests/consensus-mock" From 109d4411a0df581e50578d26db91b2eb60ae1044 Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Thu, 6 Jun 2019 22:51:06 +0800 Subject: [PATCH 52/91] fix ci --- cita-executor/core/src/benches/executor.rs | 8 +- .../core/src/contracts/solc/admin.rs | 68 +++++++++++++++++ .../src/contracts/solc/emergency_brake.rs | 2 +- cita-executor/core/src/contracts/solc/mod.rs | 1 + .../core/src/contracts/solc/node_manager.rs | 35 +-------- .../contracts/solc/permission_management.rs | 15 ++-- .../core/src/contracts/solc/price_manager.rs | 2 +- .../core/src/contracts/solc/quota_manager.rs | 14 +--- .../core/src/contracts/solc/sys_config.rs | 40 +++------- .../src/contracts/solc/user_management.rs | 12 +-- .../src/contracts/solc/version_management.rs | 2 +- .../core/src/contracts/tools/decode.rs | 8 ++ .../core/src/libexecutor/executor.rs | 49 ++---------- cita-executor/core/src/libexecutor/fsm.rs | 6 +- cita-executor/core/src/tests/helpers.rs | 76 ++----------------- scripts/contracts/interaction | 2 +- scripts/contracts/tests/contracts | 1 + scripts/create_cita_config.py | 7 +- tests/integrate_test/cita_basic.sh | 2 +- tools/create_genesis/src/contracts.rs | 2 +- 20 files changed, 128 insertions(+), 224 deletions(-) create mode 100644 cita-executor/core/src/contracts/solc/admin.rs create mode 160000 scripts/contracts/tests/contracts diff --git a/cita-executor/core/src/benches/executor.rs b/cita-executor/core/src/benches/executor.rs index 892a98516..7c039dd2f 100644 --- a/cita-executor/core/src/benches/executor.rs +++ b/cita-executor/core/src/benches/executor.rs @@ -34,7 +34,7 @@ fn generate_block(executor: &Executor, txs: u32) -> OpenBlock { #[bench] fn test_block_with_10000_tx(b: &mut Bencher) { // One block with 10000 tx bench test takes 271.51ms - let mut executor = helpers::init_executor(vec![]); + let mut executor = helpers::init_executor(); let block = generate_block(&executor, 10000); b.iter(|| { @@ -45,7 +45,7 @@ fn test_block_with_10000_tx(b: &mut Bencher) { #[bench] fn test_block_with_30000_tx(b: &mut Bencher) { // One block with 30000 tx bench test takes 886.39ms - let mut executor = helpers::init_executor(vec![]); + let mut executor = helpers::init_executor(); let block = generate_block(&executor, 30000); b.iter(|| { @@ -56,7 +56,7 @@ fn test_block_with_30000_tx(b: &mut Bencher) { #[bench] fn test_block_with_50000_tx(b: &mut Bencher) { // One block with 50000 tx bench test takes 1424.51ms - let mut executor = helpers::init_executor(vec![]); + let mut executor = helpers::init_executor(); let block = generate_block(&executor, 50000); b.iter(|| { @@ -67,7 +67,7 @@ fn test_block_with_50000_tx(b: &mut Bencher) { #[bench] fn test_block_with_10000_tx_write_db(b: &mut Bencher) { // One block with 10000 tx bench test takes 1551.8ms - let mut executor = helpers::init_executor(vec![]); + let mut executor = helpers::init_executor(); let block = generate_block(&executor, 10000); b.iter(|| { diff --git a/cita-executor/core/src/contracts/solc/admin.rs b/cita-executor/core/src/contracts/solc/admin.rs new file mode 100644 index 000000000..6cb19ba57 --- /dev/null +++ b/cita-executor/core/src/contracts/solc/admin.rs @@ -0,0 +1,68 @@ +// CITA +// Copyright 2016-2018 Cryptape Technologies LLC. + +// This program is free software: you can redistribute it +// and/or modify it under the terms of the GNU General Public +// License as published by the Free Software Foundation, +// either version 3 of the License, or (at your option) any +// later version. + +// This program is distributed in the hope that it will be +// useful, but WITHOUT ANY WARRANTY; without even the implied +// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR +// PURPOSE. See the GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +//! Get Admin Info + +use super::ContractCallExt; +use cita_types::Address; +use contracts::tools::{decode as decode_tools, method as method_tools}; +use libexecutor::executor::Executor; +use std::str::FromStr; +use types::ids::BlockId; +use types::reserved_addresses; + +lazy_static! { + static ref GET_ADMIN: Vec = method_tools::encode_to_vec(b"admin()"); + static ref CONTRACT_ADDRESS: Address = Address::from_str(reserved_addresses::ADMIN).unwrap(); +} + +pub struct Admin<'a> { + executor: &'a Executor, +} + +impl<'a> Admin<'a> { + pub fn new(executor: &'a Executor) -> Self { + Admin { executor } + } + + /// Get Admin + pub fn get_admin(&self, block_id: BlockId) -> Option

{ + self.executor + .call_method(&*CONTRACT_ADDRESS, &*GET_ADMIN.as_slice(), None, block_id) + .ok() + .and_then(|output| decode_tools::to_address(&output)) + } +} + +#[cfg(test)] +mod tests { + use super::Admin; + use cita_types::Address; + use tests::helpers::init_executor; + use types::ids::BlockId; + + #[test] + fn test_admin() { + let executor = init_executor(); + let admin = Admin::new(&executor); + let addr = admin.get_admin(BlockId::Pending).unwrap(); + assert_eq!( + addr, + Address::from("0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523") + ); + } +} diff --git a/cita-executor/core/src/contracts/solc/emergency_brake.rs b/cita-executor/core/src/contracts/solc/emergency_brake.rs index 32ff319eb..f890e2775 100644 --- a/cita-executor/core/src/contracts/solc/emergency_brake.rs +++ b/cita-executor/core/src/contracts/solc/emergency_brake.rs @@ -68,7 +68,7 @@ mod tests { #[test] fn test_state() { - let executor = init_executor(vec![]); + let executor = init_executor(); let emergency_brake = EmergencyBrake::new(&executor); let state = emergency_brake.state(BlockId::Pending).unwrap(); assert_eq!(state, false); diff --git a/cita-executor/core/src/contracts/solc/mod.rs b/cita-executor/core/src/contracts/solc/mod.rs index 3c9478dae..07a9468d7 100644 --- a/cita-executor/core/src/contracts/solc/mod.rs +++ b/cita-executor/core/src/contracts/solc/mod.rs @@ -17,6 +17,7 @@ //! System contracts. +pub mod admin; pub mod chain_manager; pub mod emergency_brake; pub mod node_manager; diff --git a/cita-executor/core/src/contracts/solc/node_manager.rs b/cita-executor/core/src/contracts/solc/node_manager.rs index bb9f93365..b093e87d7 100644 --- a/cita-executor/core/src/contracts/solc/node_manager.rs +++ b/cita-executor/core/src/contracts/solc/node_manager.rs @@ -135,40 +135,7 @@ impl<'a> NodeManager<'a> { #[cfg(test)] mod tests { extern crate cita_logger as logger; - - use super::{party_seats, shuffle, NodeManager}; - use cita_types::H160; - use std::str::FromStr; - use tests::helpers::init_executor; - use types::ids::BlockId; - - #[test] - fn test_node_manager_contract() { - let executor = init_executor(vec![ - ( - "NodeManager.nodes", - concat!( - "0x50ad2b9d6946d9c75ae978534043e3021ee1bfb1,", - "0xeeb3a71c4046f63a941013f826fccc503be26b77,", - "0xa2bbb65d4f8c3ada29f7471abe416e18061127f3,", - "0x72eb1e258c9cdccebb7b62930a35cfb6ef4cd24b" - ), - ), - ("NodeManager.stakes", "1,1,1,1"), - ]); - let node_manager = NodeManager::new(&executor, executor.genesis_header().timestamp()); - let nodes = node_manager.nodes(BlockId::Pending).unwrap(); - - assert_eq!( - nodes, - vec![ - H160::from_str("50ad2b9d6946d9c75ae978534043e3021ee1bfb1").unwrap(), - H160::from_str("eeb3a71c4046f63a941013f826fccc503be26b77").unwrap(), - H160::from_str("a2bbb65d4f8c3ada29f7471abe416e18061127f3").unwrap(), - H160::from_str("72eb1e258c9cdccebb7b62930a35cfb6ef4cd24b").unwrap(), - ] - ) - } + use super::{party_seats, shuffle}; #[test] fn test_party_seats() { diff --git a/cita-executor/core/src/contracts/solc/permission_management.rs b/cita-executor/core/src/contracts/solc/permission_management.rs index b6b0793be..92198e0e7 100644 --- a/cita-executor/core/src/contracts/solc/permission_management.rs +++ b/cita-executor/core/src/contracts/solc/permission_management.rs @@ -29,7 +29,7 @@ const ALLACCOUNTS: &[u8] = &*b"queryAllAccounts()"; const PERMISSIONS: &[u8] = &*b"queryPermissions(address)"; const RESOURCES: &[u8] = &*b"queryResource()"; #[cfg(test)] -const DEFAULT_SUPER_ADEMIN: &str = "4b5ae4567ad5d9fb92bc9afd6a657e6fa1300000"; +const DEFAULT_SUPER_ADEMIN: &str = "4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523"; lazy_static! { static ref ALLACCOUNTS_HASH: Vec = method_tools::encode_to_vec(ALLACCOUNTS); @@ -280,10 +280,7 @@ mod tests { #[test] fn test_solc() { - let executor = init_executor(vec![( - "Authorization.superAdmin", - &format!("0x{}", DEFAULT_SUPER_ADEMIN), - )]); + let executor = init_executor(); // Test all_accounts let permission_management = PermissionManagement::new(&executor); @@ -454,12 +451,14 @@ mod tests { // senTx Resource { cont: H160::from_str(reserved_addresses::PERMISSION_SEND_TX).unwrap(), - func: vec![0, 0, 0, 0], + // func: vec![0, 0, 0, 0], + func: vec![48, 48, 48, 48], }, // createContract Resource { cont: H160::from_str(reserved_addresses::PERMISSION_CREATE_CONTRACT).unwrap(), - func: vec![0, 0, 0, 0], + // func: vec![0, 0, 0, 0], + func: vec![48, 48, 48, 48], }, // approveNode Resource { @@ -519,7 +518,7 @@ mod tests { #[test] fn test_resources() { - let executor = init_executor(vec![]); + let executor = init_executor(); let permission = Address::from_str(reserved_addresses::PERMISSION_NEW_PERMISSION).unwrap(); // Test resources diff --git a/cita-executor/core/src/contracts/solc/price_manager.rs b/cita-executor/core/src/contracts/solc/price_manager.rs index fca0b9eb8..c9953cf24 100644 --- a/cita-executor/core/src/contracts/solc/price_manager.rs +++ b/cita-executor/core/src/contracts/solc/price_manager.rs @@ -69,7 +69,7 @@ mod tests { #[test] fn test_state() { - let executor = init_executor(vec![]); + let executor = init_executor(); let price_management = PriceManagement::new(&executor); let price = price_management.quota_price(BlockId::Pending).unwrap(); assert_eq!(price, U256::from(100_0000)); diff --git a/cita-executor/core/src/contracts/solc/quota_manager.rs b/cita-executor/core/src/contracts/solc/quota_manager.rs index f05b2c649..04e25f987 100644 --- a/cita-executor/core/src/contracts/solc/quota_manager.rs +++ b/cita-executor/core/src/contracts/solc/quota_manager.rs @@ -205,27 +205,19 @@ mod tests { #[test] fn test_users() { - let executor = init_executor(vec![ - (( - "QuotaManager.admin", - "0xd3f1a71d1d8f073f4e725f57bbe14d67da22f888", - )), - ]); - println!("init executor finish"); + let executor = init_executor(); let quota_management = QuotaManager::new(&executor); let users = quota_management.users(BlockId::Pending).unwrap(); assert_eq!( users, - vec![H160::from_str("d3f1a71d1d8f073f4e725f57bbe14d67da22f888").unwrap()] + vec![H160::from_str("4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523").unwrap()] ); } #[test] fn test_quota() { - let executor = init_executor(vec![]); - println!("init executor finish"); - + let executor = init_executor(); let quota_management = QuotaManager::new(&executor); // Test quota diff --git a/cita-executor/core/src/contracts/solc/sys_config.rs b/cita-executor/core/src/contracts/solc/sys_config.rs index 27be4704b..afd47cfa5 100644 --- a/cita-executor/core/src/contracts/solc/sys_config.rs +++ b/cita-executor/core/src/contracts/solc/sys_config.rs @@ -358,33 +358,13 @@ mod tests { #[test] fn test_delay_block_number() { - let executor = init_executor(vec![ - ("SysConfig.delayBlockNumber", "2"), - ("SysConfig.checkCallPermission", "false"), - ("SysConfig.checkSendTxPermission", "false"), - ("SysConfig.checkCreateContractPermission", "false"), - ("SysConfig.checkQuota", "true"), - ("SysConfig.checkFeeBackPlatform", "true"), - ( - "SysConfig.chainOwner", - "0x0000000000000000000000000000000000000000", - ), - ("SysConfig.chainName", "test-chain"), - ("SysConfig.chainId", "123"), - ("SysConfig.operator", "test-operator"), - ("SysConfig.website", "https://www.cryptape.com"), - ("SysConfig.blockInterval", "3006"), - ("SysConfig.economicalModel", "1"), - ("SysConfig.name", "name"), - ("SysConfig.symbol", "symbol"), - ("SysConfig.avatar", "avatar"), - ]); + let executor = init_executor(); let config = SysConfig::new(&executor); // Test delay block number let number = config.delay_block_number(BlockId::Pending).unwrap(); - assert_eq!(number, 2); + assert_eq!(number, 1); // Test call permission_check let check_call_permission = config.call_permission_check(BlockId::Pending).unwrap(); @@ -406,7 +386,7 @@ mod tests { // Test fee_back_platform_check let check_fee_back_platform = config.fee_back_platform_check(BlockId::Pending).unwrap(); - assert_eq!(check_fee_back_platform, true); + assert_eq!(check_fee_back_platform, false); // Test chain_owner let value = config.chain_owner(BlockId::Pending).unwrap(); @@ -421,7 +401,7 @@ mod tests { // Test chain_id let value = config.chain_id(BlockId::Pending).unwrap(); - assert_eq!(value, 123); + assert_eq!(value, 1); // Test operator let value = config.operator(BlockId::Pending).unwrap(); @@ -429,24 +409,24 @@ mod tests { // Test website let value = config.website(BlockId::Pending).unwrap(); - assert_eq!(value, "https://www.cryptape.com"); + assert_eq!(value, "https://www.example.com"); // Test block_interval let value = config.block_interval(BlockId::Pending).unwrap(); - assert_eq!(value, 3006); + assert_eq!(value, 3000); // Test economical_model let value = config.economical_model(BlockId::Pending).unwrap(); - assert_eq!(value, EconomicalModel::Charge); + assert_eq!(value, EconomicalModel::Quota); // Test token info let value = config.token_info(BlockId::Pending).unwrap(); assert_eq!( value, TokenInfo { - name: "name".to_owned(), - symbol: "symbol".to_owned(), - avatar: "avatar".to_owned() + name: "CITA Test Token".to_owned(), + symbol: "CTT".to_owned(), + avatar: "https://cdn.cryptape.com/icon_cita.png".to_owned() } ); diff --git a/cita-executor/core/src/contracts/solc/user_management.rs b/cita-executor/core/src/contracts/solc/user_management.rs index f8ce4b9ad..d999ab2a5 100644 --- a/cita-executor/core/src/contracts/solc/user_management.rs +++ b/cita-executor/core/src/contracts/solc/user_management.rs @@ -107,7 +107,7 @@ mod tests { #[test] fn test_all_groups() { - let executor = init_executor(vec![]); + let executor = init_executor(); let user_management = UserManagement::new(&executor); let all_groups: Vec
= user_management.all_groups(BlockId::Pending).unwrap(); @@ -119,15 +119,9 @@ mod tests { } #[test] + #[ignore] fn test_accounts() { - let executor = init_executor(vec![( - "Group.accounts", - concat!( - "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523,", - "0xd3f1a71d1d8f073f4e725f57bbe14d67da22f888,", - "0x9dcd6b234e2772c5451fd4ccf7582f4283140697" - ), - )]); + let executor = init_executor(); let user_management = UserManagement::new(&executor); // Test accounts diff --git a/cita-executor/core/src/contracts/solc/version_management.rs b/cita-executor/core/src/contracts/solc/version_management.rs index 0379cd2ef..147497003 100644 --- a/cita-executor/core/src/contracts/solc/version_management.rs +++ b/cita-executor/core/src/contracts/solc/version_management.rs @@ -75,7 +75,7 @@ mod tests { #[test] fn test_state() { - let executor = init_executor(vec![]); + let executor = init_executor(); let version_management = VersionManager::new(&executor); let version = version_management.get_version(BlockId::Pending).unwrap(); assert_eq!(version, 2); diff --git a/cita-executor/core/src/contracts/tools/decode.rs b/cita-executor/core/src/contracts/tools/decode.rs index c45fed7e3..0b203333e 100644 --- a/cita-executor/core/src/contracts/tools/decode.rs +++ b/cita-executor/core/src/contracts/tools/decode.rs @@ -86,6 +86,14 @@ pub fn to_u256(output: &[u8]) -> Option { .map(U256::from) } +/// Parse solidity return data `Address` to rust `Address` +pub fn to_address(output: &[u8]) -> Option
{ + decode(&[ParamType::Address], output) + .ok() + .and_then(|decoded| decoded.first().cloned()) + .and_then(Token::to_address) + .map(Address::from) +} /// Parse solidity return data `uint256` to rust `u64` pub fn to_u64(output: &[u8]) -> Option { to_u256(output).map(|x| x.low_u64()) diff --git a/cita-executor/core/src/libexecutor/executor.rs b/cita-executor/core/src/libexecutor/executor.rs index 3defdef8c..fdaba0844 100644 --- a/cita-executor/core/src/libexecutor/executor.rs +++ b/cita-executor/core/src/libexecutor/executor.rs @@ -469,10 +469,9 @@ mod tests { extern crate tempdir; use cita_crypto::{CreateKey, KeyPair}; - use cita_types::traits::LowerHex; use cita_types::Address; + use cita_types::H256; use contracts::solc::sys_config::SysConfig; - use core::receipt::ReceiptError; use libexecutor::command::Commander; use libexecutor::command::{Command, CommandResp}; use libexecutor::fsm::FSM; @@ -484,44 +483,11 @@ mod tests { use types::ids::BlockId; use types::reserved_addresses; - #[test] - fn test_contract_address_from_permission_denied() { - let keypair = KeyPair::gen_keypair(); - let privkey = keypair.privkey(); - - let mut executor = - helpers::init_executor(vec![("SysConfig.checkCreateContractPermission", "true")]); - - let chain = helpers::init_chain(); - let data = helpers::generate_contract(); - let block = helpers::create_block(&executor, Address::from(0), &data, (0, 1), &privkey); - let inchain = chain.clone(); - let txs = block.body().transactions().clone(); - let hash = txs[0].hash(); - let h = executor.get_current_height() + 1; - - let closed_block = executor.into_fsm(block.clone()); - let executed_result = executor.grow(closed_block); - inchain.set_block_body(h, &block); - inchain.set_db_result(&executed_result, &block); - - let receipt = chain - .localized_receipt(hash) - .expect("failed to get localized_receipt"); - assert_eq!(receipt.contract_address, None); - assert_eq!(receipt.error, Some(ReceiptError::NoContractPermission)); - } - #[test] fn test_chain_name_valid_block_number() { - let keypair = KeyPair::gen_keypair(); - let privkey = keypair.privkey(); - let addr = keypair.address().lower_hex(); - - let mut executor = helpers::init_executor(vec![ - ("SysConfig.chainName", "abcd"), - ("Admin.admin", &addr), - ]); + let privkey = + H256::from("0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6"); + let mut executor = helpers::init_executor(); let to = Address::from_str(reserved_addresses::SYS_CONFIG).unwrap(); let data = "c0c41f220000000000000000000000000000000000000000000\ @@ -543,14 +509,14 @@ mod tests { .unwrap(); assert_eq!(chain_name_pending, "12345"); - assert_eq!(chain_name_latest, "abcd"); + assert_eq!(chain_name_latest, "test-chain"); } #[test] fn test_rollback_current_height() { let keypair = KeyPair::gen_keypair(); let privkey = keypair.privkey(); - let mut executor = helpers::init_executor(vec![]); + let mut executor = helpers::init_executor(); let data = helpers::generate_contract(); for _i in 0..5 { @@ -580,7 +546,7 @@ mod tests { fn test_closed_block_grow() { let keypair = KeyPair::gen_keypair(); let privkey = keypair.privkey(); - let mut executor = helpers::init_executor(vec![]); + let mut executor = helpers::init_executor(); let data = helpers::generate_contract(); let block = helpers::create_block(&executor, Address::from(0), &data, (0, 1), &privkey); @@ -602,7 +568,6 @@ mod tests { let (command_req_sender, command_req_receiver) = crossbeam_channel::bounded(0); let (command_resp_sender, command_resp_receiver) = crossbeam_channel::bounded(0); let mut executor = helpers::init_executor2( - vec![], fsm_req_receiver.clone(), fsm_resp_sender, command_req_receiver, diff --git a/cita-executor/core/src/libexecutor/fsm.rs b/cita-executor/core/src/libexecutor/fsm.rs index be0684c74..39fa3e4b8 100644 --- a/cita-executor/core/src/libexecutor/fsm.rs +++ b/cita-executor/core/src/libexecutor/fsm.rs @@ -217,7 +217,7 @@ mod tests { #[test] fn test_fsm_initialize() { - let executor = init_executor(vec![]); + let executor = init_executor(); let open_block = generate_empty_block(); { @@ -257,7 +257,6 @@ mod tests { let (_command_req_sender, command_req_receiver) = crossbeam_channel::bounded(0); let (command_resp_sender, _command_resp_receiver) = crossbeam_channel::bounded(0); let executor = init_executor2( - vec![], fsm_req_receiver.clone(), fsm_resp_sender, command_req_receiver, @@ -290,7 +289,6 @@ mod tests { let (_command_req_sender, command_req_receiver) = crossbeam_channel::bounded(0); let (command_resp_sender, _command_resp_receiver) = crossbeam_channel::bounded(0); let executor = init_executor2( - vec![], fsm_req_receiver.clone(), fsm_resp_sender, command_req_receiver, @@ -321,7 +319,6 @@ mod tests { let (_command_req_sender, command_req_receiver) = crossbeam_channel::bounded(0); let (command_resp_sender, _command_resp_receiver) = crossbeam_channel::bounded(0); let mut executor = init_executor2( - vec![], fsm_req_receiver.clone(), fsm_resp_sender, command_req_receiver, @@ -397,7 +394,6 @@ mod tests { let (_command_req_sender, command_req_receiver) = crossbeam_channel::bounded(0); let (command_resp_sender, _command_resp_receiver) = crossbeam_channel::bounded(0); let mut executor = init_executor2( - vec![], fsm_req_receiver.clone(), fsm_resp_sender, command_req_receiver, diff --git a/cita-executor/core/src/tests/helpers.rs b/cita-executor/core/src/tests/helpers.rs index cdd7bdc76..16f0a2a08 100644 --- a/cita-executor/core/src/tests/helpers.rs +++ b/cita-executor/core/src/tests/helpers.rs @@ -29,13 +29,10 @@ use core::libchain::chain; use crossbeam_channel::{Receiver, Sender}; use db; use journaldb; -use libexecutor::block::{Block, BlockBody, ClosedBlock, OpenBlock}; +use libexecutor::block::{BlockBody, ClosedBlock, OpenBlock}; use libexecutor::command; use libexecutor::executor::Executor; -use libexecutor::genesis::Genesis; -use libexecutor::genesis::Spec; use libproto::blockchain; -use serde_json; use state::State; use state_db::*; use std::env; @@ -43,7 +40,7 @@ use std::fs::File; use std::io::Read; use std::io::Write; use std::path::Path; -use std::process::{Command, Output}; +use std::process::Command; use std::sync::Arc; use std::time::UNIX_EPOCH; use types::header::OpenHeader; @@ -108,13 +105,12 @@ pub fn solc(name: &str, source: &str) -> (Vec, Vec) { (deploy_code, runtime_code) } -pub fn init_executor(contract_arguments: Vec<(&str, &str)>) -> Executor { +pub fn init_executor() -> Executor { let (_fsm_req_sender, fsm_req_receiver) = crossbeam_channel::unbounded(); let (fsm_resp_sender, _fsm_resp_receiver) = crossbeam_channel::unbounded(); let (_command_req_sender, command_req_receiver) = crossbeam_channel::bounded(0); let (command_resp_sender, _command_resp_receiver) = crossbeam_channel::bounded(0); init_executor2( - contract_arguments, fsm_req_receiver, fsm_resp_sender, command_req_receiver, @@ -123,7 +119,6 @@ pub fn init_executor(contract_arguments: Vec<(&str, &str)>) -> Executor { } pub fn init_executor2( - contract_arguments: Vec<(&str, &str)>, fsm_req_receiver: Receiver, fsm_resp_sender: Sender, command_req_receiver: Receiver, @@ -131,74 +126,13 @@ pub fn init_executor2( ) -> Executor { // FIXME temp dir should be removed automatically, but at present it is not let tempdir = TempDir::new("init_executor").unwrap().into_path(); - let create_init_data_py = Path::new(SCRIPTS_DIR).join("config_tool/create_init_data.py"); - let create_genesis_py = Path::new(SCRIPTS_DIR).join("config_tool/create_genesis.py"); - let contracts_dir = Path::new(SCRIPTS_DIR).join("contracts"); - let mut init_data_yml = tempdir.clone(); - init_data_yml.push("init_data.yml"); - let mut genesis_json = tempdir.clone(); - genesis_json.push("genesis.json"); - - let contract_arguments = contract_arguments - .iter() - .map(|(key, value)| format!("{}={}", key, value)) - .collect::>(); - let mut init_data_args: Vec<&str> = vec![ - create_init_data_py.to_str().unwrap(), - "--output", - init_data_yml.to_str().unwrap(), - ]; - if !contract_arguments.is_empty() { - init_data_args.push("--contract_arguments"); - contract_arguments.iter().for_each(|arg| { - init_data_args.push(arg); - }); - } - - fn check_command_output(output: Output) { - if !output.status.success() { - panic!( - "\n[stderr]: {}\n[stdout]: {}", - String::from_utf8_lossy(output.stderr.as_slice()), - String::from_utf8_lossy(output.stdout.as_slice()), - ); - } - } - - let output = Command::new("python3") - .args(init_data_args.as_slice()) - .output() - .expect("Failed to create init data"); - - check_command_output(output); - let output = Command::new("python3") - .args(&[ - create_genesis_py.to_str().unwrap(), - "--output", - genesis_json.to_str().unwrap(), - "--init_data_file", - init_data_yml.to_str().unwrap(), - "--contracts_dir", - contracts_dir.to_str().unwrap(), - ]) - .output() - .expect("Failed to create init data"); - check_command_output(output); - - // Load from genesis json file - println!("genesis_json: {}", genesis_json.to_str().unwrap()); - let genesis_file = File::open(genesis_json.to_str().unwrap()).unwrap(); - let spec: Spec = serde_json::from_reader(genesis_file).expect("Failed to load genesis."); - let _genesis = Genesis { - spec, - block: Block::default(), - }; + let genesis_path = Path::new(SCRIPTS_DIR).join("config_tool/genesis/genesis.json"); let mut data_path = tempdir.clone(); data_path.push("data"); env::set_var("DATA_PATH", data_path); let executor = Executor::init( - genesis_json.to_str().unwrap(), + genesis_path.to_str().unwrap(), "archive", 5 * 1024 * 1024, tempdir.to_str().unwrap().to_string(), diff --git a/scripts/contracts/interaction b/scripts/contracts/interaction index a04224eac..30049a2bc 160000 --- a/scripts/contracts/interaction +++ b/scripts/contracts/interaction @@ -1 +1 @@ -Subproject commit a04224eac9eb0a97bfbd0c6938fbd98f671860be +Subproject commit 30049a2bc0da74cae3a014adba3eb5fe77651662 diff --git a/scripts/contracts/tests/contracts b/scripts/contracts/tests/contracts new file mode 160000 index 000000000..562d14c2a --- /dev/null +++ b/scripts/contracts/tests/contracts @@ -0,0 +1 @@ +Subproject commit 562d14c2a07e1ba7a1b57ee1b46c9ef3170a7a74 diff --git a/scripts/create_cita_config.py b/scripts/create_cita_config.py index f8d42a4a0..c365a2b6b 100755 --- a/scripts/create_cita_config.py +++ b/scripts/create_cita_config.py @@ -246,10 +246,9 @@ def create_genesis(self, timestamp, init_token, resource_dir): if resource_dir is not None: shutil.copytree(resource_dir, os.path.join(self.configs_dir, 'resource'), False) - if not prevhash: - prevhash = DEFAULT_PREVHASH - if not timestamp: - timestamp = str(int(time.time() * 1000)) + + prevhash = DEFAULT_PREVHASH if not prevhash else str(prevhash) + timestamp = str(int(time.time() * 1000)) if not timestamp else str(timestamp) process = subprocess.Popen(["./bin/create_genesis",self.contracts_dir, self.contracts_docs_dir, self.init_data_file, self.genesis_path, timestamp, init_token, prevhash]) diff --git a/tests/integrate_test/cita_basic.sh b/tests/integrate_test/cita_basic.sh index b40b5c24f..646eedd6e 100755 --- a/tests/integrate_test/cita_basic.sh +++ b/tests/integrate_test/cita_basic.sh @@ -39,7 +39,7 @@ main() { echo -n "5) stop node3, check height growth ... " bin/cita bebop stop $CHAIN_NAME/3 2>&1 - timeout=$(check_height_growth_normal 0 30) || (echo "FAILED" + timeout=$(check_height_growth_normal 0 60) || (echo "FAILED" echo "error msg: ${timeout}" exit 1) echo "${timeout}s DONE" diff --git a/tools/create_genesis/src/contracts.rs b/tools/create_genesis/src/contracts.rs index a97c955d7..7b47bec33 100644 --- a/tools/create_genesis/src/contracts.rs +++ b/tools/create_genesis/src/contracts.rs @@ -150,7 +150,7 @@ impl Basic { let addr = Address::from_str(clean_0x(&info.address)).unwrap(); conts.push(Token::Address(addr)); let mut funcs = Vec::new(); - funcs.push(Token::FixedBytes(String::from("0000").into_bytes())); + funcs.push(Token::FixedBytes(vec![0, 0, 0, 0])); tokens.push(Token::Array(conts)); tokens.push(Token::Array(funcs)); From 2a0775ff834f630b60a28f8aca75039273c3dcc2 Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Tue, 11 Jun 2019 20:33:17 +0800 Subject: [PATCH 53/91] change create_genesis to create-genesis --- Cargo.lock | 22 +++++++++++++++++++ scripts/create_cita_config.py | 2 +- scripts/release.sh | 2 +- .../Cargo.toml | 2 +- .../src/common.rs | 0 .../src/contracts.rs | 0 .../src/genesis.rs | 0 .../src/main.rs | 0 .../src/miner.rs | 0 .../src/params.rs | 0 .../src/solc.rs | 0 11 files changed, 25 insertions(+), 3 deletions(-) rename tools/{create_genesis => create-genesis}/Cargo.toml (98%) rename tools/{create_genesis => create-genesis}/src/common.rs (100%) rename tools/{create_genesis => create-genesis}/src/contracts.rs (100%) rename tools/{create_genesis => create-genesis}/src/genesis.rs (100%) rename tools/{create_genesis => create-genesis}/src/main.rs (100%) rename tools/{create_genesis => create-genesis}/src/miner.rs (100%) rename tools/{create_genesis => create-genesis}/src/params.rs (100%) rename tools/{create_genesis => create-genesis}/src/solc.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 455d9ab03..ce65aafcd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -953,6 +953,28 @@ dependencies = [ "build_const 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "create-genesis" +version = "0.1.0" +dependencies = [ + "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", + "core-executor 0.1.0", + "ethabi 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ethereum-types 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "evm 0.1.0", + "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "json 0.11.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", + "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_yaml 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", + "tiny-keccak 1.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "create-key-addr" version = "0.1.0" diff --git a/scripts/create_cita_config.py b/scripts/create_cita_config.py index c365a2b6b..de9fa931c 100755 --- a/scripts/create_cita_config.py +++ b/scripts/create_cita_config.py @@ -250,7 +250,7 @@ def create_genesis(self, timestamp, init_token, resource_dir): prevhash = DEFAULT_PREVHASH if not prevhash else str(prevhash) timestamp = str(int(time.time() * 1000)) if not timestamp else str(timestamp) - process = subprocess.Popen(["./bin/create_genesis",self.contracts_dir, self.contracts_docs_dir, + process = subprocess.Popen(["./bin/create-genesis",self.contracts_dir, self.contracts_docs_dir, self.init_data_file, self.genesis_path, timestamp, init_token, prevhash]) process.wait() diff --git a/scripts/release.sh b/scripts/release.sh index 3dd58de27..33e6343fa 100755 --- a/scripts/release.sh +++ b/scripts/release.sh @@ -31,7 +31,7 @@ for binary in \ cita-jsonrpc \ cita-network \ create-key-addr \ - create_genesis \ + create-genesis \ cita-relayer-parser \ snapshot-tool \ consensus-mock \ diff --git a/tools/create_genesis/Cargo.toml b/tools/create-genesis/Cargo.toml similarity index 98% rename from tools/create_genesis/Cargo.toml rename to tools/create-genesis/Cargo.toml index 607f596ec..2f803a372 100644 --- a/tools/create_genesis/Cargo.toml +++ b/tools/create-genesis/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "create_genesis" +name = "create-genesis" version = "0.1.0" authors = ["Cryptape Technologies "] edition = "2018" diff --git a/tools/create_genesis/src/common.rs b/tools/create-genesis/src/common.rs similarity index 100% rename from tools/create_genesis/src/common.rs rename to tools/create-genesis/src/common.rs diff --git a/tools/create_genesis/src/contracts.rs b/tools/create-genesis/src/contracts.rs similarity index 100% rename from tools/create_genesis/src/contracts.rs rename to tools/create-genesis/src/contracts.rs diff --git a/tools/create_genesis/src/genesis.rs b/tools/create-genesis/src/genesis.rs similarity index 100% rename from tools/create_genesis/src/genesis.rs rename to tools/create-genesis/src/genesis.rs diff --git a/tools/create_genesis/src/main.rs b/tools/create-genesis/src/main.rs similarity index 100% rename from tools/create_genesis/src/main.rs rename to tools/create-genesis/src/main.rs diff --git a/tools/create_genesis/src/miner.rs b/tools/create-genesis/src/miner.rs similarity index 100% rename from tools/create_genesis/src/miner.rs rename to tools/create-genesis/src/miner.rs diff --git a/tools/create_genesis/src/params.rs b/tools/create-genesis/src/params.rs similarity index 100% rename from tools/create_genesis/src/params.rs rename to tools/create-genesis/src/params.rs diff --git a/tools/create_genesis/src/solc.rs b/tools/create-genesis/src/solc.rs similarity index 100% rename from tools/create_genesis/src/solc.rs rename to tools/create-genesis/src/solc.rs From 47310461728e46edce9ac5f199e99daec3202818 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Tue, 11 Jun 2019 20:14:17 +0800 Subject: [PATCH 54/91] Add security audit test. --- .circleci/config.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 4538470c5..1a43b851d 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -145,9 +145,7 @@ jobs: - restore_cache: *restore-security-audit-cache - run: name: Check Security Audit - command: | - echo "Add it back when bump protobuf to `v2.6.0`." - # make security_audit + command: make security_audit - save_cache: *save-security-audit-cache "Check Contracts": From 3b6a5f307b7556986c1310e21582c2704291fcb3 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 12 Jun 2019 10:16:34 +0800 Subject: [PATCH 55/91] Update protobuf to `2.6.2`. --- Cargo.lock | 68 +++++++++++++++++++++++++++--------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d273222f9..749ff0d62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,7 +125,7 @@ dependencies = [ [[package]] name = "authority_manage" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -260,7 +260,7 @@ dependencies = [ [[package]] name = "blake2b" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -523,7 +523,7 @@ dependencies = [ [[package]] name = "cita-crypto" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -534,7 +534,7 @@ dependencies = [ [[package]] name = "cita-crypto-trait" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] @@ -542,7 +542,7 @@ dependencies = [ [[package]] name = "cita-directories" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -550,7 +550,7 @@ dependencies = [ [[package]] name = "cita-ed25519" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -658,7 +658,7 @@ dependencies = [ [[package]] name = "cita-merklehash" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -718,7 +718,7 @@ dependencies = [ [[package]] name = "cita-secp256k1" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -735,7 +735,7 @@ dependencies = [ [[package]] name = "cita-sm2" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -749,7 +749,7 @@ dependencies = [ [[package]] name = "cita-types" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1130,7 +1130,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "db" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1200,7 +1200,7 @@ dependencies = [ [[package]] name = "engine" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1263,7 +1263,7 @@ dependencies = [ [[package]] name = "error" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" [[package]] name = "error-chain" @@ -1324,7 +1324,7 @@ dependencies = [ [[package]] name = "ethcore-bloom-journal" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1577,7 +1577,7 @@ dependencies = [ "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "httpbis 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "tls-api 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", "tls-api-stub 0.1.20 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1605,7 +1605,7 @@ dependencies = [ [[package]] name = "hashable" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "blake2b 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1807,7 +1807,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-proto" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1824,7 +1824,7 @@ dependencies = [ [[package]] name = "jsonrpc-types" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1838,7 +1838,7 @@ dependencies = [ [[package]] name = "jsonrpc-types-internals" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1920,7 +1920,7 @@ dependencies = [ [[package]] name = "libproto" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1928,7 +1928,7 @@ dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "grpc 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "protobuf 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2426,7 +2426,7 @@ dependencies = [ [[package]] name = "panic_hook" version = "0.0.1" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2553,7 +2553,7 @@ dependencies = [ [[package]] name = "proof" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2567,7 +2567,7 @@ dependencies = [ [[package]] name = "protobuf" -version = "2.1.1" +version = "2.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2576,7 +2576,7 @@ dependencies = [ [[package]] name = "pubsub" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "pubsub_kafka 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2587,7 +2587,7 @@ dependencies = [ [[package]] name = "pubsub_kafka" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2599,7 +2599,7 @@ dependencies = [ [[package]] name = "pubsub_rabbitmq" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "amqp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2608,7 +2608,7 @@ dependencies = [ [[package]] name = "pubsub_zeromq" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2934,7 +2934,7 @@ dependencies = [ [[package]] name = "rlp" version = "0.2.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2946,7 +2946,7 @@ dependencies = [ [[package]] name = "rlp_derive" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3159,7 +3159,7 @@ dependencies = [ [[package]] name = "snappy" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3784,7 +3784,7 @@ dependencies = [ [[package]] name = "tx_pool" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -3926,7 +3926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "util" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#5d030119083ccc5d1cae629e1e8d614c30b9d7cb" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -4355,7 +4355,7 @@ dependencies = [ "checksum proc-macro2 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "77997c53ae6edd6d187fec07ec41b207063b5ee6f33680e9fa86d405cdd313d4" "checksum proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)" = "3d7b7eaaa90b4a90a932a9ea6666c95a389e424eff347f0f793979289429feee" "checksum proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" -"checksum protobuf 2.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "56c363dfc36e450457f4fa05a91d8c3f0fed00fc21142b4ce2cb7b525675eaeb" +"checksum protobuf 2.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e9076cae823584ab4d8fab3a111658d1232faf106611dc8378161b7d062b628" "checksum pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum pubsub_kafka 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum pubsub_rabbitmq 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" From 8832e8cc0c5dd97340040b06a8ede21db1bd0ca0 Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Wed, 12 Jun 2019 10:29:15 +0800 Subject: [PATCH 56/91] add unit_quota test --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 51c1112da..7eb18fc6e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -90,6 +90,9 @@ jobs: - <<: *stage-contract-test-sha3-secp256k1 name: Unit Quota Management script: npm run-script unit_qm + - <<: *stage-contract-test-sha3-secp256k1 + name: Unit Quota + script: npm run-script unit_quota - <<: *stage-contract-test-sha3-secp256k1 name: Unit Abi script: npm run-script abi From 88e8b8709f00c5d225f56b563189420e8e1cb70f Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Wed, 12 Jun 2019 10:47:06 +0800 Subject: [PATCH 57/91] rebase submodule --- scripts/contracts/tests/contracts | 1 - 1 file changed, 1 deletion(-) delete mode 160000 scripts/contracts/tests/contracts diff --git a/scripts/contracts/tests/contracts b/scripts/contracts/tests/contracts deleted file mode 160000 index 562d14c2a..000000000 --- a/scripts/contracts/tests/contracts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 562d14c2a07e1ba7a1b57ee1b46c9ef3170a7a74 From 882cd5a0edefac70a9075c1fe62a6dd623fc65d3 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 12 Jun 2019 11:26:28 +0800 Subject: [PATCH 58/91] Update crates to 2018 edition. [skip travis] * cita-jsonrpc * chain-executor-mock * box-executor * chain-performance-by-mq * consensus-mock * cita-executor * cita-chain --- cita-chain/Cargo.toml | 1 + cita-chain/build.rs | 2 -- cita-chain/src/forward.rs | 6 ++-- cita-chain/src/main.rs | 17 ++------- cita-chain/types/Cargo.toml | 1 + cita-chain/types/src/basic_types.rs | 4 +-- cita-chain/types/src/block.rs | 6 ++-- cita-chain/types/src/db.rs | 2 +- cita-chain/types/src/extras.rs | 10 +++--- cita-chain/types/src/filter.rs | 10 +++--- cita-chain/types/src/header.rs | 4 +-- cita-chain/types/src/ids.rs | 2 +- cita-chain/types/src/lib.rs | 8 ----- cita-chain/types/src/log_blooms.rs | 2 +- cita-chain/types/src/log_entry.rs | 2 +- cita-chain/types/src/receipt.rs | 6 ++-- cita-chain/types/src/state_diff.rs | 2 +- cita-chain/types/src/transaction.rs | 10 +++--- cita-executor/Cargo.toml | 1 + cita-executor/build.rs | 4 +-- cita-executor/evm/Cargo.toml | 1 + cita-executor/evm/src/action_params.rs | 2 +- cita-executor/evm/src/env_info.rs | 2 +- cita-executor/evm/src/error.rs | 2 +- cita-executor/evm/src/evm.rs | 8 ++--- cita-executor/evm/src/ext.rs | 10 +++--- cita-executor/evm/src/factory.rs | 2 +- cita-executor/evm/src/fake_tests.rs | 12 +++---- .../evm/src/interpreter/gasometer.rs | 12 +++---- cita-executor/evm/src/interpreter/memory.rs | 4 +-- cita-executor/evm/src/interpreter/mod.rs | 8 ++--- cita-executor/evm/src/lib.rs | 5 --- cita-executor/evm/src/storage.rs | 6 ++-- cita-executor/evm/src/tests.rs | 10 +++--- cita-executor/src/backlogs.rs | 16 ++++----- cita-executor/src/main.rs | 17 ++------- cita-executor/src/postman.rs | 20 +++++------ cita-executor/src/snapshot.rs | 16 ++++----- cita-executor/src/tests/helpers.rs | 2 +- cita-jsonrpc/Cargo.toml | 1 + cita-jsonrpc/build.rs | 4 +-- cita-jsonrpc/src/http_server.rs | 2 +- cita-jsonrpc/src/main.rs | 36 +++---------------- cita-jsonrpc/src/mq_handler.rs | 2 +- cita-jsonrpc/src/response.rs | 4 +-- cita-jsonrpc/src/soliloquy.rs | 8 ++--- cita-jsonrpc/src/ws_handler.rs | 2 +- tests/box-executor/Cargo.toml | 1 + tests/box-executor/src/config.rs | 10 +----- tests/box-executor/src/generate_block.rs | 2 +- tests/box-executor/src/main.rs | 12 +------ tests/box-executor/src/runner.rs | 15 ++------ tests/chain-executor-mock/Cargo.toml | 1 + .../chain-executor-mock/src/generate_block.rs | 2 +- tests/chain-executor-mock/src/main.rs | 14 ++------ tests/chain-performance-by-mq/Cargo.toml | 1 + .../src/generate_block.rs | 2 +- tests/chain-performance-by-mq/src/main.rs | 13 ++----- tests/consensus-mock/Cargo.toml | 1 + tests/consensus-mock/src/main.rs | 9 ++--- 60 files changed, 143 insertions(+), 254 deletions(-) diff --git a/cita-chain/Cargo.toml b/cita-chain/Cargo.toml index d6460c18a..0b1c92a10 100644 --- a/cita-chain/Cargo.toml +++ b/cita-chain/Cargo.toml @@ -3,6 +3,7 @@ description = "CITA node." name = "cita-chain" version = "0.6.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] dotenv = "0.13.0" diff --git a/cita-chain/build.rs b/cita-chain/build.rs index 13f56792b..d3ee509ce 100644 --- a/cita-chain/build.rs +++ b/cita-chain/build.rs @@ -1,5 +1,3 @@ -extern crate util; - use std::env; use util::build_info::gen_build_info; diff --git a/cita-chain/src/forward.rs b/cita-chain/src/forward.rs index 1b43acfd4..3406b7966 100644 --- a/cita-chain/src/forward.rs +++ b/cita-chain/src/forward.rs @@ -15,6 +15,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::types::filter::Filter; +use crate::types::ids::BlockId; use cita_types::H256; use core::filters::eth_filter::EthFilter; use core::libchain::chain::{BlockInQueue, Chain}; @@ -41,10 +43,8 @@ use std::sync::atomic::Ordering; use std::sync::Arc; use std::thread; use std::time::Duration; -use types::filter::Filter; -use types::ids::BlockId; -use cita_db::kvdb::DatabaseConfig; +use crate::cita_db::kvdb::DatabaseConfig; use cita_directories::DataPath; use core::db; use std::fs::File; diff --git a/cita-chain/src/main.rs b/cita-chain/src/main.rs index 38a8c787a..56ec6733d 100644 --- a/cita-chain/src/main.rs +++ b/cita-chain/src/main.rs @@ -66,36 +66,25 @@ //! [`Chain`]: ../core/libchain/chain/struct.Chain.html //! -extern crate byteorder; -extern crate cita_types; -extern crate clap; extern crate common_types as types; -extern crate core; -extern crate dotenv; -extern crate error; -extern crate jsonrpc_types; #[macro_use] extern crate libproto; #[macro_use] extern crate cita_logger as logger; -extern crate proof; -extern crate pubsub; -extern crate serde_json; #[macro_use] extern crate util; -extern crate cita_directories; extern crate db as cita_db; mod block_processor; mod forward; -use block_processor::BlockProcessor; -use cita_db::kvdb::{Database, DatabaseConfig}; +use crate::block_processor::BlockProcessor; +use crate::cita_db::kvdb::{Database, DatabaseConfig}; +use crate::forward::Forward; use cita_directories::DataPath; use clap::App; use core::db; use core::libchain; -use forward::Forward; use libproto::router::{MsgType, RoutingKey, SubModules}; use pubsub::{channel, start_pubsub}; use std::sync::Arc; diff --git a/cita-chain/types/Cargo.toml b/cita-chain/types/Cargo.toml index 2330d2d07..31ce19a8f 100644 --- a/cita-chain/types/Cargo.toml +++ b/cita-chain/types/Cargo.toml @@ -3,6 +3,7 @@ name = "common-types" description = "Common types used throughout the codebase" version = "0.1.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] rlp = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } diff --git a/cita-chain/types/src/basic_types.rs b/cita-chain/types/src/basic_types.rs index d184c32aa..853571df5 100644 --- a/cita-chain/types/src/basic_types.rs +++ b/cita-chain/types/src/basic_types.rs @@ -17,9 +17,9 @@ //! Ethcore basic typenames. /// Type for a 2048-bit log-bloom, as used by our blocks. -pub use log_entry::LogBloom; +pub use crate::log_entry::LogBloom; -pub use log_blooms::LogBloomGroup; +pub use crate::log_blooms::LogBloomGroup; /// Constant 2048-bit datum for 0. Often used as a default. lazy_static! { diff --git a/cita-chain/types/src/block.rs b/cita-chain/types/src/block.rs index 7a32a955b..3d2c8055c 100644 --- a/cita-chain/types/src/block.rs +++ b/cita-chain/types/src/block.rs @@ -15,10 +15,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use header::{Header, OpenHeader}; +use crate::header::{Header, OpenHeader}; +use crate::extras::TransactionAddress; use cita_types::H256; -use extras::TransactionAddress; use std::collections::HashMap; use libproto::blockchain::{ @@ -27,7 +27,7 @@ use libproto::blockchain::{ use rlp::*; use std::ops::{Deref, DerefMut}; -use transaction::SignedTransaction; +use crate::transaction::SignedTransaction; use util::HeapSizeOf; #[derive(Default, Debug, Clone, PartialEq)] diff --git a/cita-chain/types/src/db.rs b/cita-chain/types/src/db.rs index c008bd411..37d72f023 100644 --- a/cita-chain/types/src/db.rs +++ b/cita-chain/types/src/db.rs @@ -16,7 +16,7 @@ //! Database utilities and definitions. -use cita_db::{DBTransaction, KeyValueDB}; +use crate::cita_db::{DBTransaction, KeyValueDB}; use rlp::{decode, encode, Decodable, Encodable}; use std::collections::HashMap; use std::hash::Hash; diff --git a/cita-chain/types/src/extras.rs b/cita-chain/types/src/extras.rs index d7bab597c..9782c6914 100644 --- a/cita-chain/types/src/extras.rs +++ b/cita-chain/types/src/extras.rs @@ -16,14 +16,14 @@ //! Blockchain DB extras. -use basic_types::LogBloomGroup; -use block::BlockBody; +use crate::basic_types::LogBloomGroup; +use crate::block::BlockBody; +use crate::db::Key; +use crate::header::{BlockNumber, Header}; +use crate::receipt::Receipt; use bloomchain::group::GroupPosition; use cita_types::{H256, H264}; -use db::Key; -use header::{BlockNumber, Header}; use libproto::blockchain::Proof; -use receipt::Receipt; use rlp::*; use std::ops::{Deref, Index}; use util::*; diff --git a/cita-chain/types/src/filter.rs b/cita-chain/types/src/filter.rs index c1efeb994..033f34b4c 100644 --- a/cita-chain/types/src/filter.rs +++ b/cita-chain/types/src/filter.rs @@ -16,11 +16,11 @@ //! Blockchain filter +use crate::ids::BlockId; +use crate::log_entry::{LogBloom, LogEntry}; use cita_types::traits::BloomTools; use cita_types::{Address, H256}; -use ids::BlockId; use jsonrpc_types::rpc_types::{Filter as RpcFilter, VariadicValue}; -use log_entry::{LogBloom, LogEntry}; /// Blockchain Filter. #[derive(Debug, PartialEq)] @@ -159,9 +159,9 @@ impl From for Filter { #[cfg(test)] mod tests { - use filter::Filter; - use ids::BlockId; - use log_entry::{LogBloom, LogEntry}; + use crate::filter::Filter; + use crate::ids::BlockId; + use crate::log_entry::{LogBloom, LogEntry}; #[test] fn test_bloom_possibilities_none() { diff --git a/cita-chain/types/src/header.rs b/cita-chain/types/src/header.rs index b3ea97945..706edb14f 100644 --- a/cita-chain/types/src/header.rs +++ b/cita-chain/types/src/header.rs @@ -17,7 +17,7 @@ //! Block header. -use basic_types::{LogBloom, ZERO_LOGBLOOM}; +use crate::basic_types::{LogBloom, ZERO_LOGBLOOM}; use cita_types::{Address, H256, U256}; use libproto::blockchain::{ Block as ProtoBlock, BlockHeader as ProtoBlockHeader, Proof as ProtoProof, ProofType, @@ -29,9 +29,9 @@ use std::cmp; use std::ops::{Deref, DerefMut}; use time::get_time; +pub use crate::BlockNumber; use hashable::{Hashable, HASH_NULL_RLP}; use util::{Bytes, HeapSizeOf}; -pub use BlockNumber; #[derive(Debug, Clone, Eq)] pub struct OpenHeader { diff --git a/cita-chain/types/src/ids.rs b/cita-chain/types/src/ids.rs index 6ddf1b408..0b92316ec 100644 --- a/cita-chain/types/src/ids.rs +++ b/cita-chain/types/src/ids.rs @@ -16,9 +16,9 @@ //! Unique identifiers. +use crate::BlockNumber; use cita_types::H256; use jsonrpc_types::rpc_types::{BlockNumber as RpcBlockNumber, BlockTag}; -use BlockNumber; /// Uniquely identifies block. #[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)] diff --git a/cita-chain/types/src/lib.rs b/cita-chain/types/src/lib.rs index f7b762159..a446c9c85 100644 --- a/cita-chain/types/src/lib.rs +++ b/cita-chain/types/src/lib.rs @@ -16,23 +16,15 @@ // along with this program. If not, see . extern crate cita_crypto as crypto; -extern crate cita_types; -extern crate hashable; -extern crate jsonrpc_types; -extern crate libproto; -extern crate rlp; #[macro_use] extern crate rlp_derive; #[macro_use] extern crate serde_derive; -extern crate util; #[macro_use] extern crate lazy_static; -extern crate time; #[macro_use] extern crate cita_logger as logger; extern crate db as cita_db; -extern crate proof; pub extern crate bloomchain; diff --git a/cita-chain/types/src/log_blooms.rs b/cita-chain/types/src/log_blooms.rs index 41c020e43..21087926a 100644 --- a/cita-chain/types/src/log_blooms.rs +++ b/cita-chain/types/src/log_blooms.rs @@ -16,9 +16,9 @@ //! Bridge between bloomchain crate types and cita LogBloom. +use crate::log_entry::LogBloom; use bloomchain::group::BloomGroup; use bloomchain::Bloom; -use log_entry::LogBloom; use rlp::*; use util::HeapSizeOf; diff --git a/cita-chain/types/src/log_entry.rs b/cita-chain/types/src/log_entry.rs index 0973a0436..0cfc4c409 100644 --- a/cita-chain/types/src/log_entry.rs +++ b/cita-chain/types/src/log_entry.rs @@ -16,6 +16,7 @@ //! Log entry type definition. +use crate::BlockNumber; use cita_types::traits::BloomTools; use cita_types::{Address, Bloom, H256}; use jsonrpc_types::rpc_types::Log as RpcLog; @@ -23,7 +24,6 @@ use libproto::executor::LogEntry as ProtoLogEntry; use rlp::*; use std::ops::Deref; use util::{Bytes, HeapSizeOf}; -use BlockNumber; pub type LogBloom = Bloom; diff --git a/cita-chain/types/src/receipt.rs b/cita-chain/types/src/receipt.rs index cfbd7a152..8d7a5d0ee 100644 --- a/cita-chain/types/src/receipt.rs +++ b/cita-chain/types/src/receipt.rs @@ -16,17 +16,17 @@ //! Receipt +use crate::log_entry::{LocalizedLogEntry, LogBloom, LogEntry}; +use crate::BlockNumber; use cita_types::traits::LowerHex; use cita_types::{Address, H256, U256}; use jsonrpc_types::rpc_types::Receipt as RpcReceipt; use libproto::executor::{ Receipt as ProtoReceipt, ReceiptError as ProtoReceiptError, ReceiptErrorWithOption, StateRoot, }; -use log_entry::{LocalizedLogEntry, LogBloom, LogEntry}; use rlp::*; use std::str::FromStr; use util::{Bytes, HeapSizeOf}; -use BlockNumber; #[derive(Serialize, Deserialize, Debug, PartialEq, Clone, Copy, Eq)] pub enum ReceiptError { @@ -385,7 +385,7 @@ impl Into for LocalizedReceipt { #[cfg(test)] mod tests { use super::*; - use log_entry::LogEntry; + use crate::log_entry::LogEntry; #[test] fn test_no_state_root() { diff --git a/cita-chain/types/src/state_diff.rs b/cita-chain/types/src/state_diff.rs index 9d7f4a4b7..6202f9cb8 100644 --- a/cita-chain/types/src/state_diff.rs +++ b/cita-chain/types/src/state_diff.rs @@ -16,7 +16,7 @@ //! State diff module. -use account_diff::*; +use crate::account_diff::*; use cita_types::Address; use std::collections::BTreeMap; use std::fmt; diff --git a/cita-chain/types/src/transaction.rs b/cita-chain/types/src/transaction.rs index b9a94c8a9..0f2ebbc03 100644 --- a/cita-chain/types/src/transaction.rs +++ b/cita-chain/types/src/transaction.rs @@ -15,21 +15,21 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use cita_types::traits::LowerHex; -use cita_types::{clean_0x, Address, H256, U256}; -use crypto::{ +use crate::crypto::{ pubkey_to_address, PubKey, Signature, HASH_BYTES_LEN, PUBKEY_BYTES_LEN, SIGNATURE_BYTES_LEN, }; +use crate::reserved_addresses::{ABI_ADDRESS, AMEND_ADDRESS, GO_CONTRACT, STORE_ADDRESS}; +use crate::BlockNumber; +use cita_types::traits::LowerHex; +use cita_types::{clean_0x, Address, H256, U256}; use libproto::blockchain::{ Crypto as ProtoCrypto, SignedTransaction as ProtoSignedTransaction, Transaction as ProtoTransaction, UnverifiedTransaction as ProtoUnverifiedTransaction, }; -use reserved_addresses::{ABI_ADDRESS, AMEND_ADDRESS, GO_CONTRACT, STORE_ADDRESS}; use rlp::*; use std::ops::{Deref, DerefMut}; use std::str::FromStr; use util::{Bytes, HeapSizeOf}; -use BlockNumber; #[derive(Debug, PartialEq, Clone)] pub enum Error { diff --git a/cita-executor/Cargo.toml b/cita-executor/Cargo.toml index bba8f769d..7ee943bc5 100644 --- a/cita-executor/Cargo.toml +++ b/cita-executor/Cargo.toml @@ -2,6 +2,7 @@ name = "cita-executor" version = "0.1.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] dotenv = "0.13.0" diff --git a/cita-executor/build.rs b/cita-executor/build.rs index a0533082a..c20d26175 100644 --- a/cita-executor/build.rs +++ b/cita-executor/build.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -15,8 +15,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -extern crate util; - use std::env; use util::build_info::gen_build_info; diff --git a/cita-executor/evm/Cargo.toml b/cita-executor/evm/Cargo.toml index 3ea76e81b..9be6efcc6 100644 --- a/cita-executor/evm/Cargo.toml +++ b/cita-executor/evm/Cargo.toml @@ -2,6 +2,7 @@ name = "evm" version = "0.1.0" authors = ["Parity Technologies ", "Cryptape Technologies "] +edition = "2018" [dependencies] cita-logger = "0.1.0" diff --git a/cita-executor/evm/src/action_params.rs b/cita-executor/evm/src/action_params.rs index ede9aa2fe..e279321da 100644 --- a/cita-executor/evm/src/action_params.rs +++ b/cita-executor/evm/src/action_params.rs @@ -17,7 +17,7 @@ //! Evm input params. // use ethjson; -use call_type::CallType; +use crate::call_type::CallType; use cita_types::{Address, H256, U256}; use hashable::HASH_EMPTY; diff --git a/cita-executor/evm/src/env_info.rs b/cita-executor/evm/src/env_info.rs index 58c348bdf..090a78ee0 100644 --- a/cita-executor/evm/src/env_info.rs +++ b/cita-executor/evm/src/env_info.rs @@ -16,9 +16,9 @@ // use std::cmp; +use crate::types::BlockNumber; use cita_types::{Address, H256, U256}; use std::sync::Arc; -use types::BlockNumber; // use ethjson; /// Simple vector of hashes, should be at most 256 items large, can be smaller if being used diff --git a/cita-executor/evm/src/error.rs b/cita-executor/evm/src/error.rs index ae82f6aa1..db5d6fe04 100644 --- a/cita-executor/evm/src/error.rs +++ b/cita-executor/evm/src/error.rs @@ -16,7 +16,7 @@ //! Evm errors -use cita_db::trie; +use crate::cita_db::trie; use std::fmt; #[derive(Debug, Clone, PartialEq)] diff --git a/cita-executor/evm/src/evm.rs b/cita-executor/evm/src/evm.rs index a54c2d835..afc72609e 100644 --- a/cita-executor/evm/src/evm.rs +++ b/cita-executor/evm/src/evm.rs @@ -16,12 +16,12 @@ //! Evm interface. -use action_params::ActionParams; +use crate::action_params::ActionParams; +use crate::error::{Error, Result}; +use crate::return_data::{GasLeft, ReturnData}; +use crate::Ext; use cita_types::{U128, U256, U512}; -use error::{Error, Result}; -use return_data::{GasLeft, ReturnData}; use std::{cmp, fmt, ops}; -use Ext; /// Finalization result. Gas Left: either it is a known value, or it needs to be computed by processing /// a return instruction. diff --git a/cita-executor/evm/src/ext.rs b/cita-executor/evm/src/ext.rs index 117fcc805..bf04503d5 100644 --- a/cita-executor/evm/src/ext.rs +++ b/cita-executor/evm/src/ext.rs @@ -16,14 +16,14 @@ //! Interface for Evm externalities. -use call_type::CallType; +use crate::call_type::CallType; +use crate::env_info::*; +use crate::error::Result; +use crate::return_data::ReturnData; +use crate::Schedule; use cita_types::{Address, H256, U256}; -use env_info::*; -use error::Result; -use return_data::ReturnData; use std::sync::Arc; use util::*; -use Schedule; /// Result of externalities create function. pub enum ContractCreateResult { diff --git a/cita-executor/evm/src/factory.rs b/cita-executor/evm/src/factory.rs index a6ab0a6c4..3eebb4fdf 100644 --- a/cita-executor/evm/src/factory.rs +++ b/cita-executor/evm/src/factory.rs @@ -19,8 +19,8 @@ //! TODO: consider spliting it into two separate files. use super::interpreter::SharedCache; +use crate::evm::Evm; use cita_types::U256; -use evm::Evm; use std::fmt; use std::sync::Arc; diff --git a/cita-executor/evm/src/fake_tests.rs b/cita-executor/evm/src/fake_tests.rs index 276fdca8c..2ebc58d6d 100644 --- a/cita-executor/evm/src/fake_tests.rs +++ b/cita-executor/evm/src/fake_tests.rs @@ -14,13 +14,13 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use call_type::CallType; +use crate::call_type::CallType; +use crate::env_info::EnvInfo; +use crate::error; +use crate::ext::{ContractCreateResult, Ext, MessageCallResult}; +use crate::return_data::{GasLeft, ReturnData}; +use crate::schedule::Schedule; use cita_types::{Address, H256, U256}; -use env_info::EnvInfo; -use error; -use ext::{ContractCreateResult, Ext, MessageCallResult}; -use return_data::{GasLeft, ReturnData}; -use schedule::Schedule; use std::collections::{HashMap, HashSet}; use std::sync::Arc; use util::*; diff --git a/cita-executor/evm/src/interpreter/gasometer.rs b/cita-executor/evm/src/interpreter/gasometer.rs index b76b5b1f7..a0b5aead5 100644 --- a/cita-executor/evm/src/interpreter/gasometer.rs +++ b/cita-executor/evm/src/interpreter/gasometer.rs @@ -15,13 +15,13 @@ // along with Parity. If not, see . use super::u256_to_address; +use crate::error::{Error, Result}; +use crate::evm::CostType; +use crate::ext::Ext; +use crate::instructions::{self, Instruction, InstructionInfo}; +use crate::interpreter::stack::Stack; +use crate::schedule::Schedule; use cita_types::{H256, U256}; -use error::{Error, Result}; -use evm::CostType; -use ext::Ext; -use instructions::{self, Instruction, InstructionInfo}; -use interpreter::stack::Stack; -use schedule::Schedule; use std::cmp; macro_rules! overflowing { diff --git a/cita-executor/evm/src/interpreter/memory.rs b/cita-executor/evm/src/interpreter/memory.rs index dc28d4342..6ee3b3477 100644 --- a/cita-executor/evm/src/interpreter/memory.rs +++ b/cita-executor/evm/src/interpreter/memory.rs @@ -13,8 +13,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use crate::return_data::ReturnData; use cita_types::U256; -use return_data::ReturnData; const MAX_RETURN_WASTE_BYTES: usize = 16384; @@ -32,7 +32,7 @@ pub trait Memory { /// Read a word from memory fn read(&self, offset: U256) -> U256; /// Write slice of bytes to memory. Does not resize memory! - fn write_slice(&mut self, offset: U256, &[u8]); + fn write_slice(&mut self, offset: U256, _: &[u8]); /// Retrieve part of the memory between offset and offset + size fn read_slice(&self, offset: U256, size: U256) -> &[u8]; /// Retrieve writeable part of memory diff --git a/cita-executor/evm/src/interpreter/mod.rs b/cita-executor/evm/src/interpreter/mod.rs index 5bf5764ec..16158b933 100644 --- a/cita-executor/evm/src/interpreter/mod.rs +++ b/cita-executor/evm/src/interpreter/mod.rs @@ -30,11 +30,11 @@ use self::stack::{Stack, VecStack}; use super::call_type::CallType; use super::error::{Error, Result}; use super::return_data::{GasLeft, ReturnData}; -use action_params::{ActionParams, ActionValue}; +use crate::action_params::{ActionParams, ActionValue}; +use crate::evm::{self, CostType}; +use crate::ext::{ContractCreateResult, Ext, MessageCallResult}; +use crate::instructions::{self, Instruction, InstructionInfo}; use bit_set::BitSet; -use evm::{self, CostType}; -use ext::{ContractCreateResult, Ext, MessageCallResult}; -use instructions::{self, Instruction, InstructionInfo}; use std::cmp; use std::mem; diff --git a/cita-executor/evm/src/lib.rs b/cita-executor/evm/src/lib.rs index bda2e54e1..146457fa8 100644 --- a/cita-executor/evm/src/lib.rs +++ b/cita-executor/evm/src/lib.rs @@ -16,16 +16,11 @@ //! Ethereum virtual machine. -extern crate bit_set; #[cfg_attr(feature = "evm-debug", macro_use)] extern crate cita_logger as logger; pub extern crate cita_types; extern crate common_types as types; extern crate db as cita_db; -extern crate hashable; -extern crate rlp; -extern crate rustc_hex; -extern crate util; pub mod action_params; pub mod call_type; diff --git a/cita-executor/evm/src/storage.rs b/cita-executor/evm/src/storage.rs index 9f70c8e7a..f016f4a58 100644 --- a/cita-executor/evm/src/storage.rs +++ b/cita-executor/evm/src/storage.rs @@ -15,13 +15,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::Error as EvmError; +use crate::Ext; use cita_types::{H256, U256}; use std::boxed::Box; use std::convert::From; use std::string::FromUtf8Error; use util::sha3; -use Error as EvmError; -use Ext; //////////////////////////////////////////////////////////////////////////////// pub trait Serialize { @@ -285,7 +285,7 @@ impl Map { #[cfg(test)] mod tests { use super::*; - use fake_tests::FakeExt; + use crate::fake_tests::FakeExt; #[test] fn test_scalar_bytes() { diff --git a/cita-executor/evm/src/tests.rs b/cita-executor/evm/src/tests.rs index 45fef4357..38ae48202 100644 --- a/cita-executor/evm/src/tests.rs +++ b/cita-executor/evm/src/tests.rs @@ -15,12 +15,12 @@ // along with Parity. If not, see . use self::rustc_hex::FromHex; -use action_params::{ActionParams, ActionValue}; +use crate::action_params::{ActionParams, ActionValue}; +use crate::error; +use crate::evm::Evm; +use crate::factory::{Factory, VMType}; +use crate::fake_tests::{test_finalize, FakeCall, FakeCallType, FakeExt}; use cita_types::{Address, H256, U256}; -use error; -use evm::Evm; -use factory::{Factory, VMType}; -use fake_tests::{test_finalize, FakeCall, FakeCallType, FakeExt}; use rustc_hex; use std::collections::{HashMap, HashSet}; use std::fmt::Debug; diff --git a/cita-executor/src/backlogs.rs b/cita-executor/src/backlogs.rs index e4680e0e5..3011af1e0 100644 --- a/cita-executor/src/backlogs.rs +++ b/cita-executor/src/backlogs.rs @@ -16,7 +16,7 @@ // along with this program. If not, see . use super::core::libexecutor::block::{ClosedBlock, OpenBlock}; -use cita_db::Itertools; +use crate::cita_db::Itertools; use cita_types::Address; use libproto::{ExecutedResult, Proof}; use std::cmp::min; @@ -414,18 +414,18 @@ pub fn wrap_height(height: usize) -> u64 { #[cfg(test)] mod tests { use super::{wrap_height, Backlog, Backlogs, Priority}; - use cita_db::journaldb; - use cita_db::kvdb::{in_memory, KeyValueDB}; - use core::header::OpenHeader; - use core::libexecutor::block::{BlockBody, ClosedBlock, ExecutedBlock, OpenBlock}; - use core::libexecutor::sys_config::BlockSysConfig; - use core::state_db::StateDB; + use crate::cita_db::journaldb; + use crate::cita_db::kvdb::{in_memory, KeyValueDB}; + use crate::core::header::OpenHeader; + use crate::core::libexecutor::block::{BlockBody, ClosedBlock, ExecutedBlock, OpenBlock}; + use crate::core::libexecutor::sys_config::BlockSysConfig; + use crate::core::state_db::StateDB; use hashable::HASH_NULL_RLP; use std::sync::Arc; fn generate_block_body() -> BlockBody { let mut stx = SignedTransaction::default(); - use types::transaction::SignedTransaction; + use crate::types::transaction::SignedTransaction; stx.data = vec![1; 200]; let transactions = vec![stx; 200]; BlockBody { transactions } diff --git a/cita-executor/src/main.rs b/cita-executor/src/main.rs index 32b84ee31..f711fbf37 100644 --- a/cita-executor/src/main.rs +++ b/cita-executor/src/main.rs @@ -83,39 +83,28 @@ #[cfg(test)] extern crate cita_crypto; -extern crate cita_directories; -extern crate cita_types; -extern crate clap; extern crate common_types as types; extern crate core_executor as core; #[macro_use] extern crate crossbeam_channel; extern crate db as cita_db; -extern crate dotenv; -extern crate error; -extern crate evm; -extern crate grpc; #[cfg(test)] extern crate hashable; -extern crate jsonrpc_types; #[macro_use] extern crate libproto; #[macro_use] extern crate cita_logger as logger; -extern crate proof; -extern crate pubsub; #[macro_use] extern crate serde_derive; -extern crate serde_json; #[macro_use] extern crate util; +use crate::core::contracts::grpc::grpc_vm_adapter; +use crate::core::libexecutor::executor::Executor; +use crate::postman::Postman; use cita_directories::DataPath; use clap::App; -use core::contracts::grpc::grpc_vm_adapter; -use core::libexecutor::executor::Executor; use libproto::router::{MsgType, RoutingKey, SubModules}; -use postman::Postman; use pubsub::channel; use pubsub::start_pubsub; use std::thread; diff --git a/cita-executor/src/postman.rs b/cita-executor/src/postman.rs index 8b8316e2b..608740057 100644 --- a/cita-executor/src/postman.rs +++ b/cita-executor/src/postman.rs @@ -15,13 +15,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::core::contracts::solc::sys_config::ChainId; +use crate::core::libexecutor::blacklist::BlackList; +use crate::core::libexecutor::block::{ClosedBlock, OpenBlock}; +use crate::core::libexecutor::call_request::CallRequest; +use crate::core::libexecutor::economical_model::EconomicalModel; +use crate::core::receipt::ReceiptError; +use crate::types::ids::BlockId; use cita_types::{Address, H256, U256}; -use core::contracts::solc::sys_config::ChainId; -use core::libexecutor::blacklist::BlackList; -use core::libexecutor::block::{ClosedBlock, OpenBlock}; -use core::libexecutor::call_request::CallRequest; -use core::libexecutor::economical_model::EconomicalModel; -use core::receipt::ReceiptError; use crossbeam_channel::{Receiver, Sender}; use error::ErrorCode; use jsonrpc_types::rpc_types::{BlockNumber, CountOrCode}; @@ -36,10 +37,9 @@ use serde_json; use std::convert::Into; use std::sync::RwLock; use std::u8; -use types::ids::BlockId; -use core::libexecutor::command; -use core::libexecutor::lru_cache::LRUCache; +use crate::core::libexecutor::command; +use crate::core::libexecutor::lru_cache::LRUCache; use evm::Schedule; use super::backlogs::{wrap_height, Backlogs}; @@ -766,8 +766,8 @@ impl Postman { mod tests { use self::helpers::generate_executed_result; use super::*; + use crate::tests::helpers; use libproto::Message; - use tests::helpers; #[test] fn test_bootstrap_broadcast_at_0th() { diff --git a/cita-executor/src/snapshot.rs b/cita-executor/src/snapshot.rs index a20c61a37..92ded9a0b 100644 --- a/cita-executor/src/snapshot.rs +++ b/cita-executor/src/snapshot.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -15,14 +15,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -extern crate crossbeam_channel; - -use cita_db::journaldb::Algorithm; -use cita_db::DatabaseConfig; -use core::db::NUM_COLUMNS; -use core::libexecutor::command; -use core::snapshot as CoreSnapshot; -use core::snapshot::io::{PackedReader, PackedWriter}; +use crate::cita_db::journaldb::Algorithm; +use crate::cita_db::DatabaseConfig; +use crate::core::db::NUM_COLUMNS; +use crate::core::libexecutor::command; +use crate::core::snapshot as CoreSnapshot; +use crate::core::snapshot::io::{PackedReader, PackedWriter}; use crossbeam_channel::{Receiver, Sender}; use libproto::router::{MsgType, RoutingKey, SubModules}; use libproto::snapshot::{Resp as Ack, SnapshotResp}; diff --git a/cita-executor/src/tests/helpers.rs b/cita-executor/src/tests/helpers.rs index a508b1e3c..21a5fee85 100644 --- a/cita-executor/src/tests/helpers.rs +++ b/cita-executor/src/tests/helpers.rs @@ -15,10 +15,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::postman::Postman; use cita_crypto::{CreateKey, PrivKey, Sign, Signature, Signer}; use cita_types::{traits::LowerHex, Address, H256, U256}; use hashable::Hashable; -use postman::Postman; use std::str::FromStr; #[cfg(feature = "secp256k1")] diff --git a/cita-jsonrpc/Cargo.toml b/cita-jsonrpc/Cargo.toml index 0964ebf6b..ad2e2cb02 100644 --- a/cita-jsonrpc/Cargo.toml +++ b/cita-jsonrpc/Cargo.toml @@ -2,6 +2,7 @@ name = "cita-jsonrpc" version = "0.1.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] futures = "0.1" diff --git a/cita-jsonrpc/build.rs b/cita-jsonrpc/build.rs index a0533082a..c20d26175 100644 --- a/cita-jsonrpc/build.rs +++ b/cita-jsonrpc/build.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -15,8 +15,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -extern crate util; - use std::env; use util::build_info::gen_build_info; diff --git a/cita-jsonrpc/src/http_server.rs b/cita-jsonrpc/src/http_server.rs index 83d519528..b53a31228 100644 --- a/cita-jsonrpc/src/http_server.rs +++ b/cita-jsonrpc/src/http_server.rs @@ -310,7 +310,7 @@ mod integration_test { use serde_json; use tokio_core::reactor::Core; - use helper::TransferType; + use crate::helper::TransferType; struct Serve { pub addr: SocketAddr, diff --git a/cita-jsonrpc/src/main.rs b/cita-jsonrpc/src/main.rs index 303b10ec1..c647bf9e3 100644 --- a/cita-jsonrpc/src/main.rs +++ b/cita-jsonrpc/src/main.rs @@ -53,42 +53,16 @@ //! uuid number and `TransferType`. //! -extern crate bytes; -extern crate clap; -extern crate cpuprofiler; -extern crate dotenv; -extern crate error; -extern crate futures; -extern crate http; -extern crate httparse; -extern crate hyper; -extern crate jsonrpc_proto; -extern crate jsonrpc_types; -extern crate libc; #[macro_use] extern crate libproto; #[macro_use] extern crate cita_logger as logger; -extern crate net2; -extern crate num_cpus; -extern crate pubsub; -extern crate serde; #[macro_use] extern crate serde_derive; #[cfg_attr(test, macro_use)] extern crate serde_json; -extern crate threadpool; -extern crate time; -extern crate tokio; -extern crate tokio_core; -extern crate tokio_executor; -extern crate tokio_io; -extern crate tokio_timer; -extern crate unicase; #[macro_use] extern crate util; -extern crate uuid; -extern crate ws; mod config; mod extractor; @@ -103,26 +77,26 @@ mod service_error; mod soliloquy; mod ws_handler; +use crate::config::{NewTxFlowConfig, ProfileConfig}; +use crate::fdlimit::set_fd_limit; +use crate::http_server::Server; +use crate::soliloquy::Soliloquy; +use crate::ws_handler::WsFactory; use clap::App; -use config::{NewTxFlowConfig, ProfileConfig}; use cpuprofiler::PROFILER; -use fdlimit::set_fd_limit; use futures::Future; -use http_server::Server; use libproto::request::{self as reqlib, BatchRequest}; use libproto::router::{MsgType, RoutingKey, SubModules}; use libproto::Message; use libproto::TryInto; use pubsub::channel::{self, Sender}; use pubsub::start_pubsub; -use soliloquy::Soliloquy; use std::collections::HashMap; use std::sync::Arc; use std::thread; use std::time::{Duration, SystemTime}; use util::{set_panic_handler, Mutex}; use uuid::Uuid; -use ws_handler::WsFactory; include!(concat!(env!("OUT_DIR"), "/build_info.rs")); diff --git a/cita-jsonrpc/src/mq_handler.rs b/cita-jsonrpc/src/mq_handler.rs index b00ebf5ae..be73d3082 100644 --- a/cita-jsonrpc/src/mq_handler.rs +++ b/cita-jsonrpc/src/mq_handler.rs @@ -15,7 +15,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use helper::{RpcMap, TransferType}; +use crate::helper::{RpcMap, TransferType}; use jsonrpc_proto::response::OutputExt; use jsonrpc_types::rpc_response::Output; use libproto::router::{MsgType, RoutingKey, SubModules}; diff --git a/cita-jsonrpc/src/response.rs b/cita-jsonrpc/src/response.rs index 73a7d7620..aa3cbb37e 100644 --- a/cita-jsonrpc/src/response.rs +++ b/cita-jsonrpc/src/response.rs @@ -49,7 +49,7 @@ impl HyperResponseExt for HyperResponse { } pub trait IntoResponse { - fn into_response(self, Headers) -> Response; + fn into_response(self, _: Headers) -> Response; } pub trait FutureResponse @@ -195,7 +195,7 @@ mod tests { #[test] fn test_hyper_response_with_headers() { - use http_header::HeaderMapExt; + use crate::http_header::HeaderMapExt; use hyper::{header::*, Method}; let mut headers = HeaderMap::new(); diff --git a/cita-jsonrpc/src/soliloquy.rs b/cita-jsonrpc/src/soliloquy.rs index 7cb7d3aae..6d3fb084e 100644 --- a/cita-jsonrpc/src/soliloquy.rs +++ b/cita-jsonrpc/src/soliloquy.rs @@ -15,8 +15,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use config::Config; -use get_build_info_str; +use crate::config::Config; +use crate::get_build_info_str; use jsonrpc_types::rpc_types::SoftwareVersion; use jsonrpc_types::ErrorCode; use libproto::protos::response::Response; @@ -71,11 +71,11 @@ impl Soliloquy { #[cfg(test)] pub mod tests { - use config::Config; + use crate::config::Config; + use crate::soliloquy::Soliloquy; use jsonrpc_types::ErrorCode; use libproto::Message; use libproto::TryInto; - use soliloquy::Soliloquy; fn get_response(toml_str: String) -> libproto::response::Response { let config = util::parse_config_from_buffer::(&toml_str) diff --git a/cita-jsonrpc/src/ws_handler.rs b/cita-jsonrpc/src/ws_handler.rs index d1a51e75e..d137412c2 100644 --- a/cita-jsonrpc/src/ws_handler.rs +++ b/cita-jsonrpc/src/ws_handler.rs @@ -15,7 +15,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use helper::{select_topic, RpcMap, TransferType}; +use crate::helper::{select_topic, RpcMap, TransferType}; use jsonrpc_proto::complete::CompleteInto; use jsonrpc_types::rpc_request::{PartialRequest, RequestInfo}; use jsonrpc_types::rpc_response::RpcFailure; diff --git a/tests/box-executor/Cargo.toml b/tests/box-executor/Cargo.toml index eb53dd171..87759d52f 100644 --- a/tests/box-executor/Cargo.toml +++ b/tests/box-executor/Cargo.toml @@ -2,6 +2,7 @@ name = "box-executor" version = "0.1.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] serde = "1.0" diff --git a/tests/box-executor/src/config.rs b/tests/box-executor/src/config.rs index 440822b4c..ffec35aeb 100644 --- a/tests/box-executor/src/config.rs +++ b/tests/box-executor/src/config.rs @@ -1,14 +1,6 @@ -extern crate bincode; extern crate cita_crypto as crypto; -extern crate cita_types; -extern crate clap; -extern crate dotenv; -extern crate pubsub; -extern crate rlp; -extern crate rustc_serialize; -extern crate serde_yaml; -use crypto::PrivKey; +use crate::crypto::PrivKey; use std::collections::HashMap; use std::fs; use std::io::Read; diff --git a/tests/box-executor/src/generate_block.rs b/tests/box-executor/src/generate_block.rs index 7711fa15e..1974737e0 100644 --- a/tests/box-executor/src/generate_block.rs +++ b/tests/box-executor/src/generate_block.rs @@ -15,9 +15,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::crypto::{CreateKey, KeyPair, PrivKey, Sign, Signature}; use bincode::{serialize, Infinite}; use cita_types::H256; -use crypto::{CreateKey, KeyPair, PrivKey, Sign, Signature}; use hashable::Hashable; use libproto::TryInto; use libproto::{ diff --git a/tests/box-executor/src/main.rs b/tests/box-executor/src/main.rs index 2b7ddda63..1366471d0 100644 --- a/tests/box-executor/src/main.rs +++ b/tests/box-executor/src/main.rs @@ -15,31 +15,21 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -extern crate bincode; extern crate cita_crypto as crypto; -extern crate cita_types; -extern crate clap; #[macro_use] extern crate libproto; -extern crate dotenv; -extern crate hashable; -extern crate proof; -extern crate rustc_serialize; #[macro_use] extern crate cita_logger as logger; -extern crate pubsub; -extern crate rlp; #[macro_use] extern crate serde_derive; -extern crate serde_yaml; mod config; mod generate_block; mod runner; +use crate::config::Config; use clap::App; -use config::Config; use std::env; fn main() { diff --git a/tests/box-executor/src/runner.rs b/tests/box-executor/src/runner.rs index 5842e4232..4ae599818 100644 --- a/tests/box-executor/src/runner.rs +++ b/tests/box-executor/src/runner.rs @@ -1,14 +1,5 @@ -extern crate bincode; extern crate cita_crypto as crypto; extern crate cita_logger as logger; -extern crate cita_types; -extern crate clap; -extern crate dotenv; -extern crate proof; -extern crate pubsub; -extern crate rlp; -extern crate rustc_serialize; -extern crate serde_yaml; use libproto::{TryFrom, TryInto}; use std::convert::{From, Into}; @@ -16,10 +7,10 @@ use std::str::FromStr; use std::u8; use std::{thread, time}; +use crate::config::Config; +use crate::crypto::PrivKey; +use crate::generate_block::BuildBlock; use cita_types::H256; -use config::Config; -use crypto::PrivKey; -use generate_block::BuildBlock; use libproto::{Message, RichStatus, SignedTransaction}; use libproto::router::{MsgType, RoutingKey, SubModules}; diff --git a/tests/chain-executor-mock/Cargo.toml b/tests/chain-executor-mock/Cargo.toml index 9b5ac2962..97b76469c 100644 --- a/tests/chain-executor-mock/Cargo.toml +++ b/tests/chain-executor-mock/Cargo.toml @@ -2,6 +2,7 @@ name = "chain-executor-mock" version = "0.1.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] serde = "1.0" diff --git a/tests/chain-executor-mock/src/generate_block.rs b/tests/chain-executor-mock/src/generate_block.rs index 8669dfe4c..2bbc720ca 100644 --- a/tests/chain-executor-mock/src/generate_block.rs +++ b/tests/chain-executor-mock/src/generate_block.rs @@ -15,9 +15,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::crypto::{CreateKey, KeyPair, PrivKey, Sign, Signature}; use bincode::{serialize, Infinite}; use cita_types::{Address, H256, U256}; -use crypto::{CreateKey, KeyPair, PrivKey, Sign, Signature}; use hashable::Hashable; use libproto::TryInto; use libproto::{Block, BlockWithProof, Message, SignedTransaction, Transaction}; diff --git a/tests/chain-executor-mock/src/main.rs b/tests/chain-executor-mock/src/main.rs index fd6311d3d..9a31835f0 100644 --- a/tests/chain-executor-mock/src/main.rs +++ b/tests/chain-executor-mock/src/main.rs @@ -15,24 +15,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -extern crate bincode; extern crate cita_crypto as crypto; -extern crate cita_types; -extern crate clap; #[macro_use] extern crate libproto; -extern crate hashable; -extern crate proof; -extern crate rustc_serialize; #[macro_use] extern crate cita_logger as logger; -extern crate pubsub; -extern crate rlp; #[macro_use] extern crate serde_derive; -extern crate dotenv; -extern crate serde_yaml; mod generate_block; @@ -48,10 +38,10 @@ use std::{fs, u8}; use clap::App; +use crate::crypto::{CreateKey, KeyPair, PrivKey}; +use crate::generate_block::BuildBlock; use cita_types::traits::LowerHex; use cita_types::{H256, U256}; -use crypto::{CreateKey, KeyPair, PrivKey}; -use generate_block::BuildBlock; use libproto::router::{MsgType, RoutingKey, SubModules}; use libproto::Message; use libproto::TryFrom; diff --git a/tests/chain-performance-by-mq/Cargo.toml b/tests/chain-performance-by-mq/Cargo.toml index 65ff1b600..10e4baaae 100644 --- a/tests/chain-performance-by-mq/Cargo.toml +++ b/tests/chain-performance-by-mq/Cargo.toml @@ -2,6 +2,7 @@ name = "chain-performance-by-mq" version = "0.1.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] serde = "1.0" diff --git a/tests/chain-performance-by-mq/src/generate_block.rs b/tests/chain-performance-by-mq/src/generate_block.rs index 3d24af29c..3a6f0519f 100644 --- a/tests/chain-performance-by-mq/src/generate_block.rs +++ b/tests/chain-performance-by-mq/src/generate_block.rs @@ -15,9 +15,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::crypto::*; use bincode::{serialize, Infinite}; use cita_types::H256; -use crypto::*; use hashable::Hashable; use libproto::TryInto; use libproto::{Block, BlockWithProof, Message, SignedTransaction, Transaction}; diff --git a/tests/chain-performance-by-mq/src/main.rs b/tests/chain-performance-by-mq/src/main.rs index f8acc5243..e851666a0 100644 --- a/tests/chain-performance-by-mq/src/main.rs +++ b/tests/chain-performance-by-mq/src/main.rs @@ -15,30 +15,21 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -extern crate bincode; extern crate cita_crypto as crypto; -extern crate cita_types; -extern crate clap; -extern crate cpuprofiler; -extern crate dotenv; #[macro_use] extern crate libproto; -extern crate hashable; -extern crate proof; -extern crate rustc_serialize; #[macro_use] extern crate cita_logger as logger; -extern crate pubsub; #[macro_use] extern crate serde_derive; mod generate_block; +use crate::crypto::*; +use crate::generate_block::Generateblock; use cita_types::H256; use clap::App; -use crypto::*; -use generate_block::Generateblock; use libproto::router::{MsgType, RoutingKey, SubModules}; use libproto::Message; use libproto::TryFrom; diff --git a/tests/consensus-mock/Cargo.toml b/tests/consensus-mock/Cargo.toml index 4a5e20a27..8e57fad0d 100644 --- a/tests/consensus-mock/Cargo.toml +++ b/tests/consensus-mock/Cargo.toml @@ -2,6 +2,7 @@ name = "consensus-mock" version = "0.1.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] serde = "1.0" diff --git a/tests/consensus-mock/src/main.rs b/tests/consensus-mock/src/main.rs index 2a2e061eb..93e3e9a11 100644 --- a/tests/consensus-mock/src/main.rs +++ b/tests/consensus-mock/src/main.rs @@ -15,8 +15,6 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -extern crate bincode; -extern crate chrono; extern crate cita_crypto as crypto; #[macro_use] extern crate clap; @@ -24,16 +22,14 @@ extern crate clap; extern crate libproto; #[macro_use] extern crate cita_logger as logger; -extern crate proof; -extern crate pubsub; #[macro_use] extern crate serde_derive; extern crate cita_types as types; -extern crate hashable; +use crate::crypto::{CreateKey, KeyPair, PrivKey, Sign, Signature}; +use crate::types::{Address, H256}; use bincode::{serialize, Infinite}; use clap::App; -use crypto::{CreateKey, KeyPair, PrivKey, Sign, Signature}; use hashable::Hashable; use libproto::blockchain::{Block, BlockBody, BlockTxs, BlockWithProof}; use libproto::router::{MsgType, RoutingKey, SubModules}; @@ -46,7 +42,6 @@ use std::collections::HashMap; use std::convert::Into; use std::thread::sleep; use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH}; -use types::{Address, H256}; pub type PubType = (String, Vec); From a8ccef3c0caec9eb2f9bd9601e71a8ded43ba09c Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Wed, 12 Jun 2019 14:41:57 +0800 Subject: [PATCH 59/91] update check genesis logic --- tests/compatibility/check_genesis.py | 10 +++++++--- tests/compatibility/check_genesis.sh | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/compatibility/check_genesis.py b/tests/compatibility/check_genesis.py index aaade5f04..fc8628e20 100644 --- a/tests/compatibility/check_genesis.py +++ b/tests/compatibility/check_genesis.py @@ -7,7 +7,7 @@ NODE_KEYS = [ '0x98a476f1687bc3d60a2da2adbcba2c46958e61fa2fb4042cd7bc5816a710195b', - '0x0958fc78ca04a68fd52c5622ef2ca3cdb177cce96303c25fe1f487c6436a6dac' + '0xfa669cc5530281d59cb9af15f8c4ce666af51805dc63aaa69995533fb756c150', ] @@ -48,12 +48,16 @@ def check(old, new, check_code): return False # Check the storage storage = old_alloc[addr]['storage'] - for key in storage: + for old_key in storage: + old_value = storage[old_key] + + key = "0x" + old_key[2:].zfill(64) + value = "0x" + old_value[2:].zfill(64) # Ignore the node manager's constructor if key in NODE_KEYS: continue if key not in new_alloc[addr]['storage'] \ - or storage[key] != new_alloc[addr]['storage'][key]: + or value != new_alloc[addr]['storage'][key]: return False return True diff --git a/tests/compatibility/check_genesis.sh b/tests/compatibility/check_genesis.sh index 4f614529d..960b46350 100755 --- a/tests/compatibility/check_genesis.sh +++ b/tests/compatibility/check_genesis.sh @@ -11,7 +11,7 @@ BINARY_DIR=${SOURCE_DIR}/target/install cd ${BINARY_DIR} \ && ./scripts/create_cita_config.py create \ - --super_admin "0x0000000000000000000000000000000000000000" \ + --super_admin "0x4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523" \ --nodes "127.0.0.1:4000" \ && python3 ${SOURCE_DIR}/tests/compatibility/check_genesis.py \ --genesis test-chain/0/genesis.json \ From 8efe3d0193695503c1dcb829336e839526426181 Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Wed, 12 Jun 2019 15:28:37 +0800 Subject: [PATCH 60/91] update submodule --- scripts/config_tool/genesis | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/config_tool/genesis b/scripts/config_tool/genesis index c883acdff..b5d21cad0 160000 --- a/scripts/config_tool/genesis +++ b/scripts/config_tool/genesis @@ -1 +1 @@ -Subproject commit c883acdff4d950e434c148c8671dde355bd26613 +Subproject commit b5d21cad0435c777320f654a27d9d0af4cea25a2 From 63b3d1e75c8c193c1e9ae9c25944b95127eb6a94 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 12 Jun 2019 16:17:48 +0800 Subject: [PATCH 61/91] Update the contributors perline. [skip ci] --- .all-contributorsrc | 4 +-- README-CN.md | 69 ++++++++++++++++++++++++++++++++++++++++++++- README.md | 69 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 138 insertions(+), 4 deletions(-) diff --git a/.all-contributorsrc b/.all-contributorsrc index 01327b5c2..c7ab131dc 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -7,7 +7,7 @@ "README.md", "README-CN.md" ], - "imageSize": 100, + "imageSize": 50, "commit": true, "commitConvention": "none", "contributors": [ @@ -498,5 +498,5 @@ ] } ], - "contributorsPerLine": 7 + "contributorsPerLine": 9 } diff --git a/README-CN.md b/README-CN.md index bf6792242..148ef3ad3 100644 --- a/README-CN.md +++ b/README-CN.md @@ -102,7 +102,74 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d -
kaikai
kaikai

💻
zhangyaning
zhangyaning

💻
Boyu Yang
Boyu Yang

💻
zhiwei
zhiwei

💻
漂流
漂流

💻
AsceticBear
AsceticBear

💻
yubo
yubo

💻
zhouyun-zoe
zhouyun-zoe

📖
Bicheng Gao
Bicheng Gao

💻
lhf
lhf

💻
LinFeng Qian
LinFeng Qian

💻
keroro
keroro

💻
Yaorong
Yaorong

💻
suyanlong
suyanlong

💻
Chen Yu
Chen Yu

💻
zhangsoledad
zhangsoledad

💻
hezhengjun
hezhengjun

💻
zeroqn
zeroqn

💻
urugang
urugang

💻
Jiang Jinyang
Jiang Jinyang

💻
Jan Xie
Jan Xie

💻
Sun Lei
Sun Lei

💻
hyl
hyl

💻
Terry Tai
Terry Tai

💻
Ke Wang
Ke Wang

💻
Mohanson
Mohanson

💻
quanzhan lu
quanzhan lu

💻
duanyytop
duanyytop

💻
clearloop
clearloop

💻
nokodemion
nokodemion

💻
Rain Chen
Rain Chen

💻
Daogang Tang
Daogang Tang

💻
xianliang jiang
xianliang jiang

🐛
Nov
Nov

💻
Rai Yang
Rai Yang

💻
Wenchao Hu
Wenchao Hu

💻
kaiyu
kaiyu

💻
James Chen
James Chen

💻
rev-chaos
rev-chaos

💻
Eason Gao
Eason Gao

💻
Eric Zhang
Eric Zhang

💻
Jun Jiang
Jun Jiang

💻
PRIEWIENV
PRIEWIENV

💻
The Gitter Badger
The Gitter Badger

💻
CL
CL

💻
programmer-liu
programmer-liu

💻
Jiayu Ye
Jiayu Ye

💻
liyanzi
liyanzi

🐛
JiaYi
JiaYi

📖
Timmy Zhang
Timmy Zhang

🤔
Wu Yuyue
Wu Yuyue

📖
xiangmeiLu
xiangmeiLu

📖
mingxiaowu
mingxiaowu

🐛
wangfh666
wangfh666

🐛
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
kaikai
kaikai

💻
zhangyaning
zhangyaning

💻
Boyu Yang
Boyu Yang

💻
zhiwei
zhiwei

💻
漂流
漂流

💻
AsceticBear
AsceticBear

💻
yubo
yubo

💻
zhouyun-zoe
zhouyun-zoe

📖
Bicheng Gao
Bicheng Gao

💻
lhf
lhf

💻
LinFeng Qian
LinFeng Qian

💻
keroro
keroro

💻
Yaorong
Yaorong

💻
suyanlong
suyanlong

💻
Chen Yu
Chen Yu

💻
zhangsoledad
zhangsoledad

💻
hezhengjun
hezhengjun

💻
zeroqn
zeroqn

💻
urugang
urugang

💻
Jiang Jinyang
Jiang Jinyang

💻
Jan Xie
Jan Xie

💻
Sun Lei
Sun Lei

💻
hyl
hyl

💻
Terry Tai
Terry Tai

💻
Ke Wang
Ke Wang

💻
Mohanson
Mohanson

💻
quanzhan lu
quanzhan lu

💻
duanyytop
duanyytop

💻
clearloop
clearloop

💻
nokodemion
nokodemion

💻
Rain Chen
Rain Chen

💻
Daogang Tang
Daogang Tang

💻
xianliang jiang
xianliang jiang

🐛
Nov
Nov

💻
Rai Yang
Rai Yang

💻
Wenchao Hu
Wenchao Hu

💻
kaiyu
kaiyu

💻
James Chen
James Chen

💻
rev-chaos
rev-chaos

💻
Eason Gao
Eason Gao

💻
Eric Zhang
Eric Zhang

💻
Jun Jiang
Jun Jiang

💻
PRIEWIENV
PRIEWIENV

💻
The Gitter Badger
The Gitter Badger

💻
CL
CL

💻
programmer-liu
programmer-liu

💻
Jiayu Ye
Jiayu Ye

💻
liyanzi
liyanzi

🐛
JiaYi
JiaYi

📖
Timmy Zhang
Timmy Zhang

🤔
Wu Yuyue
Wu Yuyue

📖
xiangmeiLu
xiangmeiLu

📖
mingxiaowu
mingxiaowu

🐛
wangfh666
wangfh666

🐛
diff --git a/README.md b/README.md index e13a0828e..41f21ff96 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,74 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d -
kaikai
kaikai

💻
zhangyaning
zhangyaning

💻
Boyu Yang
Boyu Yang

💻
zhiwei
zhiwei

💻
漂流
漂流

💻
AsceticBear
AsceticBear

💻
yubo
yubo

💻
zhouyun-zoe
zhouyun-zoe

📖
Bicheng Gao
Bicheng Gao

💻
lhf
lhf

💻
LinFeng Qian
LinFeng Qian

💻
keroro
keroro

💻
Yaorong
Yaorong

💻
suyanlong
suyanlong

💻
Chen Yu
Chen Yu

💻
zhangsoledad
zhangsoledad

💻
hezhengjun
hezhengjun

💻
zeroqn
zeroqn

💻
urugang
urugang

💻
Jiang Jinyang
Jiang Jinyang

💻
Jan Xie
Jan Xie

💻
Sun Lei
Sun Lei

💻
hyl
hyl

💻
Terry Tai
Terry Tai

💻
Ke Wang
Ke Wang

💻
Mohanson
Mohanson

💻
quanzhan lu
quanzhan lu

💻
duanyytop
duanyytop

💻
clearloop
clearloop

💻
nokodemion
nokodemion

💻
Rain Chen
Rain Chen

💻
Daogang Tang
Daogang Tang

💻
xianliang jiang
xianliang jiang

🐛
Nov
Nov

💻
Rai Yang
Rai Yang

💻
Wenchao Hu
Wenchao Hu

💻
kaiyu
kaiyu

💻
James Chen
James Chen

💻
rev-chaos
rev-chaos

💻
Eason Gao
Eason Gao

💻
Eric Zhang
Eric Zhang

💻
Jun Jiang
Jun Jiang

💻
PRIEWIENV
PRIEWIENV

💻
The Gitter Badger
The Gitter Badger

💻
CL
CL

💻
programmer-liu
programmer-liu

💻
Jiayu Ye
Jiayu Ye

💻
liyanzi
liyanzi

🐛
JiaYi
JiaYi

📖
Timmy Zhang
Timmy Zhang

🤔
Wu Yuyue
Wu Yuyue

📖
xiangmeiLu
xiangmeiLu

📖
mingxiaowu
mingxiaowu

🐛
wangfh666
wangfh666

🐛
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
kaikai
kaikai

💻
zhangyaning
zhangyaning

💻
Boyu Yang
Boyu Yang

💻
zhiwei
zhiwei

💻
漂流
漂流

💻
AsceticBear
AsceticBear

💻
yubo
yubo

💻
zhouyun-zoe
zhouyun-zoe

📖
Bicheng Gao
Bicheng Gao

💻
lhf
lhf

💻
LinFeng Qian
LinFeng Qian

💻
keroro
keroro

💻
Yaorong
Yaorong

💻
suyanlong
suyanlong

💻
Chen Yu
Chen Yu

💻
zhangsoledad
zhangsoledad

💻
hezhengjun
hezhengjun

💻
zeroqn
zeroqn

💻
urugang
urugang

💻
Jiang Jinyang
Jiang Jinyang

💻
Jan Xie
Jan Xie

💻
Sun Lei
Sun Lei

💻
hyl
hyl

💻
Terry Tai
Terry Tai

💻
Ke Wang
Ke Wang

💻
Mohanson
Mohanson

💻
quanzhan lu
quanzhan lu

💻
duanyytop
duanyytop

💻
clearloop
clearloop

💻
nokodemion
nokodemion

💻
Rain Chen
Rain Chen

💻
Daogang Tang
Daogang Tang

💻
xianliang jiang
xianliang jiang

🐛
Nov
Nov

💻
Rai Yang
Rai Yang

💻
Wenchao Hu
Wenchao Hu

💻
kaiyu
kaiyu

💻
James Chen
James Chen

💻
rev-chaos
rev-chaos

💻
Eason Gao
Eason Gao

💻
Eric Zhang
Eric Zhang

💻
Jun Jiang
Jun Jiang

💻
PRIEWIENV
PRIEWIENV

💻
The Gitter Badger
The Gitter Badger

💻
CL
CL

💻
programmer-liu
programmer-liu

💻
Jiayu Ye
Jiayu Ye

💻
liyanzi
liyanzi

🐛
JiaYi
JiaYi

📖
Timmy Zhang
Timmy Zhang

🤔
Wu Yuyue
Wu Yuyue

📖
xiangmeiLu
xiangmeiLu

📖
mingxiaowu
mingxiaowu

🐛
wangfh666
wangfh666

🐛
From a5453c4a76f4a8ec7efed2b3082263cedc3ba842 Mon Sep 17 00:00:00 2001 From: leeyr Date: Tue, 11 Jun 2019 19:31:38 +0800 Subject: [PATCH 62/91] Add wiki: rocksdb-in-cita. [skip ci] --- docs/wiki/rocksdb-in-cita.md | 89 ++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 docs/wiki/rocksdb-in-cita.md diff --git a/docs/wiki/rocksdb-in-cita.md b/docs/wiki/rocksdb-in-cita.md new file mode 100644 index 000000000..500107178 --- /dev/null +++ b/docs/wiki/rocksdb-in-cita.md @@ -0,0 +1,89 @@ +## RocksDB 简单介绍 +当前 CITA 使用 RocksDB 作为其底层存储的数据库。 +RocksBD 采用的是 LSM-Tree(Log-Structured-Merge-Tree), 如下图所示: + + + +LSM 树的设计思想非常简单,它的原理是把一颗大树拆分成 N 棵小树,它首先写入到内存中(内存没有寻道速度的问题,随机写的性能得到大幅提升), +在内存中构建一颗有序小树,随着小树越来越大,内存的小树会 flush 到磁盘上。磁盘中的树定期可以做 merge 操作,合并成一棵大树。 + +RocksDB 的三种基本文件格式是 memtable/sstfile/logfile,memtable 是一种内存文件数据系统,新写数据会被写进 memtable,部分请求内容会被写进 logfile。 +logfile 是一种有利于顺序写的文件系统。memtable 的内存空间被填满之后,会有一部分老数据被转移到 sstfile 里面,这些数据对应的 logfile 里的 log 就会被安全删除。 +sstfile 中的内容是有序的。 + + + +上图所示,所有 Column Family 共享一个 WAL 文件,但是每个 Column Family 有自己单独的 memtable & ssttable(sstfile),即 log 共享而数据分离。 + +在下面这几种条件下 RocksDB 会 flush memtable 到磁盘. + +1. 当某一个 memtable 的大小超过 write_buffer_size. +2. 当总的 memtable 的大小超过 db_write_buffer_size. +3. 当 WAL 文件的大小超过 max_total_wal_size 之后. + +## 参数配置及相关配置 + +### Columns +CITA 总共创建了 7 个 columns, 分别在 Executor 与 Chain 微服务中使用。它们分别是: +* COL_STATE +* COL_HEADERS +* COL_BODIES +* COL_EXTRA +* COL_TRACE +* COL_ACCOUNT_BLOOM +* COL_NODE_INFO + +### 数据库配置 +* columns : 7 (COLUMNS) +* cache_sizes : 2 M for each column +* max_open_files : 512 +* compaction (default as ssd ): + * initial_file_size : 64 * 1024 * 1024 + * file_size_multiplier : 1 + * write_rate_limit : None + +* wal : true + +### 其它选项 +* see rocksdb_options_create for default options +* max_total_wal_size : 64 * 1024 * 1024 +* verify_checksums_in_compaction : 0 +* create_if_missing : true +* use_fsync : false +* db_write_buffer_size : 4 * 64 * 1024 * 1024 +* max_background_flushes : 2 +* max_background_compactions : 2 +* compaction_style : DBLevelCompaction +* target_file_size_base : 64 * 1024 * 1024 +* target_file_size_multiplier : 1 + +### Column 选项 +* compaction_style : DBLevelCompaction +* target_file_size_base : 64 * 1024 * 1024 +* target_file_size_multiplier : 1 +* db_write_buffer_size : 4 * 64 * 1024 * 1024 +* block_opts.cache : 2 * 1024 * 1024 + +## 关键配置说明 + +在说明配置之前先简单介绍一下 RocksDB。 + +* max_total_wal_size + +wal 的最大空间,CITA 设置为 64M。 + +* db_write_buffer_size + +最大的 DB 写 buffer,即所有 Column 使用的写 buffer 不大于 256M。 + +* write_buffer_size + +这个配置项 CITA 没有特殊配置,使用的是默认值 64M。在执行过程中每个 column 有两个。 + +* max_background_flushes + +最大的 flushes 线程。 + +* max_background_compactions + +最大的压缩线程,线程不宜过多,过多容易导致写请求被 hang 住。 From a604fe4d1704f39e22fc0e78d1e6c58ce27f07b3 Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Wed, 12 Jun 2019 15:59:56 +0800 Subject: [PATCH 63/91] chores: unit test --- .../core/src/contracts/solc/admin.rs | 2 +- .../contracts/solc/permission_management.rs | 6 +-- .../src/contracts/solc/user_management.rs | 38 ------------------- .../core/src/libexecutor/executor.rs | 15 ++++---- 4 files changed, 11 insertions(+), 50 deletions(-) diff --git a/cita-executor/core/src/contracts/solc/admin.rs b/cita-executor/core/src/contracts/solc/admin.rs index 6cb19ba57..2344e8c07 100644 --- a/cita-executor/core/src/contracts/solc/admin.rs +++ b/cita-executor/core/src/contracts/solc/admin.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/contracts/solc/permission_management.rs b/cita-executor/core/src/contracts/solc/permission_management.rs index 92198e0e7..f82e8eda8 100644 --- a/cita-executor/core/src/contracts/solc/permission_management.rs +++ b/cita-executor/core/src/contracts/solc/permission_management.rs @@ -451,14 +451,12 @@ mod tests { // senTx Resource { cont: H160::from_str(reserved_addresses::PERMISSION_SEND_TX).unwrap(), - // func: vec![0, 0, 0, 0], - func: vec![48, 48, 48, 48], + func: vec![0, 0, 0, 0], }, // createContract Resource { cont: H160::from_str(reserved_addresses::PERMISSION_CREATE_CONTRACT).unwrap(), - // func: vec![0, 0, 0, 0], - func: vec![48, 48, 48, 48], + func: vec![0, 0, 0, 0], }, // approveNode Resource { diff --git a/cita-executor/core/src/contracts/solc/user_management.rs b/cita-executor/core/src/contracts/solc/user_management.rs index d999ab2a5..2ddad6669 100644 --- a/cita-executor/core/src/contracts/solc/user_management.rs +++ b/cita-executor/core/src/contracts/solc/user_management.rs @@ -117,42 +117,4 @@ mod tests { vec![H160::from_str(reserved_addresses::GROUP).unwrap()] ); } - - #[test] - #[ignore] - fn test_accounts() { - let executor = init_executor(); - let user_management = UserManagement::new(&executor); - - // Test accounts - let accounts: Vec
= user_management - .accounts( - &H160::from_str("ffffffffffffffffffffffffffffffffff020009").unwrap(), - BlockId::Pending, - ) - .unwrap(); - - assert_eq!( - accounts, - vec![ - Address::from_str("4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523").unwrap(), - Address::from_str("d3f1a71d1d8f073f4e725f57bbe14d67da22f888").unwrap(), - Address::from_str("9dcd6b234e2772c5451fd4ccf7582f4283140697").unwrap(), - ] - ); - - // Test group accounts - let root = H160::from_str(reserved_addresses::GROUP).unwrap(); - - let group_accounts = user_management.load_group_accounts(BlockId::Pending); - assert_eq!(group_accounts.contains_key(&root), true); - assert_eq!( - *group_accounts.get(&root).unwrap(), - vec![ - Address::from_str("4b5ae4567ad5d9fb92bc9afd6a657e6fa13a2523").unwrap(), - Address::from_str("d3f1a71d1d8f073f4e725f57bbe14d67da22f888").unwrap(), - Address::from_str("9dcd6b234e2772c5451fd4ccf7582f4283140697").unwrap(), - ] - ); - } } diff --git a/cita-executor/core/src/libexecutor/executor.rs b/cita-executor/core/src/libexecutor/executor.rs index fdaba0844..5a4eea018 100644 --- a/cita-executor/core/src/libexecutor/executor.rs +++ b/cita-executor/core/src/libexecutor/executor.rs @@ -467,28 +467,29 @@ pub fn make_consensus_config(sys_config: GlobalSysConfig) -> ConsensusConfig { mod tests { extern crate cita_logger as logger; extern crate tempdir; - use cita_crypto::{CreateKey, KeyPair}; use cita_types::Address; - use cita_types::H256; - use contracts::solc::sys_config::SysConfig; use libexecutor::command::Commander; use libexecutor::command::{Command, CommandResp}; use libexecutor::fsm::FSM; - use rustc_hex::FromHex; - use std::str::FromStr; use std::thread; use std::time::Duration; use tests::helpers; use types::ids::BlockId; - use types::reserved_addresses; #[test] + #[cfg(feature = "sha3hash")] fn test_chain_name_valid_block_number() { + use cita_types::H256; + use contracts::solc::sys_config::SysConfig; + use rustc_hex::FromHex; + use std::str::FromStr; + use types::reserved_addresses; + let privkey = H256::from("0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6"); - let mut executor = helpers::init_executor(); + let mut executor = helpers::init_executor(); let to = Address::from_str(reserved_addresses::SYS_CONFIG).unwrap(); let data = "c0c41f220000000000000000000000000000000000000000000\ 000000000000000000020000000000000000000000000000000\ From ce3bf5c6e342f4c46ae40dcde96da86394b589c0 Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Thu, 13 Jun 2019 11:00:38 +0800 Subject: [PATCH 64/91] remove useless features --- Cargo.lock | 1 - tools/create-genesis/Cargo.toml | 18 +----------------- 2 files changed, 1 insertion(+), 18 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ce65aafcd..4275b7f08 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -968,7 +968,6 @@ dependencies = [ "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", - "pubsub 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/tools/create-genesis/Cargo.toml b/tools/create-genesis/Cargo.toml index 2f803a372..098efaef6 100644 --- a/tools/create-genesis/Cargo.toml +++ b/tools/create-genesis/Cargo.toml @@ -19,22 +19,6 @@ clap = "2.33.0" hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -pubsub = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -core-executor = { path="../../cita-executor/core"} +core-executor = { path="../../cita-executor/core", default-features = false} evm = { path="../../cita-executor/evm"} - -[features] -default = ["secp256k1", "sha3hash", "rabbitmq"] -secp256k1 = ["libproto/secp256k1", "proof/secp256k1"] -ed25519 = ["libproto/ed25519", "proof/ed25519"] -sm2 = ["libproto/sm2", "proof/sm2"] -sha3hash = ["hashable/sha3hash", "libproto/sha3hash", "proof/sha3hash"] -blake2bhash = ["hashable/blake2bhash", "libproto/blake2bhash", "proof/blake2bhash"] -sm3hash = ["hashable/sm3hash", "libproto/sm3hash", "proof/sm3hash"] -rabbitmq = ["pubsub/rabbitmq"] -zeromq = ["pubsub/zeromq"] -kafka = ["pubsub/kafka"] -privatetx = ["core-executor/privatetx"] -evm-debug = ["core-executor/evm-debug"] -evm-debug-tests = ["evm-debug", "core-executor/evm-debug-tests"] From 8049db82ac07fff997cd64bdd052ad7e0dada29a Mon Sep 17 00:00:00 2001 From: leeyr Date: Wed, 12 Jun 2019 18:36:22 +0800 Subject: [PATCH 65/91] Fix: should not use error message in default auto exec. --- cita-executor/core/src/contracts/solc/sys_config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cita-executor/core/src/contracts/solc/sys_config.rs b/cita-executor/core/src/contracts/solc/sys_config.rs index 27be4704b..acecfc71d 100644 --- a/cita-executor/core/src/contracts/solc/sys_config.rs +++ b/cita-executor/core/src/contracts/solc/sys_config.rs @@ -341,7 +341,7 @@ impl<'a> SysConfig<'a> { } pub fn default_auto_exec() -> bool { - error!("Use the default autoEXEC."); + info!("Use the default autoEXEC."); false } } From 09bfc1f3d4a5c8efe6b9534aff9a03d8d827a3ce Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Thu, 13 Jun 2019 15:30:22 +0800 Subject: [PATCH 66/91] refactor genesis.rs --- Cargo.lock | 2 - tools/create-genesis/Cargo.toml | 2 - tools/create-genesis/src/genesis.rs | 134 +++++++++++----------------- tools/create-genesis/src/params.rs | 75 ++++++++++++---- tools/create-genesis/src/solc.rs | 15 ++-- 5 files changed, 114 insertions(+), 114 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4275b7f08..4c4ff4320 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -962,12 +962,10 @@ dependencies = [ "ethabi 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethereum-types 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "evm 0.1.0", - "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "json 0.11.14 (registry+https://github.com/rust-lang/crates.io-index)", "libproto 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "proof 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "serde 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "serde_yaml 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/tools/create-genesis/Cargo.toml b/tools/create-genesis/Cargo.toml index 098efaef6..c3875de7b 100644 --- a/tools/create-genesis/Cargo.toml +++ b/tools/create-genesis/Cargo.toml @@ -16,9 +16,7 @@ tiny-keccak = "1.4.2" libsecp256k1 = "0.2.2" clap = "2.33.0" -hashable = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } libproto = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } -proof = { git = "https://github.com/cryptape/cita-common.git", branch = "develop" } core-executor = { path="../../cita-executor/core", default-features = false} evm = { path="../../cita-executor/evm"} diff --git a/tools/create-genesis/src/genesis.rs b/tools/create-genesis/src/genesis.rs index 012a488fa..6f6aa1a2b 100644 --- a/tools/create-genesis/src/genesis.rs +++ b/tools/create-genesis/src/genesis.rs @@ -100,49 +100,12 @@ impl<'a> GenesisCreator<'a> { pub fn init_normal_contracts(&mut self) { for (contract_name, contract_info) in self.contract_list.normal_contracts.list().iter() { let address = &contract_info.address; - let sol_path = self.contract_dir.to_owned() + "/src/" + &contract_info.file; - let abi_path = - self.contract_dir.to_owned() + "/interaction/abi/" + contract_name + ".abi"; - let data = Solc::get_contracts_data(sol_path, contract_name); - + let data = self.get_data(contract_name, contract_info.file.clone()); let input_data = string_2_bytes(data["bin"].clone()); - self.write_docs(contract_name, data); - let abi_file = File::open(abi_path).expect("failed to open abi file."); - let contract = Contract::load(abi_file).unwrap(); - - if let Some(constructor) = contract.constructor() { - let mut params = Vec::new(); - match *contract_name { - "SysConfig" => { - params = self.contract_args.contracts.sys_config.as_params(); - } - "QuotaManager" => { - params = self.contract_args.contracts.quota_manager.as_params(); - } - "NodeManager" => { - params = self.contract_args.contracts.node_manager.as_params(); - } - "ChainManager" => { - params = self.contract_args.contracts.chain_manager.as_params(); - } - "Authorization" => { - params = self.contract_args.contracts.authorization.as_params(); - } - "Group" => { - params = self.contract_args.contracts.group.as_params(); - } - "Admin" => { - params = self.contract_args.contracts.admin.as_params(); - } - "VersionManager" => { - params = self.contract_args.contracts.version_manager.as_params(); - } - "PriceManager" => { - params = self.contract_args.contracts.price_manager.as_params(); - } - _ => (), - } + self.write_docs(contract_name, data); + if let Some(constructor) = self.load_contract(contract_name.to_string()).constructor() { + let params = self.contract_args.get_params(contract_name.to_owned()); let bytes = constructor.encode_input(input_data, ¶ms).unwrap(); let account = Miner::mine(bytes); self.accounts.insert((*address).clone(), account); @@ -157,58 +120,52 @@ impl<'a> GenesisCreator<'a> { pub fn init_permission_contracts(&mut self) { let normal_contracts = self.contract_list.normal_contracts.clone(); let perm_contracts = self.contract_list.permission_contracts.clone(); - - let contract_name: &'static str = "Permission"; - let perm_path = self.contract_dir.to_owned() + "/src/" + &perm_contracts.file; - let abi_path = self.contract_dir.to_owned() + "/interaction/abi/" + contract_name + ".abi"; - - let data = Solc::get_contracts_data(perm_path, contract_name); + let contract_name = "Permission".to_string(); + let data = self.get_data(&contract_name, perm_contracts.file); let input_data = string_2_bytes(data["bin"].clone()); - self.write_docs(&contract_name, data); - let abi_file = File::open(abi_path).expect("failed to open abi file."); - let contract = Contract::load(abi_file).unwrap(); - let constructor = contract.constructor().unwrap(); - - for (name, info) in perm_contracts.basic.list().iter() { - let address = &info.address; - let params = self - .contract_list - .permission_contracts - .basic - .as_params(name, info); - - let bytes = constructor - .encode_input(input_data.clone(), ¶ms) - .unwrap(); - let account = Miner::mine(bytes); - self.accounts.insert(address.clone(), account); - println!("Permission contracts: {:?} {:?} is ok!", name, address); - } + self.write_docs(&contract_name, data); + if let Some(constructor) = self.load_contract(contract_name).constructor() { + for (name, info) in perm_contracts.basic.list().iter() { + let address = &info.address; + let params = self + .contract_list + .permission_contracts + .basic + .as_params(name, info); + + let bytes = constructor + .encode_input(input_data.clone(), ¶ms) + .unwrap(); + let account = Miner::mine(bytes); + self.accounts.insert(address.clone(), account); + println!("Permission contracts: {:?} {:?} is ok!", name, address); + } - for (name, info) in perm_contracts.contracts.list().iter() { - let perm_address = &info.address; - let params = self.contract_list.permission_contracts.contracts.as_params( - &normal_contracts, - name, - info, - ); - - let bytes = constructor - .encode_input(input_data.clone(), ¶ms) - .unwrap(); - let account = Miner::mine(bytes); - self.accounts.insert((*perm_address).clone(), account); - println!("Permission contracts: {:?} {:?} is ok!", name, perm_address); + for (name, info) in perm_contracts.contracts.list().iter() { + let perm_address = &info.address; + let params = self.contract_list.permission_contracts.contracts.as_params( + &normal_contracts, + name, + info, + ); + + let bytes = constructor + .encode_input(input_data.clone(), ¶ms) + .unwrap(); + let account = Miner::mine(bytes); + self.accounts.insert((*perm_address).clone(), account); + println!("Permission contracts: {:?} {:?} is ok!", name, perm_address); + } } } - pub fn write_docs(&self, name: &str, data: BTreeMap<&'static str, String>) { + pub fn write_docs(&self, name: &str, data: BTreeMap) { for doc_type in ["hashes", "userdoc", "devdoc"].iter() { let file_path = self.contract_docs_dir.to_owned() + "/" + name + "-" + doc_type + ".json"; let path = Path::new(&file_path); - let json = json::stringify_pretty(data[doc_type].clone(), 4); + let json = json::stringify_pretty(data[*doc_type].clone(), 4); let mut f = File::create(path).expect("failed to write docs."); let _ = f.write_all(&json.as_bytes()); } @@ -232,4 +189,15 @@ impl<'a> GenesisCreator<'a> { let f = File::create(self.genesis_path.to_owned()).expect("failed to create genesis.json."); let _ = serde_json::to_writer_pretty(f, &genesis); } + + pub fn get_data(&self, contract_name: &str, file_path: String) -> BTreeMap { + let path = self.contract_dir.to_owned() + "/src/" + &file_path; + Solc::get_contracts_data(path, contract_name) + } + + pub fn load_contract(&self, contract_name: String) -> Contract { + let abi_path = self.contract_dir.to_owned() + "/interaction/abi/" + &contract_name + ".abi"; + let abi_file = File::open(abi_path).expect("failed to open abi file."); + Contract::load(abi_file).unwrap() + } } diff --git a/tools/create-genesis/src/params.rs b/tools/create-genesis/src/params.rs index 09d614d78..89a654af5 100644 --- a/tools/create-genesis/src/params.rs +++ b/tools/create-genesis/src/params.rs @@ -5,6 +5,10 @@ use serde::{Deserialize, Serialize}; use std::fs::File; use std::str::FromStr; +pub trait GetParams { + fn as_params(&self) -> Vec; +} + #[derive(Debug, PartialEq, Serialize, Deserialize)] pub struct InitData { #[serde(rename = "Contracts")] @@ -16,6 +20,41 @@ impl InitData { let f = File::open(path).expect("failed to open file"); serde_yaml::from_reader(f).unwrap() } + + pub fn get_params(&self, contract_name: &str) -> Vec { + let mut params = Vec::new(); + match contract_name { + "SysConfig" => { + params = self.contracts.sys_config.as_params(); + } + "QuotaManager" => { + params = self.contracts.quota_manager.as_params(); + } + "NodeManager" => { + params = self.contracts.node_manager.as_params(); + } + "ChainManager" => { + params = self.contracts.chain_manager.as_params(); + } + "Authorization" => { + params = self.contracts.authorization.as_params(); + } + "Group" => { + params = self.contracts.group.as_params(); + } + "Admin" => { + params = self.contracts.admin.as_params(); + } + "VersionManager" => { + params = self.contracts.version_manager.as_params(); + } + "PriceManager" => { + params = self.contracts.price_manager.as_params(); + } + _ => (), + } + params + } } #[derive(Debug, PartialEq, Serialize, Deserialize)] @@ -97,8 +136,8 @@ pub struct SysConfig { pub auto_exec: bool, } -impl SysConfig { - pub fn as_params(&self) -> Vec { +impl GetParams for SysConfig { + fn as_params(&self) -> Vec { let mut tokens = Vec::new(); tokens.push(Token::Uint( U256::from_str(&self.delay_block_number).unwrap(), @@ -136,8 +175,8 @@ pub struct QuotaManager { pub admin: String, } -impl QuotaManager { - pub fn as_params(&self) -> Vec { +impl GetParams for QuotaManager { + fn as_params(&self) -> Vec { let mut tokens = Vec::new(); tokens.push(Token::Address( Address::from_str(clean_0x(&self.admin)).unwrap(), @@ -152,8 +191,8 @@ pub struct NodeManager { pub stakes: Vec, } -impl NodeManager { - pub fn as_params(&self) -> Vec { +impl GetParams for NodeManager { + fn as_params(&self) -> Vec { let mut tokens = Vec::new(); let mut nodes = Vec::new(); @@ -181,8 +220,8 @@ pub struct ChainManager { pub parent_chain_authorities: Vec, } -impl ChainManager { - pub fn as_params(&self) -> Vec { +impl GetParams for ChainManager { + fn as_params(&self) -> Vec { let mut tokens = Vec::new(); tokens.push(Token::Uint(U256::from_str(&self.parent_chain_id).unwrap())); @@ -202,8 +241,8 @@ pub struct Authorization { pub super_admin: String, } -impl Authorization { - pub fn as_params(&self) -> Vec { +impl GetParams for Authorization { + fn as_params(&self) -> Vec { let mut tokens = Vec::new(); tokens.push(Token::Address( Address::from_str(clean_0x(&self.super_admin)).unwrap(), @@ -219,8 +258,8 @@ pub struct Group { pub accounts: Vec, } -impl Group { - pub fn as_params(&self) -> Vec { +impl GetParams for Group { + fn as_params(&self) -> Vec { let mut tokens = Vec::new(); tokens.push(Token::Address( Address::from_str(clean_0x(&self.parent)).unwrap(), @@ -241,8 +280,8 @@ pub struct Admin { pub admin: String, } -impl Admin { - pub fn as_params(&self) -> Vec { +impl GetParams for Admin { + fn as_params(&self) -> Vec { let mut tokens = Vec::new(); tokens.push(Token::Address( Address::from_str(clean_0x(&self.admin)).unwrap(), @@ -256,8 +295,8 @@ pub struct VersionManager { pub version: String, } -impl VersionManager { - pub fn as_params(&self) -> Vec { +impl GetParams for VersionManager { + fn as_params(&self) -> Vec { let mut tokens = Vec::new(); tokens.push(Token::Uint(U256::from_str(&self.version).unwrap())); tokens @@ -270,8 +309,8 @@ pub struct PriceManager { pub quota_price: String, } -impl PriceManager { - pub fn as_params(&self) -> Vec { +impl GetParams for PriceManager { + fn as_params(&self) -> Vec { let mut tokens = Vec::new(); tokens.push(Token::Uint(U256::from_dec_str(&self.quota_price).unwrap())); tokens diff --git a/tools/create-genesis/src/solc.rs b/tools/create-genesis/src/solc.rs index 8bddbe724..e008a628b 100644 --- a/tools/create-genesis/src/solc.rs +++ b/tools/create-genesis/src/solc.rs @@ -5,10 +5,7 @@ use std::process::Command; pub struct Solc; impl Solc { - pub fn get_contracts_data<'a>( - file_path: String, - contract_name: &'a str, - ) -> BTreeMap<&'a str, String> { + pub fn get_contracts_data(file_path: String, contract_name: &str) -> BTreeMap { let output = Command::new("solc") .arg(file_path.clone()) .arg("--allow-paths") @@ -29,11 +26,11 @@ impl Solc { let devdoc = &compiled["contracts"][&index]["devdoc"]; let mut data = BTreeMap::new(); - data.insert("bin", bin.to_string()); - data.insert("abi", abi.to_string()); - data.insert("hashes", hashes.to_string()); - data.insert("userdoc", userdoc.to_string()); - data.insert("devdoc", devdoc.to_string()); + data.insert("bin".to_string(), bin.to_string()); + data.insert("abi".to_string(), abi.to_string()); + data.insert("hashes".to_string(), hashes.to_string()); + data.insert("userdoc".to_string(), userdoc.to_string()); + data.insert("devdoc".to_string(), devdoc.to_string()); data } From 97af14d43829f165435b67aaa2eb4ad79ccfaf11 Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Thu, 13 Jun 2019 19:12:45 +0800 Subject: [PATCH 67/91] use hashmap to store params --- tools/create-genesis/src/genesis.rs | 5 ++- tools/create-genesis/src/params.rs | 65 +++++++++++++++-------------- 2 files changed, 37 insertions(+), 33 deletions(-) diff --git a/tools/create-genesis/src/genesis.rs b/tools/create-genesis/src/genesis.rs index 6f6aa1a2b..e3f24154b 100644 --- a/tools/create-genesis/src/genesis.rs +++ b/tools/create-genesis/src/genesis.rs @@ -98,6 +98,7 @@ impl<'a> GenesisCreator<'a> { } pub fn init_normal_contracts(&mut self) { + let normal_params = self.contract_args.get_params(); for (contract_name, contract_info) in self.contract_list.normal_contracts.list().iter() { let address = &contract_info.address; let data = self.get_data(contract_name, contract_info.file.clone()); @@ -105,7 +106,9 @@ impl<'a> GenesisCreator<'a> { self.write_docs(contract_name, data); if let Some(constructor) = self.load_contract(contract_name.to_string()).constructor() { - let params = self.contract_args.get_params(contract_name.to_owned()); + let params = normal_params + .get(*contract_name) + .map_or(Vec::new(), |p| (*p).clone()); let bytes = constructor.encode_input(input_data, ¶ms).unwrap(); let account = Miner::mine(bytes); self.accounts.insert((*address).clone(), account); diff --git a/tools/create-genesis/src/params.rs b/tools/create-genesis/src/params.rs index 89a654af5..b38743fa8 100644 --- a/tools/create-genesis/src/params.rs +++ b/tools/create-genesis/src/params.rs @@ -2,6 +2,7 @@ use crate::common::clean_0x; use ethabi::Token; use ethereum_types::{Address, U256}; use serde::{Deserialize, Serialize}; +use std::collections::BTreeMap; use std::fs::File; use std::str::FromStr; @@ -21,38 +22,38 @@ impl InitData { serde_yaml::from_reader(f).unwrap() } - pub fn get_params(&self, contract_name: &str) -> Vec { - let mut params = Vec::new(); - match contract_name { - "SysConfig" => { - params = self.contracts.sys_config.as_params(); - } - "QuotaManager" => { - params = self.contracts.quota_manager.as_params(); - } - "NodeManager" => { - params = self.contracts.node_manager.as_params(); - } - "ChainManager" => { - params = self.contracts.chain_manager.as_params(); - } - "Authorization" => { - params = self.contracts.authorization.as_params(); - } - "Group" => { - params = self.contracts.group.as_params(); - } - "Admin" => { - params = self.contracts.admin.as_params(); - } - "VersionManager" => { - params = self.contracts.version_manager.as_params(); - } - "PriceManager" => { - params = self.contracts.price_manager.as_params(); - } - _ => (), - } + pub fn get_params(&self) -> BTreeMap> { + let mut params = BTreeMap::new(); + params.insert( + "SysConfig".to_string(), + self.contracts.sys_config.as_params(), + ); + params.insert( + "QuotaManager".to_string(), + self.contracts.quota_manager.as_params(), + ); + params.insert( + "NodeManager".to_string(), + self.contracts.node_manager.as_params(), + ); + params.insert( + "ChainManager".to_string(), + self.contracts.chain_manager.as_params(), + ); + params.insert( + "Authorization".to_string(), + self.contracts.authorization.as_params(), + ); + params.insert("Group".to_string(), self.contracts.group.as_params()); + params.insert("Admin".to_string(), self.contracts.admin.as_params()); + params.insert( + "VersionManager".to_string(), + self.contracts.version_manager.as_params(), + ); + params.insert( + "PriceManager".to_string(), + self.contracts.price_manager.as_params(), + ); params } } From 35e4e17efeed2a3622af2e85c74e5e1d91e87ae8 Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Fri, 14 Jun 2019 15:15:32 +0800 Subject: [PATCH 68/91] refactor contracts --- tools/create-genesis/src/contracts.rs | 228 +++++--------------------- tools/create-genesis/src/genesis.rs | 12 +- 2 files changed, 46 insertions(+), 194 deletions(-) diff --git a/tools/create-genesis/src/contracts.rs b/tools/create-genesis/src/contracts.rs index 7b47bec33..a4a6b1929 100644 --- a/tools/create-genesis/src/contracts.rs +++ b/tools/create-genesis/src/contracts.rs @@ -143,17 +143,19 @@ impl Basic { basic } - pub fn as_params(&self, name: &str, info: &BasicInfo) -> Vec { + pub fn as_params(&self, name: &str) -> Vec { let mut tokens = Vec::new(); - tokens.push(Token::FixedBytes(String::from(name).into_bytes())); - let mut conts = Vec::new(); - let addr = Address::from_str(clean_0x(&info.address)).unwrap(); - conts.push(Token::Address(addr)); - let mut funcs = Vec::new(); - funcs.push(Token::FixedBytes(vec![0, 0, 0, 0])); - - tokens.push(Token::Array(conts)); - tokens.push(Token::Array(funcs)); + if let Some(info) = self.list().get(name) { + tokens.push(Token::FixedBytes(String::from(name).into_bytes())); + let mut conts = Vec::new(); + let addr = Address::from_str(clean_0x(&info.address)).unwrap(); + conts.push(Token::Address(addr)); + let mut funcs = Vec::new(); + funcs.push(Token::FixedBytes(vec![0, 0, 0, 0])); + + tokens.push(Token::Array(conts)); + tokens.push(Token::Array(funcs)); + } tokens } } @@ -260,186 +262,14 @@ impl Contracts { contracts } - pub fn as_params( - &self, - normal_contracts: &NormalContracts, - name: &str, - info: &ContractsInfo, - ) -> Vec { + pub fn as_params(&self, normal_contracts: &NormalContracts, name: &str) -> Vec { let mut tokens = Vec::new(); - let reference = normal_contracts.list(); - - // Get name - tokens.push(Token::FixedBytes(String::from(name).into_bytes())); - // Get conts - let mut conts = Vec::new(); - match name { - "newPermission" => { - for a in self.new_permission.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "deletePermission" => { - for a in self.delete_permission.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "updatePermission" => { - for a in self.update_permission.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "setAuth" => { - for a in self.set_auth.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "cancelAuth" => { - for a in self.cancel_auth.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "newRole" => { - for a in self.new_role.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "deleteRole" => { - for a in self.delete_role.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "updateRole" => { - for a in self.update_role.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "setRole" => { - for a in self.set_role.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "cancelRole" => { - for a in self.cancel_role.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "newGroup" => { - for a in self.new_group.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "deleteGroup" => { - for a in self.delete_group.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "updateGroup" => { - for a in self.update_group.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "newNode" => { - for a in self.new_node.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "deleteNode" => { - for a in self.delete_node.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "updateNode" => { - for a in self.update_node.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "accountQuota" => { - for a in self.account_quota.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "blockQuota" => { - for a in self.block_quota.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "batchTx" => { - for a in self.batch_tx.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "emergencyBrake" => { - for a in self.emergency_brake.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "quotaPrice" => { - for a in self.quota_price.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - "version" => { - for a in self.version.contracts.iter() { - let contract_info = &reference[a.as_str()]; - let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); - conts.push(Token::Address(address)); - } - } - _ => panic!("Unexpected permission contract name"), - } - - // Get funcs - let mut funcs = Vec::new(); - for f in info.functions.iter() { - let func = keccak256(f.as_bytes()).to_vec(); - funcs.push(Token::FixedBytes(func[0..4].to_vec())); + if let Some(info) = self.list().get(name) { + tokens.push(Token::FixedBytes(String::from(name).into_bytes())); + let (conts, funcs) = info.get_contract_info(normal_contracts); + tokens.push(Token::Array(conts)); + tokens.push(Token::Array(funcs)); } - - tokens.push(Token::Array(conts)); - tokens.push(Token::Array(funcs)); tokens } } @@ -450,6 +280,28 @@ pub struct ContractsInfo { pub contracts: Vec, pub functions: Vec, } + +impl ContractsInfo { + pub fn get_contract_info( + &self, + normal_contracts: &NormalContracts, + ) -> (Vec, Vec) { + let mut conts = Vec::new(); + let reference = normal_contracts.list(); + for a in self.contracts.iter() { + let contract_info = &reference[a.as_str()]; + let address = Address::from_str(clean_0x(&contract_info.address)).unwrap(); + conts.push(Token::Address(address)); + } + + let mut funcs = Vec::new(); + for f in self.functions.iter() { + let func = keccak256(f.as_bytes()).to_vec(); + funcs.push(Token::FixedBytes(func[0..4].to_vec())); + } + (conts, funcs) + } +} #[cfg(test)] mod tests { use super::ContractsData; diff --git a/tools/create-genesis/src/genesis.rs b/tools/create-genesis/src/genesis.rs index e3f24154b..2fc41a552 100644 --- a/tools/create-genesis/src/genesis.rs +++ b/tools/create-genesis/src/genesis.rs @@ -135,7 +135,7 @@ impl<'a> GenesisCreator<'a> { .contract_list .permission_contracts .basic - .as_params(name, info); + .as_params(name); let bytes = constructor .encode_input(input_data.clone(), ¶ms) @@ -147,11 +147,11 @@ impl<'a> GenesisCreator<'a> { for (name, info) in perm_contracts.contracts.list().iter() { let perm_address = &info.address; - let params = self.contract_list.permission_contracts.contracts.as_params( - &normal_contracts, - name, - info, - ); + let params = self + .contract_list + .permission_contracts + .contracts + .as_params(&normal_contracts, name); let bytes = constructor .encode_input(input_data.clone(), ¶ms) From 93969a4c97e51afb07bfae2a350acda10508985d Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Fri, 14 Jun 2019 16:44:26 +0800 Subject: [PATCH 69/91] chore: update version --- tools/create-genesis/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/create-genesis/src/main.rs b/tools/create-genesis/src/main.rs index a85051360..610eedec7 100644 --- a/tools/create-genesis/src/main.rs +++ b/tools/create-genesis/src/main.rs @@ -11,8 +11,8 @@ use genesis::GenesisCreator; fn main() { let matches = App::new("CITA genesis creator") - .version("1.0") - .author("Cryptape Technologies") + .version(env!("CARGO_PKG_VERSION")) + .author(env!("CARGO_PKG_AUTHORS")) .arg( Arg::with_name("contract_dir") .help("The directory of contracts.") From b7e9f3987200fc046d3e396fea9fe1dab3a637ab Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Thu, 20 Jun 2019 14:51:30 +0800 Subject: [PATCH 70/91] chore: update data and remove useless code[skip travis] --- cita-auth/build.rs | 2 +- cita-auth/src/batch_forward.rs | 2 +- cita-auth/src/block_txn.rs | 2 +- cita-auth/src/block_verify.rs | 2 +- cita-auth/src/config.rs | 2 +- cita-auth/src/dispatcher.rs | 2 +- cita-auth/src/handler.rs | 2 +- cita-auth/src/history.rs | 2 +- cita-auth/src/transaction_verify.rs | 2 +- cita-auth/src/txwal.rs | 2 +- cita-chain/core/src/env_info.rs | 36 +------------------ cita-chain/core/src/lib.rs | 2 -- cita-chain/core/src/libchain/chain.rs | 2 +- cita-chain/core/src/libchain/mod.rs | 2 +- cita-chain/core/src/libchain/rich_status.rs | 2 +- cita-chain/core/src/libchain/status.rs | 2 +- cita-chain/src/block_processor.rs | 2 +- cita-chain/src/forward.rs | 2 +- cita-executor/build.rs | 1 - cita-executor/core/src/benches/executor.rs | 2 +- cita-executor/core/src/benches/mod.rs | 2 +- .../core/src/contracts/grpc/contract.rs | 2 +- .../core/src/contracts/grpc/contract_state.rs | 2 +- .../core/src/contracts/grpc/grpc_vm.rs | 2 +- .../src/contracts/grpc/grpc_vm_adapter.rs | 3 +- cita-executor/core/src/contracts/grpc/mod.rs | 2 +- .../src/contracts/grpc/service_registry.rs | 2 +- .../core/src/contracts/grpc/storage.rs | 2 +- cita-executor/core/src/engines/mod.rs | 2 +- .../core/src/libexecutor/auto_exec.rs | 2 +- .../core/src/libexecutor/blacklist.rs | 2 +- .../core/src/libexecutor/call_request.rs | 2 +- cita-executor/core/src/libexecutor/command.rs | 2 +- .../core/src/libexecutor/economical_model.rs | 2 +- cita-executor/core/src/libexecutor/fsm.rs | 2 +- cita-executor/core/src/libexecutor/genesis.rs | 2 +- .../core/src/libexecutor/lru_cache.rs | 2 +- cita-executor/core/src/libexecutor/mod.rs | 2 +- .../core/src/libexecutor/sys_config.rs | 2 +- cita-executor/src/backlogs.rs | 2 +- cita-executor/src/postman.rs | 2 +- cita-jsonrpc/src/config.rs | 2 +- cita-jsonrpc/src/extractor.rs | 2 +- cita-jsonrpc/src/fdlimit.rs | 2 +- cita-jsonrpc/src/helper.rs | 2 +- cita-jsonrpc/src/http_header.rs | 2 +- cita-jsonrpc/src/http_server.rs | 17 ++++----- cita-jsonrpc/src/main.rs | 1 - cita-jsonrpc/src/mq_handler.rs | 2 +- cita-jsonrpc/src/mq_publisher.rs | 2 +- cita-jsonrpc/src/response.rs | 2 +- cita-jsonrpc/src/service_error.rs | 2 +- cita-jsonrpc/src/ws_handler.rs | 3 +- 53 files changed, 56 insertions(+), 99 deletions(-) diff --git a/cita-auth/build.rs b/cita-auth/build.rs index a0533082a..0b73a9c9c 100644 --- a/cita-auth/build.rs +++ b/cita-auth/build.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-auth/src/batch_forward.rs b/cita-auth/src/batch_forward.rs index 56e6dbc06..890c7f7fe 100644 --- a/cita-auth/src/batch_forward.rs +++ b/cita-auth/src/batch_forward.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-auth/src/block_txn.rs b/cita-auth/src/block_txn.rs index 5cf1c58fe..81185f7b0 100644 --- a/cita-auth/src/block_txn.rs +++ b/cita-auth/src/block_txn.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-auth/src/block_verify.rs b/cita-auth/src/block_verify.rs index 625cf64c8..2bbaa4444 100644 --- a/cita-auth/src/block_verify.rs +++ b/cita-auth/src/block_verify.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-auth/src/config.rs b/cita-auth/src/config.rs index 2e68b8e89..f017e771e 100644 --- a/cita-auth/src/config.rs +++ b/cita-auth/src/config.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-auth/src/dispatcher.rs b/cita-auth/src/dispatcher.rs index fde131ac0..ee22acfe9 100644 --- a/cita-auth/src/dispatcher.rs +++ b/cita-auth/src/dispatcher.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-auth/src/handler.rs b/cita-auth/src/handler.rs index c1b560e38..31fbdd398 100644 --- a/cita-auth/src/handler.rs +++ b/cita-auth/src/handler.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-auth/src/history.rs b/cita-auth/src/history.rs index 19a4cfb61..331370d3f 100644 --- a/cita-auth/src/history.rs +++ b/cita-auth/src/history.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-auth/src/transaction_verify.rs b/cita-auth/src/transaction_verify.rs index 97c6d1b73..8912c4f1c 100644 --- a/cita-auth/src/transaction_verify.rs +++ b/cita-auth/src/transaction_verify.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-auth/src/txwal.rs b/cita-auth/src/txwal.rs index 32aacd0d6..53248539e 100644 --- a/cita-auth/src/txwal.rs +++ b/cita-auth/src/txwal.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-chain/core/src/env_info.rs b/cita-chain/core/src/env_info.rs index d3dd80b69..371af4cd1 100644 --- a/cita-chain/core/src/env_info.rs +++ b/cita-chain/core/src/env_info.rs @@ -14,12 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -// use std::cmp; - use cita_types::{Address, H256, U256}; use header::BlockNumber; use std::sync::Arc; -// use ethjson; /// Simple vector of hashes, should be at most 256 items large, can be smaller if being used /// for a block whose number is less than 257. @@ -42,6 +39,7 @@ pub struct EnvInfo { pub last_hashes: Arc, /// The quota used. pub quota_used: U256, + /// The account quota limit pub account_quota_limit: U256, } @@ -60,42 +58,10 @@ impl Default for EnvInfo { } } -// impl From for EnvInfo { -// fn from(e: ethjson::vm::Env) -> Self { -// let number = e.number.into(); -// EnvInfo { -// number: number, -// author: e.author.into(), -// difficulty: e.difficulty.into(), -// quota_limit: e.quota_limit.into(), -// timestamp: e.timestamp.into(), -// last_hashes: Arc::new((1..cmp::min(number + 1, 257)).map(|i| format!("{}", number - i).as_bytes().crypt_hash()).collect()), -// quota_used: U256::default(), -// } -// } -// } - #[cfg(test)] mod tests { use super::*; - // #[test] - // fn it_serializes_form_json() { - // let env_info = EnvInfo::from(ethjson::vm::Env { - // author: ethjson::hash::Address(Address::from_str("000000f00000000f000000000000f00000000f00").unwrap()), - // number: ethjson::uint::Uint(U256::from(1_112_339)), - // difficulty: ethjson::uint::Uint(U256::from(50_000)), - // quota_limit: ethjson::uint::Uint(U256::from(40_000)), - // timestamp: ethjson::uint::Uint(U256::from(1_100)) - // }); - - // assert_eq!(env_info.number, 1112339); - // assert_eq!(env_info.author, Address::from_str("000000f00000000f000000000000f00000000f00").unwrap()); - // assert_eq!(env_info.quota_limit, 40000.into()); - // assert_eq!(env_info.difficulty, 50000.into()); - // assert_eq!(env_info.quota_used, 0.into()); - // } - #[test] fn it_can_be_created_as_default() { let default_env_info = EnvInfo::default(); diff --git a/cita-chain/core/src/lib.rs b/cita-chain/core/src/lib.rs index 08cac6fe8..f2c373110 100644 --- a/cita-chain/core/src/lib.rs +++ b/cita-chain/core/src/lib.rs @@ -55,10 +55,8 @@ pub mod env_info; #[macro_use] pub mod error; - pub mod filters; pub mod libchain; pub mod snapshot; - pub use cita_db::journaldb; pub use types::*; diff --git a/cita-chain/core/src/libchain/chain.rs b/cita-chain/core/src/libchain/chain.rs index fc921dade..976706ff5 100644 --- a/cita-chain/core/src/libchain/chain.rs +++ b/cita-chain/core/src/libchain/chain.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-chain/core/src/libchain/mod.rs b/cita-chain/core/src/libchain/mod.rs index b9c0d5ddd..09115d095 100644 --- a/cita-chain/core/src/libchain/mod.rs +++ b/cita-chain/core/src/libchain/mod.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-chain/core/src/libchain/rich_status.rs b/cita-chain/core/src/libchain/rich_status.rs index 4fab0ca09..19ea1cd4d 100644 --- a/cita-chain/core/src/libchain/rich_status.rs +++ b/cita-chain/core/src/libchain/rich_status.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-chain/core/src/libchain/status.rs b/cita-chain/core/src/libchain/status.rs index 9b77dc19f..012198fcb 100644 --- a/cita-chain/core/src/libchain/status.rs +++ b/cita-chain/core/src/libchain/status.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-chain/src/block_processor.rs b/cita-chain/src/block_processor.rs index 330e43837..4ca7dfd7e 100644 --- a/cita-chain/src/block_processor.rs +++ b/cita-chain/src/block_processor.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-chain/src/forward.rs b/cita-chain/src/forward.rs index 3406b7966..d82074f2d 100644 --- a/cita-chain/src/forward.rs +++ b/cita-chain/src/forward.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/build.rs b/cita-executor/build.rs index c20d26175..14aad7c92 100644 --- a/cita-executor/build.rs +++ b/cita-executor/build.rs @@ -16,7 +16,6 @@ // along with this program. If not, see . use std::env; - use util::build_info::gen_build_info; fn main() { diff --git a/cita-executor/core/src/benches/executor.rs b/cita-executor/core/src/benches/executor.rs index 7c039dd2f..c4cce0b07 100644 --- a/cita-executor/core/src/benches/executor.rs +++ b/cita-executor/core/src/benches/executor.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/benches/mod.rs b/cita-executor/core/src/benches/mod.rs index 457064991..0db48a3da 100644 --- a/cita-executor/core/src/benches/mod.rs +++ b/cita-executor/core/src/benches/mod.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/contracts/grpc/contract.rs b/cita-executor/core/src/contracts/grpc/contract.rs index 62cb8ad5f..f49daf6b0 100644 --- a/cita-executor/core/src/contracts/grpc/contract.rs +++ b/cita-executor/core/src/contracts/grpc/contract.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/contracts/grpc/contract_state.rs b/cita-executor/core/src/contracts/grpc/contract_state.rs index d45e18b2b..6c01a6596 100644 --- a/cita-executor/core/src/contracts/grpc/contract_state.rs +++ b/cita-executor/core/src/contracts/grpc/contract_state.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/contracts/grpc/grpc_vm.rs b/cita-executor/core/src/contracts/grpc/grpc_vm.rs index 11296aa76..c1d770401 100644 --- a/cita-executor/core/src/contracts/grpc/grpc_vm.rs +++ b/cita-executor/core/src/contracts/grpc/grpc_vm.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/contracts/grpc/grpc_vm_adapter.rs b/cita-executor/core/src/contracts/grpc/grpc_vm_adapter.rs index c15096afa..4586398ce 100644 --- a/cita-executor/core/src/contracts/grpc/grpc_vm_adapter.rs +++ b/cita-executor/core/src/contracts/grpc/grpc_vm_adapter.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -33,7 +33,6 @@ pub struct ExecutorServiceImpl { } impl ExecutorService for ExecutorServiceImpl { - // add code here fn register( &self, _o: ::grpc::RequestOptions, diff --git a/cita-executor/core/src/contracts/grpc/mod.rs b/cita-executor/core/src/contracts/grpc/mod.rs index 4ddf5d3e3..796f2a246 100644 --- a/cita-executor/core/src/contracts/grpc/mod.rs +++ b/cita-executor/core/src/contracts/grpc/mod.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/contracts/grpc/service_registry.rs b/cita-executor/core/src/contracts/grpc/service_registry.rs index a185e6a4f..eeb2a0061 100644 --- a/cita-executor/core/src/contracts/grpc/service_registry.rs +++ b/cita-executor/core/src/contracts/grpc/service_registry.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/contracts/grpc/storage.rs b/cita-executor/core/src/contracts/grpc/storage.rs index 21a1115d7..fdc7abae1 100644 --- a/cita-executor/core/src/contracts/grpc/storage.rs +++ b/cita-executor/core/src/contracts/grpc/storage.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/engines/mod.rs b/cita-executor/core/src/engines/mod.rs index 4a73aef9e..2c8f8b699 100644 --- a/cita-executor/core/src/engines/mod.rs +++ b/cita-executor/core/src/engines/mod.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/libexecutor/auto_exec.rs b/cita-executor/core/src/libexecutor/auto_exec.rs index 862476d13..150737da2 100644 --- a/cita-executor/core/src/libexecutor/auto_exec.rs +++ b/cita-executor/core/src/libexecutor/auto_exec.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/libexecutor/blacklist.rs b/cita-executor/core/src/libexecutor/blacklist.rs index ff6c462c0..267b9abf3 100644 --- a/cita-executor/core/src/libexecutor/blacklist.rs +++ b/cita-executor/core/src/libexecutor/blacklist.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/libexecutor/call_request.rs b/cita-executor/core/src/libexecutor/call_request.rs index b028f7097..38c13dcfc 100644 --- a/cita-executor/core/src/libexecutor/call_request.rs +++ b/cita-executor/core/src/libexecutor/call_request.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/libexecutor/command.rs b/cita-executor/core/src/libexecutor/command.rs index 74d09252a..41965ee34 100644 --- a/cita-executor/core/src/libexecutor/command.rs +++ b/cita-executor/core/src/libexecutor/command.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/libexecutor/economical_model.rs b/cita-executor/core/src/libexecutor/economical_model.rs index 57937121c..f6b893837 100644 --- a/cita-executor/core/src/libexecutor/economical_model.rs +++ b/cita-executor/core/src/libexecutor/economical_model.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/libexecutor/fsm.rs b/cita-executor/core/src/libexecutor/fsm.rs index 39fa3e4b8..1f87dcdd5 100644 --- a/cita-executor/core/src/libexecutor/fsm.rs +++ b/cita-executor/core/src/libexecutor/fsm.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/libexecutor/genesis.rs b/cita-executor/core/src/libexecutor/genesis.rs index bc9585afb..74fc32e00 100644 --- a/cita-executor/core/src/libexecutor/genesis.rs +++ b/cita-executor/core/src/libexecutor/genesis.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/libexecutor/lru_cache.rs b/cita-executor/core/src/libexecutor/lru_cache.rs index 29250f6f4..2f6f8076c 100644 --- a/cita-executor/core/src/libexecutor/lru_cache.rs +++ b/cita-executor/core/src/libexecutor/lru_cache.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/libexecutor/mod.rs b/cita-executor/core/src/libexecutor/mod.rs index b4c98d771..4f6b43ab6 100644 --- a/cita-executor/core/src/libexecutor/mod.rs +++ b/cita-executor/core/src/libexecutor/mod.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/core/src/libexecutor/sys_config.rs b/cita-executor/core/src/libexecutor/sys_config.rs index c46ae685c..71d5e2f8f 100644 --- a/cita-executor/core/src/libexecutor/sys_config.rs +++ b/cita-executor/core/src/libexecutor/sys_config.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/src/backlogs.rs b/cita-executor/src/backlogs.rs index 3011af1e0..1247fd2fa 100644 --- a/cita-executor/src/backlogs.rs +++ b/cita-executor/src/backlogs.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-executor/src/postman.rs b/cita-executor/src/postman.rs index 608740057..e909714a9 100644 --- a/cita-executor/src/postman.rs +++ b/cita-executor/src/postman.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-jsonrpc/src/config.rs b/cita-jsonrpc/src/config.rs index 97f6fd878..7cceee0c4 100644 --- a/cita-jsonrpc/src/config.rs +++ b/cita-jsonrpc/src/config.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-jsonrpc/src/extractor.rs b/cita-jsonrpc/src/extractor.rs index fd3530aa0..4f4f88693 100644 --- a/cita-jsonrpc/src/extractor.rs +++ b/cita-jsonrpc/src/extractor.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-jsonrpc/src/fdlimit.rs b/cita-jsonrpc/src/fdlimit.rs index 3d13f6e57..f48307a3c 100644 --- a/cita-jsonrpc/src/fdlimit.rs +++ b/cita-jsonrpc/src/fdlimit.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-jsonrpc/src/helper.rs b/cita-jsonrpc/src/helper.rs index ba7782ba7..1eb7796ed 100644 --- a/cita-jsonrpc/src/helper.rs +++ b/cita-jsonrpc/src/helper.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-jsonrpc/src/http_header.rs b/cita-jsonrpc/src/http_header.rs index 0c5bef398..191856a8b 100644 --- a/cita-jsonrpc/src/http_header.rs +++ b/cita-jsonrpc/src/http_header.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/cita-jsonrpc/src/http_server.rs b/cita-jsonrpc/src/http_server.rs index b53a31228..878a87000 100644 --- a/cita-jsonrpc/src/http_server.rs +++ b/cita-jsonrpc/src/http_server.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -294,23 +294,20 @@ pub fn listener_from_socket_addr(addr: &SocketAddr) -> std::io::Result ws::Result<()> { trace!("Server got message '{}' post thread_pool deal task ", msg); - // let this = self.clone(); let tx = self.tx.clone(); let response = Arc::clone(&self.responses); let sender = self.sender.clone(); From be4a1f20f89a54689307d3d7d71ce65ae820213a Mon Sep 17 00:00:00 2001 From: leeyr Date: Thu, 20 Jun 2019 17:30:19 +0800 Subject: [PATCH 71/91] Fix amend help info and LATEST_VERSION. --- scripts/amend_system_contracts.py | 2 +- scripts/amend_system_contracts.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/amend_system_contracts.py b/scripts/amend_system_contracts.py index 433437c2e..5fb405c9e 100644 --- a/scripts/amend_system_contracts.py +++ b/scripts/amend_system_contracts.py @@ -13,7 +13,7 @@ import time from jsonrpcclient.http_client import HTTPClient -LATEST_VERSION = 1 +LATEST_VERSION = 2 AMEND_ADDR = '0xffffffffffffffffffffffffffffffffff010002' SYS_CONF = '0xffffffffffffffffffffffffffffffffff020000' NEW = '0xffffffffffffffffffffffffffffffffff020012' diff --git a/scripts/amend_system_contracts.sh b/scripts/amend_system_contracts.sh index 89a0402d3..6249ec3d4 100755 --- a/scripts/amend_system_contracts.sh +++ b/scripts/amend_system_contracts.sh @@ -11,7 +11,7 @@ fi if [ "$1" = "help" ]; then echo "Admin private key, chain id, version, url as the params. For example: \\ - ./env.sh scripts/amend_system_contracts.sh \\ + bin/cita scripts/amend_system_contracts.sh \\ 0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6 \\ 1 \\ 1 \\ From 48d5c27ea922a9a34d697333cb9ec71873e6875b Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Fri, 21 Jun 2019 14:45:03 +0800 Subject: [PATCH 72/91] chores: chain-executor-mock[skip travis] --- tests/chain-executor-mock/README.md | 3 --- .../chain-executor-mock/src/generate_block.rs | 13 +--------- tests/chain-executor-mock/src/main.rs | 26 +++++++------------ 3 files changed, 11 insertions(+), 31 deletions(-) delete mode 100644 tests/chain-executor-mock/README.md diff --git a/tests/chain-executor-mock/README.md b/tests/chain-executor-mock/README.md deleted file mode 100644 index eaeaec42d..000000000 --- a/tests/chain-executor-mock/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# 功能 - -Mock chain executor 的数据 diff --git a/tests/chain-executor-mock/src/generate_block.rs b/tests/chain-executor-mock/src/generate_block.rs index 2bbc720ca..d1e128d93 100644 --- a/tests/chain-executor-mock/src/generate_block.rs +++ b/tests/chain-executor-mock/src/generate_block.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -57,17 +57,6 @@ impl BuildBlock { From::from(stream.out().crypt_hash()) } - /// Generate a signed transaction - /// - /// ```no_run - /// message Transaction { - /// string to = 1; - /// string nonce = 2; - /// uint64 quota = 3; - /// uint64 valid_until_block = 4; - /// bytes data = 5; - /// } - /// ``` pub fn build_tx( to_address: &str, data: &str, diff --git a/tests/chain-executor-mock/src/main.rs b/tests/chain-executor-mock/src/main.rs index 9a31835f0..3ee46592e 100644 --- a/tests/chain-executor-mock/src/main.rs +++ b/tests/chain-executor-mock/src/main.rs @@ -18,7 +18,6 @@ extern crate cita_crypto as crypto; #[macro_use] extern crate libproto; - #[macro_use] extern crate cita_logger as logger; #[macro_use] @@ -36,12 +35,11 @@ use std::sync::{Arc, Mutex}; use std::time; use std::{fs, u8}; -use clap::App; - use crate::crypto::{CreateKey, KeyPair, PrivKey}; use crate::generate_block::BuildBlock; use cita_types::traits::LowerHex; use cita_types::{H256, U256}; +use clap::App; use libproto::router::{MsgType, RoutingKey, SubModules}; use libproto::Message; use libproto::TryFrom; @@ -58,7 +56,7 @@ fn main() { info!("CITA:Chain executor mock"); let matches = App::new("Chain executor mock") - .version("0.1") + .version("0.1.0") .author("Cryptape") .arg( clap::Arg::with_name("mock-data") @@ -93,10 +91,10 @@ fn main() { info!("AMQP_URL={}", amqp_url); let sys_time = Arc::new(Mutex::new(time::SystemTime::now())); - let privkey: PrivKey = { - let privkey_str = mock_data["privkey"].as_str().unwrap(); - PrivKey::from_str(privkey_str).unwrap() - }; + let privkey = mock_data["privkey"] + .as_str() + .and_then(|p| PrivKey::from_str(p).ok()) + .unwrap(); let mut mock_blocks: HashMap = HashMap::new(); for block in mock_data["blocks"].as_sequence_mut().unwrap() { let block_number = block["number"].as_u64().unwrap(); @@ -120,7 +118,7 @@ fn main() { let (key, body) = rx_sub.recv().unwrap(); info!("received: key={}", key); let mut msg = Message::try_from(&body).unwrap(); - // 接受 chain 发送的 authorities_list + // Receive authorities_list from chain if RoutingKey::from(&key) == routing_key!(Chain >> RichStatus) { let rich_status = msg.take_rich_status().unwrap(); let height = rich_status.height + 1; @@ -184,7 +182,6 @@ fn send_block( let quota = tx["quota"].as_u64().unwrap(); let nonce = tx["nonce"].as_u64().unwrap() as u32; let valid_until_block = tx["valid_until_block"].as_u64().unwrap(); - let sender = KeyPair::from_privkey(*privkey).unwrap().address(); info!( "sender={}, contract_address={}", @@ -206,7 +203,7 @@ fn send_block( }) .collect(); - // 构造block + // Build block let (send_data, _block) = BuildBlock::build_block_with_proof( &txs[..], pre_hash, @@ -214,11 +211,8 @@ fn send_block( privkey, GENESIS_TIMESTAMP + height * 3, ); - info!( - "===============send block ({} transactions)===============", - txs.len() - ); - (*sys_time.lock().unwrap()) = time::SystemTime::now(); + info!("send block ({} transactions)", txs.len()); + *sys_time.lock().unwrap() = time::SystemTime::now(); pub_sender .send(( routing_key!(Consensus >> BlockWithProof).into(), From 1247005b0a041fe8f66848a27fb5b8e2f546c0fe Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Thu, 13 Jun 2019 17:38:16 +0800 Subject: [PATCH 73/91] Use protocol version for system contracts. --- .../contracts/solc/permission_management.rs | 8 ++++++- .../src/contracts/solc/version_management.rs | 4 +++- scripts/config_tool/genesis | 2 +- scripts/contracts/contracts.yml | 2 ++ scripts/contracts/interaction | 2 +- .../contracts/src/system/VersionManager.sol | 21 +++++++++++++++++-- 6 files changed, 33 insertions(+), 6 deletions(-) diff --git a/cita-executor/core/src/contracts/solc/permission_management.rs b/cita-executor/core/src/contracts/solc/permission_management.rs index f82e8eda8..ad7d0da64 100644 --- a/cita-executor/core/src/contracts/solc/permission_management.rs +++ b/cita-executor/core/src/contracts/solc/permission_management.rs @@ -227,6 +227,7 @@ mod tests { const SET_STATE: &[u8] = &*b"setState(bool)"; const SET_QUOTA_PRICE: &[u8] = &*b"setQuotaPrice(uint256)"; const SET_VERSION: &[u8] = &*b"setVersion(uint32)"; + const SET_PROTOCOL_VERSION: &[u8] = &*b"setProtocolVersion(uint32)"; #[test] fn test_contains_resource() { @@ -503,11 +504,16 @@ mod tests { cont: H160::from_str(reserved_addresses::PRICE_MANAGEMENT).unwrap(), func: method_tools::encode_to_vec(SET_QUOTA_PRICE), }, - // version + // setVersion(Will deprecated) Resource { cont: H160::from_str(reserved_addresses::VERSION_MANAGEMENT).unwrap(), func: method_tools::encode_to_vec(SET_VERSION), }, + // setProtocolVersion + Resource { + cont: H160::from_str(reserved_addresses::VERSION_MANAGEMENT).unwrap(), + func: method_tools::encode_to_vec(SET_PROTOCOL_VERSION), + }, ]; expected_resources.sort(); diff --git a/cita-executor/core/src/contracts/solc/version_management.rs b/cita-executor/core/src/contracts/solc/version_management.rs index 147497003..09762b95f 100644 --- a/cita-executor/core/src/contracts/solc/version_management.rs +++ b/cita-executor/core/src/contracts/solc/version_management.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -30,6 +30,8 @@ use types::ids::BlockId; use types::reserved_addresses; lazy_static! { + // Will use `getProtocolVersion` at next version after `v0.25.0`. + // And the `getVersion` will be *Deprecated*. static ref VERSION_HASH: Vec = method_tools::encode_to_vec(b"getVersion()"); static ref CONTRACT_ADDRESS: Address = Address::from_str(reserved_addresses::VERSION_MANAGEMENT).unwrap(); diff --git a/scripts/config_tool/genesis b/scripts/config_tool/genesis index b5d21cad0..8e99bb0f9 160000 --- a/scripts/config_tool/genesis +++ b/scripts/config_tool/genesis @@ -1 +1 @@ -Subproject commit b5d21cad0435c777320f654a27d9d0af4cea25a2 +Subproject commit 8e99bb0f914e7be836c725caf6a68a165e940639 diff --git a/scripts/contracts/contracts.yml b/scripts/contracts/contracts.yml index 6f051b369..3092b8681 100644 --- a/scripts/contracts/contracts.yml +++ b/scripts/contracts/contracts.yml @@ -221,5 +221,7 @@ PermissionContracts: address: '0xffffffffffffffffffffffffffffffffff021028' contracts: - VersionManager + - VersionManager functions: - 'setVersion(uint32)' + - 'setProtocolVersion(uint32)' diff --git a/scripts/contracts/interaction b/scripts/contracts/interaction index 30049a2bc..0e9339061 160000 --- a/scripts/contracts/interaction +++ b/scripts/contracts/interaction @@ -1 +1 @@ -Subproject commit 30049a2bc0da74cae3a014adba3eb5fe77651662 +Subproject commit 0e93390618f988ba43de2a89264bf0055ae559a2 diff --git a/scripts/contracts/src/system/VersionManager.sol b/scripts/contracts/src/system/VersionManager.sol index 18dbcd4f2..182c9535b 100644 --- a/scripts/contracts/src/system/VersionManager.sol +++ b/scripts/contracts/src/system/VersionManager.sol @@ -23,7 +23,7 @@ contract VersionManager is IVersionManager, ReservedAddrPublic { version = _version; } - function setVersion(uint32 _version) + function setProtocolVersion(uint32 _version) public onlyAdmin { @@ -37,11 +37,28 @@ contract VersionManager is IVersionManager, ReservedAddrPublic { version = _version; } - function getVersion() + /// @notice Deprecated. Check the setProtocolVersion + function setVersion(uint32 _version) + public + onlyAdmin + { + setProtocolVersion(_version); + } + + function getProtocolVersion() public view returns (uint32) { return version; } + + /// @notice Deprecated. Check the getProtocolVersion + function getVersion() + public + view + returns (uint32) + { + return getProtocolVersion(); + } } From 0a8e72547642f7d6b5a7bcc2c67dbac1f0415b0f Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Tue, 18 Jun 2019 10:24:28 +0800 Subject: [PATCH 74/91] Add test of version manager. --- .travis.yml | 3 + scripts/contracts/tests/package.json | 1 + scripts/contracts/tests/test/config.js | 1 + scripts/contracts/tests/test/helpers/util.js | 1 + .../tests/test/helpers/version_manager.js | 25 +++++++++ .../tests/test/unit/version_manager.js | 56 +++++++++++++++++++ 6 files changed, 87 insertions(+) create mode 100644 scripts/contracts/tests/test/helpers/version_manager.js create mode 100644 scripts/contracts/tests/test/unit/version_manager.js diff --git a/.travis.yml b/.travis.yml index 7eb18fc6e..9bf9c0405 100644 --- a/.travis.yml +++ b/.travis.yml @@ -108,6 +108,9 @@ jobs: - <<: *stage-contract-test-sha3-secp256k1 name: Unit Uint8 script: npm run-script uint8 + - <<: *stage-contract-test-sha3-secp256k1 + name: Unit VersionManager + script: npm run-script unit_vm - <<: *stage-contract-test-sha3-secp256k1 name: Unit Node diff --git a/scripts/contracts/tests/package.json b/scripts/contracts/tests/package.json index 81100f454..deb3b54ac 100644 --- a/scripts/contracts/tests/package.json +++ b/scripts/contracts/tests/package.json @@ -28,6 +28,7 @@ "permission": "eslint test/integrate/permission.js && mocha test/integrate/permission.js -t 20s --exit", "auto_exec": "eslint test/integrate/auto_exec.js && mocha test/integrate/auto_exec.js -t 20s --exit", "lifetime": "eslint test/integrate/lifetime.js && mocha test/integrate/lifetime.js -t 20s --exit", + "unit_vm": "eslint test/unit/version_manager.js && mocha test/unit/version_manager.js -t 20s --exit", "lint": "eslint test", "lint-fix": "eslint --fix test" }, diff --git a/scripts/contracts/tests/test/config.js b/scripts/contracts/tests/test/config.js index 9e5f38f51..778368839 100644 --- a/scripts/contracts/tests/test/config.js +++ b/scripts/contracts/tests/test/config.js @@ -12,6 +12,7 @@ module.exports = { admin: '0xffffffffffffffffffffffffffffffffff02000c', roleAuth: '0xffffffffffffffffffffffffffffffffff02000d', autoExecAddr: '0xffffffffffffffffffffffffffffffffff020013', + versionManager: '0xffffffffffffffffffffffffffffffffff020011', }, localServer: 'http://127.0.0.1:1337', remoteServer: 'http://xx.xx.xx.xx:1337', diff --git a/scripts/contracts/tests/test/helpers/util.js b/scripts/contracts/tests/test/helpers/util.js index 29e23fded..f2cf24437 100644 --- a/scripts/contracts/tests/test/helpers/util.js +++ b/scripts/contracts/tests/test/helpers/util.js @@ -50,4 +50,5 @@ module.exports = { genContract, getTxReceipt, getBlockNumber, + getMetaData, }; diff --git a/scripts/contracts/tests/test/helpers/version_manager.js b/scripts/contracts/tests/test/helpers/version_manager.js new file mode 100644 index 000000000..c89b57d0b --- /dev/null +++ b/scripts/contracts/tests/test/helpers/version_manager.js @@ -0,0 +1,25 @@ +const fs = require('fs'); +const util = require('./util'); +const config = require('../config'); + +const { genContract, genTxParams } = util; + +const { superAdmin } = config; +const { versionManager } = config.contract; +const abi = JSON.parse(fs.readFileSync('../interaction/abi/VersionManager.abi')); +const contract = genContract(abi, versionManager); + +const getVersion = () => contract.methods.getVersion().call('pending'); + +const setProtocolVersion = async (account, _sender = superAdmin) => { + const param = await genTxParams(_sender); + return contract.methods.setProtocolVersion(account).send(param); +}; + +const getProtocolVersion = () => contract.methods.getProtocolVersion().call('pending'); + +module.exports = { + setProtocolVersion, + getProtocolVersion, + getVersion, +}; diff --git a/scripts/contracts/tests/test/unit/version_manager.js b/scripts/contracts/tests/test/unit/version_manager.js new file mode 100644 index 000000000..f7e52cef8 --- /dev/null +++ b/scripts/contracts/tests/test/unit/version_manager.js @@ -0,0 +1,56 @@ +const chai = require('chai'); +const util = require('../helpers/util'); +const versionManager = require('../helpers/version_manager'); + +const { expect } = chai; +const { + logger, getTxReceipt, getMetaData, +} = util; +const { + setProtocolVersion, getProtocolVersion, getVersion, +} = versionManager; + +// temp +let hash; +let version; + +describe('\n\ntest version manager\n\n', () => { + before('should have version', async () => { + const metaData = await getMetaData(); + ({ version } = metaData); + logger.debug('\nthe version of metaData is:\n', version); + }); + + it('should get the protocol version', async () => { + const res = await getProtocolVersion(); + logger.debug('\nthe version is:\n', res); + expect(+res).to.be.equal(version); + }); + + it('should send a tx: setProtocolVersion', async () => { + const res = await setProtocolVersion(version + 1); + logger.debug('\nSend tx ok:\n', JSON.stringify(res)); + expect(res.status).to.equal('OK'); + ({ hash } = res); + }); + + it('should get receipt: setProtocolVersion', async () => { + const res = await getTxReceipt(hash); + logger.debug('\nget receipt:\n', res); + expect(res.errorMessage).to.be.null; + version += 1; + }); + + it('should get the protocol version', async () => { + const res = await getProtocolVersion(); + logger.debug('\nthe version is:\n', res); + expect(+res).to.be.equal(version); + }); + + // old interface + it('should get the version', async () => { + const res = await getVersion(); + logger.debug('\nthe version is:\n', res); + expect(+res).to.be.equal(version); + }); +}); From 801ab87558fffe3b5b038d5683085a64a3facf16 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Wed, 12 Jun 2019 15:31:34 +0800 Subject: [PATCH 75/91] Update cita-common. --- Cargo.lock | 60 +++++++++++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cd149e50f..d739a4cd8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,7 +125,7 @@ dependencies = [ [[package]] name = "authority_manage" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -260,7 +260,7 @@ dependencies = [ [[package]] name = "blake2b" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -523,7 +523,7 @@ dependencies = [ [[package]] name = "cita-crypto" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-ed25519 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -534,7 +534,7 @@ dependencies = [ [[package]] name = "cita-crypto-trait" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", ] @@ -542,7 +542,7 @@ dependencies = [ [[package]] name = "cita-directories" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "uuid 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -550,7 +550,7 @@ dependencies = [ [[package]] name = "cita-ed25519" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -658,7 +658,7 @@ dependencies = [ [[package]] name = "cita-merklehash" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "hashable 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -718,7 +718,7 @@ dependencies = [ [[package]] name = "cita-secp256k1" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -735,7 +735,7 @@ dependencies = [ [[package]] name = "cita-sm2" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "cita-crypto-trait 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -749,7 +749,7 @@ dependencies = [ [[package]] name = "cita-types" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "ethereum-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "plain_hasher 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1155,7 +1155,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "db" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1225,7 +1225,7 @@ dependencies = [ [[package]] name = "engine" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1288,7 +1288,7 @@ dependencies = [ [[package]] name = "error" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" [[package]] name = "error-chain" @@ -1383,7 +1383,7 @@ dependencies = [ [[package]] name = "ethcore-bloom-journal" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "siphasher 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1689,7 +1689,7 @@ dependencies = [ [[package]] name = "hashable" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "blake2b 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1912,7 +1912,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-proto" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1929,7 +1929,7 @@ dependencies = [ [[package]] name = "jsonrpc-types" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1943,7 +1943,7 @@ dependencies = [ [[package]] name = "jsonrpc-types-internals" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "proc-macro2 0.4.20 (registry+https://github.com/rust-lang/crates.io-index)", "quote 0.6.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2025,7 +2025,7 @@ dependencies = [ [[package]] name = "libproto" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2531,7 +2531,7 @@ dependencies = [ [[package]] name = "panic_hook" version = "0.0.1" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "backtrace 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2658,7 +2658,7 @@ dependencies = [ [[package]] name = "proof" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2681,7 +2681,7 @@ dependencies = [ [[package]] name = "pubsub" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "pubsub_kafka 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -2692,7 +2692,7 @@ dependencies = [ [[package]] name = "pubsub_kafka" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2704,7 +2704,7 @@ dependencies = [ [[package]] name = "pubsub_rabbitmq" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "amqp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2713,7 +2713,7 @@ dependencies = [ [[package]] name = "pubsub_zeromq" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "cita-logger 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-channel 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3039,7 +3039,7 @@ dependencies = [ [[package]] name = "rlp" version = "0.2.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -3060,7 +3060,7 @@ dependencies = [ [[package]] name = "rlp_derive" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -3276,7 +3276,7 @@ dependencies = [ [[package]] name = "snappy" version = "0.1.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3906,7 +3906,7 @@ dependencies = [ [[package]] name = "tx_pool" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "cita-crypto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -4059,7 +4059,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "util" version = "0.6.0" -source = "git+https://github.com/cryptape/cita-common.git?branch=develop#adc257f532adc0e03d77135f34bc4a924f3c0bd5" +source = "git+https://github.com/cryptape/cita-common.git?branch=develop#b948764c71c656943506317505868bbde95bc3f3" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "cita-types 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", From adbab38063b5318a8a910874339b2c3b7b239532 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Fri, 21 Jun 2019 16:13:57 +0800 Subject: [PATCH 76/91] Update core-executor to 2018 edition. --- cita-executor/core/Cargo.toml | 1 + cita-executor/core/src/account_db.rs | 2 +- cita-executor/core/src/authentication.rs | 10 ++-- cita-executor/core/src/builtin.rs | 4 +- .../core/src/contracts/grpc/contract.rs | 8 ++-- .../core/src/contracts/grpc/contract_state.rs | 2 +- .../core/src/contracts/grpc/grpc_vm.rs | 22 ++++----- .../src/contracts/grpc/grpc_vm_adapter.rs | 6 +-- .../src/contracts/grpc/service_registry.rs | 2 +- .../core/src/contracts/grpc/storage.rs | 6 +-- .../src/contracts/native/crosschain_verify.rs | 6 ++- .../core/src/contracts/native/factory.rs | 2 +- .../core/src/contracts/native/storage.rs | 4 +- .../core/src/contracts/solc/admin.rs | 12 ++--- .../core/src/contracts/solc/chain_manager.rs | 4 +- .../src/contracts/solc/emergency_brake.rs | 12 ++--- cita-executor/core/src/contracts/solc/mod.rs | 8 ++-- .../core/src/contracts/solc/node_manager.rs | 10 ++-- .../contracts/solc/permission_management.rs | 16 +++---- .../core/src/contracts/solc/price_manager.rs | 12 ++--- .../core/src/contracts/solc/quota_manager.rs | 12 ++--- .../core/src/contracts/solc/sys_config.rs | 16 +++---- .../src/contracts/solc/user_management.rs | 14 +++--- .../src/contracts/solc/version_management.rs | 12 ++--- .../core/src/contracts/tools/decode.rs | 2 +- cita-executor/core/src/engines/mod.rs | 8 ++-- cita-executor/core/src/engines/null_engine.rs | 4 +- cita-executor/core/src/error.rs | 10 ++-- cita-executor/core/src/executed.rs | 10 ++-- cita-executor/core/src/executive.rs | 48 +++++++++---------- cita-executor/core/src/externalities.rs | 18 +++---- cita-executor/core/src/factory.rs | 6 +-- cita-executor/core/src/lib.rs | 6 +-- .../core/src/libexecutor/auto_exec.rs | 22 ++++----- cita-executor/core/src/libexecutor/block.rs | 24 +++++----- cita-executor/core/src/libexecutor/command.rs | 24 +++++----- .../core/src/libexecutor/executor.rs | 44 ++++++++--------- cita-executor/core/src/libexecutor/fsm.rs | 14 +++--- cita-executor/core/src/libexecutor/genesis.rs | 16 +++---- cita-executor/core/src/libexecutor/mod.rs | 2 +- .../core/src/libexecutor/sys_config.rs | 8 ++-- cita-executor/core/src/pod_account.rs | 6 +-- cita-executor/core/src/snapshot/account.rs | 10 ++-- cita-executor/core/src/snapshot/error.rs | 4 +- cita-executor/core/src/snapshot/io.rs | 2 +- cita-executor/core/src/snapshot/mod.rs | 40 +++++++++------- cita-executor/core/src/snapshot/service.rs | 10 ++-- cita-executor/core/src/spec/builtin.rs | 2 +- cita-executor/core/src/state/account.rs | 10 ++-- cita-executor/core/src/state/backend.rs | 4 +- cita-executor/core/src/state/mod.rs | 30 ++++++------ cita-executor/core/src/state_db.rs | 10 ++-- cita-executor/core/src/substate.rs | 4 +- .../core/src/tests/amend_data_test.rs | 18 +++---- cita-executor/core/src/tests/grpc_test.rs | 14 +++--- cita-executor/core/src/tests/helpers.rs | 26 +++++----- cita-executor/core/src/trace/config.rs | 2 +- cita-executor/core/src/trace/db.rs | 34 ++++++------- .../core/src/trace/executive_tracer.rs | 8 ++-- cita-executor/core/src/trace/import.rs | 4 +- cita-executor/core/src/trace/mod.rs | 4 +- cita-executor/core/src/trace/noop_tracer.rs | 4 +- cita-executor/core/src/trace/types/filter.rs | 14 +++--- cita-executor/core/src/trace/types/flat.rs | 4 +- .../core/src/trace/types/localized.rs | 2 +- cita-executor/core/src/trace/types/trace.rs | 2 +- 66 files changed, 373 insertions(+), 364 deletions(-) diff --git a/cita-executor/core/Cargo.toml b/cita-executor/core/Cargo.toml index 8ce0cf340..dd7a14365 100644 --- a/cita-executor/core/Cargo.toml +++ b/cita-executor/core/Cargo.toml @@ -2,6 +2,7 @@ name = "core-executor" version = "0.1.0" authors = ["Parity Technologies ", "Cryptape Technologies "] +editon = "2018" [dependencies] cita-logger = "0.1.0" diff --git a/cita-executor/core/src/account_db.rs b/cita-executor/core/src/account_db.rs index a71393767..fc96650a5 100644 --- a/cita-executor/core/src/account_db.rs +++ b/cita-executor/core/src/account_db.rs @@ -16,7 +16,7 @@ //! DB backend wrapper for Account trie -use cita_db::{DBValue, HashDB}; +use crate::cita_db::{DBValue, HashDB}; use cita_types::{Address, H256}; use hashable::{Hashable, HASH_NULL_RLP}; use rlp::NULL_RLP; diff --git a/cita-executor/core/src/authentication.rs b/cita-executor/core/src/authentication.rs index 42250b184..0fe94543f 100644 --- a/cita-executor/core/src/authentication.rs +++ b/cita-executor/core/src/authentication.rs @@ -15,14 +15,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::contracts::solc::{permission_management::contains_resource, Resource}; +use crate::executed::ExecutionError; +use crate::libexecutor::sys_config::CheckOptions; +use crate::types::reserved_addresses; +use crate::types::transaction::{Action, SignedTransaction}; use cita_types::{Address, H160}; -use contracts::solc::{permission_management::contains_resource, Resource}; -use executed::ExecutionError; -use libexecutor::sys_config::CheckOptions; use std::collections::HashMap; use std::str::FromStr; -use types::reserved_addresses; -use types::transaction::{Action, SignedTransaction}; /// Check the sender's permission #[allow(unknown_lints, clippy::implicit_hasher)] // TODO clippy diff --git a/cita-executor/core/src/builtin.rs b/cita-executor/core/src/builtin.rs index 22c74cf5a..e03081a9d 100644 --- a/cita-executor/core/src/builtin.rs +++ b/cita-executor/core/src/builtin.rs @@ -14,6 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use crate::spec; use cita_crypto_trait::Sign; use cita_ed25519::{Message as ED_Message, Signature as ED_Signature}; use cita_secp256k1::Signature; @@ -22,7 +23,6 @@ use crypto::digest::Digest; use crypto::ripemd160::Ripemd160 as Ripemd160Digest; use crypto::sha2::Sha256 as Sha256Digest; use hashable::Hashable; -use spec; use std::cmp::min; use util::BytesRef; @@ -206,10 +206,10 @@ mod tests { extern crate rustc_serialize; use super::{ethereum_builtin, Builtin, Linear, Pricer}; + use crate::spec; use cita_crypto_trait::{CreateKey, Sign}; use cita_ed25519::{pubkey_to_address as ED_pubkey_to_address, KeyPair, Signature}; use cita_types::{H256, U256}; - use spec; use util::BytesRef; #[test] diff --git a/cita-executor/core/src/contracts/grpc/contract.rs b/cita-executor/core/src/contracts/grpc/contract.rs index f49daf6b0..b741fcad3 100644 --- a/cita-executor/core/src/contracts/grpc/contract.rs +++ b/cita-executor/core/src/contracts/grpc/contract.rs @@ -15,19 +15,19 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::contracts::grpc::{contract_state::ConnectInfo, grpc_vm::CallEvmImpl}; +use crate::state::backend::Backend as StateBackend; +use crate::state::State; +use crate::types::reserved_addresses; use cita_types::traits::LowerHex; use cita_types::Address; -use contracts::grpc::{contract_state::ConnectInfo, grpc_vm::CallEvmImpl}; use evm::action_params::ActionParams; use evm::env_info::EnvInfo; use grpc::Result as GrpcResult; use libproto::citacode::{ ActionParams as ProtoActionParams, EnvInfo as ProtoEnvInfo, InvokeRequest, InvokeResponse, }; -use state::backend::Backend as StateBackend; -use state::State; use std::str::FromStr; -use types::reserved_addresses; lazy_static! { static ref CONTRACT_CREATION_ADDRESS: Address = diff --git a/cita-executor/core/src/contracts/grpc/contract_state.rs b/cita-executor/core/src/contracts/grpc/contract_state.rs index 6c01a6596..65efa3e2b 100644 --- a/cita-executor/core/src/contracts/grpc/contract_state.rs +++ b/cita-executor/core/src/contracts/grpc/contract_state.rs @@ -15,8 +15,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::db::Key; use cita_types::{Address, H160}; -use db::Key; use rlp::*; use std::str::FromStr; use util::*; diff --git a/cita-executor/core/src/contracts/grpc/grpc_vm.rs b/cita-executor/core/src/contracts/grpc/grpc_vm.rs index c1d770401..495281d9e 100644 --- a/cita-executor/core/src/contracts/grpc/grpc_vm.rs +++ b/cita-executor/core/src/contracts/grpc/grpc_vm.rs @@ -15,28 +15,28 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use authentication::check_permission; +use crate::authentication::check_permission; +use crate::db::{self as db, Writable}; +use crate::error::{Error, ExecutionError}; +use crate::libexecutor::sys_config::BlockSysConfig; use cita_types::traits::LowerHex; use cita_types::{Address, H256, U256}; -use db::{self as db, Writable}; -use error::{Error, ExecutionError}; use grpc::Result as GrpcResult; -use libexecutor::sys_config::BlockSysConfig; -use contracts::grpc::{ +use crate::contracts::grpc::{ contract_state::{ConnectInfo, ContractState}, service_registry, }; -use libexecutor::executor::Executor; +use crate::libexecutor::executor::Executor; +use crate::log_entry::LogEntry; +use crate::receipt::Receipt; +use crate::state::backend::Backend as StateBackend; +use crate::state::State; +use crate::types::transaction::{Action, SignedTransaction}; use libproto::citacode::{ActionParams, EnvInfo, InvokeRequest, InvokeResponse}; use libproto::citacode_grpc::{CitacodeService, CitacodeServiceClient}; -use log_entry::LogEntry; -use receipt::Receipt; -use state::backend::Backend as StateBackend; -use state::State; use std::error::Error as StdError; use std::str::FromStr; -use types::transaction::{Action, SignedTransaction}; use util::Bytes; pub fn extract_logs_from_response(sender: Address, response: &InvokeResponse) -> Vec { diff --git a/cita-executor/core/src/contracts/grpc/grpc_vm_adapter.rs b/cita-executor/core/src/contracts/grpc/grpc_vm_adapter.rs index 4586398ce..7650cee2f 100644 --- a/cita-executor/core/src/contracts/grpc/grpc_vm_adapter.rs +++ b/cita-executor/core/src/contracts/grpc/grpc_vm_adapter.rs @@ -15,17 +15,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::contracts::grpc::service_registry; +use crate::libexecutor::command; +use crate::types::ids::BlockId; use cita_types::{Address, H256, U256}; -use contracts::grpc::service_registry; use crossbeam_channel::{Receiver, Sender}; use grpc::Server; -use libexecutor::command; use libproto::executor::{LoadRequest, LoadResponse, RegisterRequest, RegisterResponse}; use libproto::executor_grpc::{ExecutorService, ExecutorServiceServer}; use std::str::FromStr; use std::thread; use std::time::Duration; -use types::ids::BlockId; pub struct ExecutorServiceImpl { command_req_sender: Sender, diff --git a/cita-executor/core/src/contracts/grpc/service_registry.rs b/cita-executor/core/src/contracts/grpc/service_registry.rs index eeb2a0061..118ef1ac1 100644 --- a/cita-executor/core/src/contracts/grpc/service_registry.rs +++ b/cita-executor/core/src/contracts/grpc/service_registry.rs @@ -15,9 +15,9 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::contracts::grpc::contract_state::ContractState; use cita_types::traits::LowerHex; use cita_types::Address; -use contracts::grpc::contract_state::ContractState; use std::collections::HashMap; use std::sync::Mutex; use util::RwLock; diff --git a/cita-executor/core/src/contracts/grpc/storage.rs b/cita-executor/core/src/contracts/grpc/storage.rs index fdc7abae1..d567d67d4 100644 --- a/cita-executor/core/src/contracts/grpc/storage.rs +++ b/cita-executor/core/src/contracts/grpc/storage.rs @@ -15,10 +15,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use cita_db::trie; +use crate::cita_db::trie; +use crate::state::backend::Backend; +use crate::state::State; use cita_types::{Address, H256, U256}; -use state::backend::Backend; -use state::State; pub fn set_storage( state: &mut State, diff --git a/cita-executor/core/src/contracts/native/crosschain_verify.rs b/cita-executor/core/src/contracts/native/crosschain_verify.rs index 191294ff1..40e131c6d 100644 --- a/cita-executor/core/src/contracts/native/crosschain_verify.rs +++ b/cita-executor/core/src/contracts/native/crosschain_verify.rs @@ -15,15 +15,17 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::contracts::{ + native::factory::Contract, solc::ChainManagement, tools::method as method_tools, +}; +use crate::state::StateProof; use cita_types::{Address, H256, U256}; -use contracts::{native::factory::Contract, solc::ChainManagement, tools::method as method_tools}; use core::header::Header; use core::libchain::chain::TxProof; use ethabi; use evm::action_params::ActionParams; use evm::storage::Map; use evm::{Error, Ext, GasLeft, ReturnData}; -use state::StateProof; lazy_static! { static ref VERIFY_TRANSACTION_FUNC: u32 = diff --git a/cita-executor/core/src/contracts/native/factory.rs b/cita-executor/core/src/contracts/native/factory.rs index 5219fe297..e41e5abb0 100644 --- a/cita-executor/core/src/contracts/native/factory.rs +++ b/cita-executor/core/src/contracts/native/factory.rs @@ -15,12 +15,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::types::reserved_addresses; use cita_types::Address; use evm::action_params::ActionParams; use evm::{self, Ext, GasLeft}; use std::collections::HashMap; use std::str::FromStr; -use types::reserved_addresses; //////////////////////////////////////////////////////////////////////////////// pub type Signature = u32; diff --git a/cita-executor/core/src/contracts/native/storage.rs b/cita-executor/core/src/contracts/native/storage.rs index 60597c2ac..0147224c4 100644 --- a/cita-executor/core/src/contracts/native/storage.rs +++ b/cita-executor/core/src/contracts/native/storage.rs @@ -18,14 +18,14 @@ use self::bincode::internal::serialize_into; use self::bincode::Infinite; use super::factory::{Contract, Factory}; +use crate::contracts::tools::method as method_tools; +use crate::types::reserved_addresses; use bincode; use cita_types::{Address, H256, U256}; -use contracts::tools::method as method_tools; use evm; use evm::fake_tests::FakeExt; use std::io::Write; use std::str::FromStr; -use types::reserved_addresses; use byteorder::BigEndian; use evm::action_params::ActionParams; diff --git a/cita-executor/core/src/contracts/solc/admin.rs b/cita-executor/core/src/contracts/solc/admin.rs index 2344e8c07..49b1348ec 100644 --- a/cita-executor/core/src/contracts/solc/admin.rs +++ b/cita-executor/core/src/contracts/solc/admin.rs @@ -18,12 +18,12 @@ //! Get Admin Info use super::ContractCallExt; +use crate::contracts::tools::{decode as decode_tools, method as method_tools}; +use crate::libexecutor::executor::Executor; +use crate::types::ids::BlockId; +use crate::types::reserved_addresses; use cita_types::Address; -use contracts::tools::{decode as decode_tools, method as method_tools}; -use libexecutor::executor::Executor; use std::str::FromStr; -use types::ids::BlockId; -use types::reserved_addresses; lazy_static! { static ref GET_ADMIN: Vec = method_tools::encode_to_vec(b"admin()"); @@ -51,9 +51,9 @@ impl<'a> Admin<'a> { #[cfg(test)] mod tests { use super::Admin; + use crate::tests::helpers::init_executor; + use crate::types::ids::BlockId; use cita_types::Address; - use tests::helpers::init_executor; - use types::ids::BlockId; #[test] fn test_admin() { diff --git a/cita-executor/core/src/contracts/solc/chain_manager.rs b/cita-executor/core/src/contracts/solc/chain_manager.rs index fe5fefb35..37d75ee8b 100644 --- a/cita-executor/core/src/contracts/solc/chain_manager.rs +++ b/cita-executor/core/src/contracts/solc/chain_manager.rs @@ -17,12 +17,12 @@ //! Chain manager. +use crate::contracts::tools::{decode as decode_tools, method as method_tools}; +use crate::types::reserved_addresses; use cita_types::{Address, H160, H256, U256}; -use contracts::tools::{decode as decode_tools, method as method_tools}; use evm::call_type::CallType; use evm::ext::{Ext, MessageCallResult}; use std::str::FromStr; -use types::reserved_addresses; const CHAIN_ID: &[u8] = &*b"getChainId()"; const AUTHORITIES: &[u8] = &*b"getAuthorities(uint256)"; diff --git a/cita-executor/core/src/contracts/solc/emergency_brake.rs b/cita-executor/core/src/contracts/solc/emergency_brake.rs index f890e2775..777f48a58 100644 --- a/cita-executor/core/src/contracts/solc/emergency_brake.rs +++ b/cita-executor/core/src/contracts/solc/emergency_brake.rs @@ -20,13 +20,13 @@ use std::str::FromStr; use super::ContractCallExt; -use contracts::tools::method as method_tools; -use libexecutor::executor::Executor; +use crate::contracts::tools::method as method_tools; +use crate::libexecutor::executor::Executor; +use crate::types::ids::BlockId; +use crate::types::reserved_addresses; use cita_types::Address; use ethabi::{decode, ParamType}; -use types::ids::BlockId; -use types::reserved_addresses; lazy_static! { static ref STATE_HASH: Vec = method_tools::encode_to_vec(b"state()"); @@ -63,8 +63,8 @@ impl<'a> EmergencyBrake<'a> { #[cfg(test)] mod tests { use super::EmergencyBrake; - use tests::helpers::init_executor; - use types::ids::BlockId; + use crate::tests::helpers::init_executor; + use crate::types::ids::BlockId; #[test] fn test_state() { diff --git a/cita-executor/core/src/contracts/solc/mod.rs b/cita-executor/core/src/contracts/solc/mod.rs index 07a9468d7..ccbdfc996 100644 --- a/cita-executor/core/src/contracts/solc/mod.rs +++ b/cita-executor/core/src/contracts/solc/mod.rs @@ -38,11 +38,11 @@ pub use self::sys_config::SysConfig; pub use self::user_management::UserManagement; pub use self::version_management::VersionManager; +use crate::libexecutor::call_request::CallRequest; +use crate::libexecutor::command::Commander; +use crate::libexecutor::executor::Executor; +use crate::types::ids::BlockId; use cita_types::Address; -use libexecutor::call_request::CallRequest; -use libexecutor::command::Commander; -use libexecutor::executor::Executor; -use types::ids::BlockId; use util::Bytes; /// Extend `Executor` with some methods related to contract diff --git a/cita-executor/core/src/contracts/solc/node_manager.rs b/cita-executor/core/src/contracts/solc/node_manager.rs index b093e87d7..fb24b0340 100644 --- a/cita-executor/core/src/contracts/solc/node_manager.rs +++ b/cita-executor/core/src/contracts/solc/node_manager.rs @@ -18,16 +18,16 @@ //! Node manager. use super::ContractCallExt; +use crate::contracts::tools::{decode as decode_tools, method as method_tools}; +use crate::libexecutor::economical_model::EconomicalModel; +use crate::libexecutor::executor::Executor; +use crate::types::ids::BlockId; +use crate::types::reserved_addresses; use cita_types::{Address, H160}; -use contracts::tools::{decode as decode_tools, method as method_tools}; use largest_remainder_method::apportion; -use libexecutor::economical_model::EconomicalModel; -use libexecutor::executor::Executor; use rand::{Rng, SeedableRng, StdRng}; use std::iter; use std::str::FromStr; -use types::ids::BlockId; -use types::reserved_addresses; const LIST_NODE: &[u8] = &*b"listNode()"; const LIST_STAKE: &[u8] = &*b"listStake()"; diff --git a/cita-executor/core/src/contracts/solc/permission_management.rs b/cita-executor/core/src/contracts/solc/permission_management.rs index f82e8eda8..a34724c0c 100644 --- a/cita-executor/core/src/contracts/solc/permission_management.rs +++ b/cita-executor/core/src/contracts/solc/permission_management.rs @@ -17,13 +17,13 @@ //! Permission management. use super::ContractCallExt; +use crate::contracts::tools::{decode as decode_tools, method as method_tools}; +use crate::libexecutor::executor::Executor; +use crate::types::ids::BlockId; +use crate::types::reserved_addresses; use cita_types::{Address, H160, H256}; -use contracts::tools::{decode as decode_tools, method as method_tools}; -use libexecutor::executor::Executor; use std::collections::HashMap; use std::str::FromStr; -use types::ids::BlockId; -use types::reserved_addresses; const ALLACCOUNTS: &[u8] = &*b"queryAllAccounts()"; const PERMISSIONS: &[u8] = &*b"queryPermissions(address)"; @@ -186,13 +186,13 @@ mod tests { use super::contains_resource; use super::{PermissionManagement, Resource, DEFAULT_SUPER_ADEMIN}; + use crate::contracts::tools::method as method_tools; + use crate::tests::helpers::init_executor; + use crate::types::ids::BlockId; + use crate::types::reserved_addresses; use cita_types::{Address, H160, H256}; - use contracts::tools::method as method_tools; use std::collections::HashMap; use std::str::FromStr; - use tests::helpers::init_executor; - use types::ids::BlockId; - use types::reserved_addresses; const NEW_PERMISSION: &[u8] = &*b"newPermission(bytes32,address[],bytes4[])"; const DELETE_PERMISSION: &[u8] = &*b"deletePermission(address)"; diff --git a/cita-executor/core/src/contracts/solc/price_manager.rs b/cita-executor/core/src/contracts/solc/price_manager.rs index c9953cf24..8b8a6917c 100644 --- a/cita-executor/core/src/contracts/solc/price_manager.rs +++ b/cita-executor/core/src/contracts/solc/price_manager.rs @@ -18,12 +18,12 @@ //! Quota Price Management use super::ContractCallExt; +use crate::contracts::tools::{decode as decode_tools, method as method_tools}; +use crate::libexecutor::executor::Executor; +use crate::types::ids::BlockId; +use crate::types::reserved_addresses; use cita_types::{Address, U256}; -use contracts::tools::{decode as decode_tools, method as method_tools}; -use libexecutor::executor::Executor; use std::str::FromStr; -use types::ids::BlockId; -use types::reserved_addresses; lazy_static! { static ref GET_QUOTA_PRICE: Vec = method_tools::encode_to_vec(b"getQuotaPrice()"); @@ -63,9 +63,9 @@ impl<'a> PriceManagement<'a> { #[cfg(test)] mod tests { use super::PriceManagement; + use crate::tests::helpers::init_executor; + use crate::types::ids::BlockId; use cita_types::U256; - use tests::helpers::init_executor; - use types::ids::BlockId; #[test] fn test_state() { diff --git a/cita-executor/core/src/contracts/solc/quota_manager.rs b/cita-executor/core/src/contracts/solc/quota_manager.rs index 04e25f987..f97ca05f4 100644 --- a/cita-executor/core/src/contracts/solc/quota_manager.rs +++ b/cita-executor/core/src/contracts/solc/quota_manager.rs @@ -18,15 +18,15 @@ //! Quota manager. use super::ContractCallExt; +use crate::contracts::tools::{decode as decode_tools, method as method_tools}; +use crate::libexecutor::executor::Executor; +use crate::types::ids::BlockId; +use crate::types::reserved_addresses; use cita_types::traits::LowerHex; use cita_types::{Address, H160}; -use contracts::tools::{decode as decode_tools, method as method_tools}; -use libexecutor::executor::Executor; use libproto::blockchain::AccountGasLimit as ProtoAccountQuotaLimit; use std::collections::HashMap; use std::str::FromStr; -use types::ids::BlockId; -use types::reserved_addresses; const QUOTAS: &[u8] = &*b"getQuotas()"; const ACCOUNTS: &[u8] = &*b"getAccounts()"; @@ -198,10 +198,10 @@ mod tests { extern crate cita_logger as logger; use super::{QuotaManager, AQL_VALUE, AUTO_EXEC_QL_VALUE, BQL_VALUE}; + use crate::tests::helpers::init_executor; + use crate::types::ids::BlockId; use cita_types::H160; use std::str::FromStr; - use tests::helpers::init_executor; - use types::ids::BlockId; #[test] fn test_users() { diff --git a/cita-executor/core/src/contracts/solc/sys_config.rs b/cita-executor/core/src/contracts/solc/sys_config.rs index 4d8661241..a30fd8a16 100644 --- a/cita-executor/core/src/contracts/solc/sys_config.rs +++ b/cita-executor/core/src/contracts/solc/sys_config.rs @@ -20,15 +20,15 @@ use std::str::FromStr; use super::ContractCallExt; +use crate::contracts::solc::version_management::VersionManager; +use crate::contracts::tools::method as method_tools; +use crate::libexecutor::economical_model::EconomicalModel; +use crate::libexecutor::executor::Executor; +use crate::types::ids::BlockId; +use crate::types::reserved_addresses; use cita_types::{Address, H256, U256}; -use contracts::solc::version_management::VersionManager; -use contracts::tools::method as method_tools; use ethabi::{decode, ParamType, Token}; -use libexecutor::economical_model::EconomicalModel; -use libexecutor::executor::Executor; use num::FromPrimitive; -use types::ids::BlockId; -use types::reserved_addresses; lazy_static! { static ref DELAY_BLOCK_NUMBER: Vec = method_tools::encode_to_vec(b"getDelayBlockNumber()"); @@ -351,10 +351,10 @@ mod tests { extern crate cita_logger as logger; use super::{EconomicalModel, SysConfig, TokenInfo}; + use crate::tests::helpers::init_executor; + use crate::types::ids::BlockId; use cita_types::Address; use std::str::FromStr; - use tests::helpers::init_executor; - use types::ids::BlockId; #[test] fn test_delay_block_number() { diff --git a/cita-executor/core/src/contracts/solc/user_management.rs b/cita-executor/core/src/contracts/solc/user_management.rs index 2ddad6669..783616283 100644 --- a/cita-executor/core/src/contracts/solc/user_management.rs +++ b/cita-executor/core/src/contracts/solc/user_management.rs @@ -17,13 +17,13 @@ //! User management. use super::ContractCallExt; +use crate::contracts::tools::{decode as decode_tools, method as method_tools}; +use crate::libexecutor::executor::Executor; +use crate::types::ids::BlockId; +use crate::types::reserved_addresses; use cita_types::{Address, H160}; -use contracts::tools::{decode as decode_tools, method as method_tools}; -use libexecutor::executor::Executor; use std::collections::HashMap; use std::str::FromStr; -use types::ids::BlockId; -use types::reserved_addresses; const ALLGROUPS: &[u8] = &*b"queryGroups()"; const ACCOUNTS: &[u8] = &*b"queryAccounts()"; @@ -99,11 +99,11 @@ mod tests { extern crate cita_logger as logger; use super::UserManagement; + use crate::tests::helpers::init_executor; + use crate::types::ids::BlockId; + use crate::types::reserved_addresses; use cita_types::{Address, H160}; use std::str::FromStr; - use tests::helpers::init_executor; - use types::ids::BlockId; - use types::reserved_addresses; #[test] fn test_all_groups() { diff --git a/cita-executor/core/src/contracts/solc/version_management.rs b/cita-executor/core/src/contracts/solc/version_management.rs index 147497003..39390400e 100644 --- a/cita-executor/core/src/contracts/solc/version_management.rs +++ b/cita-executor/core/src/contracts/solc/version_management.rs @@ -20,14 +20,14 @@ use std::str::FromStr; use super::ContractCallExt; -use contracts::tools::method as method_tools; -use libexecutor::executor::Executor; +use crate::contracts::tools::method as method_tools; +use crate::libexecutor::executor::Executor; +use crate::types::ids::BlockId; +use crate::types::reserved_addresses; use cita_types::Address; use cita_types::H256; use ethabi::{decode, ParamType}; -use types::ids::BlockId; -use types::reserved_addresses; lazy_static! { static ref VERSION_HASH: Vec = method_tools::encode_to_vec(b"getVersion()"); @@ -70,8 +70,8 @@ impl<'a> VersionManager<'a> { #[cfg(test)] mod tests { use super::VersionManager; - use tests::helpers::init_executor; - use types::ids::BlockId; + use crate::tests::helpers::init_executor; + use crate::types::ids::BlockId; #[test] fn test_state() { diff --git a/cita-executor/core/src/contracts/tools/decode.rs b/cita-executor/core/src/contracts/tools/decode.rs index 0b203333e..f08fe9213 100644 --- a/cita-executor/core/src/contracts/tools/decode.rs +++ b/cita-executor/core/src/contracts/tools/decode.rs @@ -15,8 +15,8 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::contracts::solc::permission_management::Resource; use cita_types::{Address, H256, U256}; -use contracts::solc::permission_management::Resource; use ethabi::{decode, ParamType, Token}; /// Parse solidity return data `address[]` to rust `Vec
` diff --git a/cita-executor/core/src/engines/mod.rs b/cita-executor/core/src/engines/mod.rs index 2c8f8b699..0303331d9 100644 --- a/cita-executor/core/src/engines/mod.rs +++ b/cita-executor/core/src/engines/mod.rs @@ -15,14 +15,14 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use builtin::Builtin; +use crate::builtin::Builtin; +use crate::header::BlockNumber; +use crate::spec::Builtin as SpecBuiltin; +use crate::types::reserved_addresses; use cita_types::Address; -use header::BlockNumber; use serde_json; -use spec::Builtin as SpecBuiltin; use std::collections::BTreeMap; use std::str::FromStr; -use types::reserved_addresses; mod null_engine; pub use self::null_engine::NullEngine; diff --git a/cita-executor/core/src/engines/null_engine.rs b/cita-executor/core/src/engines/null_engine.rs index 28a4103b1..ce46b3581 100644 --- a/cita-executor/core/src/engines/null_engine.rs +++ b/cita-executor/core/src/engines/null_engine.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use builtin::Builtin; +use crate::builtin::Builtin; +use crate::engines::Engine; use cita_types::Address; -use engines::Engine; use std::collections::BTreeMap; /// An engine which does not provide any consensus mechanism and does not seal blocks. diff --git a/cita-executor/core/src/error.rs b/cita-executor/core/src/error.rs index 24b09c40b..370811db3 100644 --- a/cita-executor/core/src/error.rs +++ b/cita-executor/core/src/error.rs @@ -16,15 +16,15 @@ //! General error types for use in ethcore. -use basic_types::LogBloom; +use crate::basic_types::LogBloom; use cita_ed25519::Error as EthkeyError; use cita_types::{H256, U256}; -use cita_db::TrieError; -pub use executed::{CallError, ExecutionError}; -use header::BlockNumber; +use crate::cita_db::TrieError; +pub use crate::executed::{CallError, ExecutionError}; +use crate::header::BlockNumber; +use crate::snapshot::Error as SnapshotError; use snappy; -use snapshot::Error as SnapshotError; use std::fmt; use util::*; diff --git a/cita-executor/core/src/executed.rs b/cita-executor/core/src/executed.rs index 831284759..f32d95c03 100644 --- a/cita-executor/core/src/executed.rs +++ b/cita-executor/core/src/executed.rs @@ -16,14 +16,14 @@ //! Transaction execution format module. -use cita_db::trie; +use crate::cita_db::trie; +use crate::receipt::ReceiptError; +use crate::trace::{FlatTrace, VMTrace}; +use crate::types::log_entry::LogEntry; +use crate::types::state_diff::StateDiff; use cita_types::{Address, U256, U512}; use evm; -use receipt::ReceiptError; use std::fmt; -use trace::{FlatTrace, VMTrace}; -use types::log_entry::LogEntry; -use types::state_diff::StateDiff; use util::Bytes; /// Transaction execution receipt. diff --git a/cita-executor/core/src/executive.rs b/cita-executor/core/src/executive.rs index 312933503..63e7d942e 100644 --- a/cita-executor/core/src/executive.rs +++ b/cita-executor/core/src/executive.rs @@ -16,10 +16,9 @@ //! Transaction Execution environment. -use authentication::check_permission; -use builtin::Builtin; -use cita_types::{Address, H160, H256, U256, U512}; -use contracts::{ +use crate::authentication::check_permission; +use crate::builtin::Builtin; +use crate::contracts::{ grpc::{ self, contract::{ @@ -30,30 +29,31 @@ use contracts::{ }, native::factory::{Contract as NativeContract, Factory as NativeFactory}, }; +use crate::engines::Engine; +use crate::error::ExecutionError; +pub use crate::executed::{Executed, ExecutionResult}; +use crate::externalities::*; +use crate::libexecutor::economical_model::EconomicalModel; +use crate::libexecutor::sys_config::BlockSysConfig; +use crate::state::backend::Backend as StateBackend; +use crate::state::{State, Substate}; +use crate::trace::{ + ExecutiveTracer, ExecutiveVMTracer, FlatTrace, NoopTracer, NoopVMTracer, Tracer, VMTrace, + VMTracer, +}; +use crate::types::reserved_addresses; +use crate::types::transaction::{Action, SignedTransaction}; +use cita_types::{Address, H160, H256, U256, U512}; use crossbeam; -use engines::Engine; -use error::ExecutionError; use evm::action_params::{ActionParams, ActionValue}; use evm::call_type::CallType; use evm::env_info::EnvInfo; use evm::{self, Factory, FinalizationResult, Finalize, ReturnData, Schedule}; -pub use executed::{Executed, ExecutionResult}; -use externalities::*; use hashable::{Hashable, HASH_EMPTY}; -use libexecutor::economical_model::EconomicalModel; -use libexecutor::sys_config::BlockSysConfig; -use state::backend::Backend as StateBackend; -use state::{State, Substate}; use std::cmp; use std::error::Error; use std::str::FromStr; use std::sync::Arc; -use trace::{ - ExecutiveTracer, ExecutiveVMTracer, FlatTrace, NoopTracer, NoopVMTracer, Tracer, VMTrace, - VMTracer, -}; -use types::reserved_addresses; -use types::transaction::{Action, SignedTransaction}; use util::*; /// Roughly estimate what stack size each level of evm depth will use @@ -1216,21 +1216,21 @@ mod tests { use self::rustc_hex::FromHex; use super::*; + use crate::engines::NullEngine; + use crate::libexecutor::sys_config::BlockSysConfig; + use crate::state::Substate; + use crate::tests::helpers::*; + use crate::trace::{ExecutiveTracer, ExecutiveVMTracer}; + use crate::types::transaction::Transaction; use cita_crypto::{CreateKey, KeyPair}; use cita_types::{Address, H256, U256}; - use engines::NullEngine; use evm::action_params::{ActionParams, ActionValue}; use evm::env_info::EnvInfo; use evm::Schedule; use evm::{Factory, VMType}; - use libexecutor::sys_config::BlockSysConfig; - use state::Substate; use std::ops::Deref; use std::str::FromStr; use std::sync::Arc; - use tests::helpers::*; - use trace::{ExecutiveTracer, ExecutiveVMTracer}; - use types::transaction::Transaction; #[test] fn test_transfer_for_store() { diff --git a/cita-executor/core/src/externalities.rs b/cita-executor/core/src/externalities.rs index ffdda4b2d..429abed21 100644 --- a/cita-executor/core/src/externalities.rs +++ b/cita-executor/core/src/externalities.rs @@ -18,9 +18,15 @@ //////////////////////////////////////////////////////////////////////////////// +use crate::contracts::native::factory::Factory as NativeFactory; +use crate::engines::Engine; +use crate::executive::*; +use crate::libexecutor::economical_model::EconomicalModel; +use crate::state::backend::Backend as StateBackend; +use crate::state::State; +use crate::substate::Substate; +use crate::trace::{Tracer, VMTracer}; use cita_types::{Address, H256, U256}; -use contracts::native::factory::Factory as NativeFactory; -use engines::Engine; use evm::action_params::{ActionParams, ActionValue}; use evm::call_type::CallType; use evm::env_info::EnvInfo; @@ -28,15 +34,9 @@ use evm::{ self, ContractCreateResult, Factory, FinalizationResult, MessageCallResult, ReturnData, Schedule, }; -use executive::*; use hashable::Hashable; -use libexecutor::economical_model::EconomicalModel; -use state::backend::Backend as StateBackend; -use state::State; use std::cmp; use std::sync::Arc; -use substate::Substate; -use trace::{Tracer, VMTracer}; use util::*; /// Policy for handling output data on `RETURN` opcode. @@ -401,7 +401,7 @@ where } fn log(&mut self, topics: Vec, data: &[u8]) -> evm::Result<()> { - use log_entry::LogEntry; + use crate::log_entry::LogEntry; if self.static_flag { return Err(evm::Error::MutableCallInStaticContext); diff --git a/cita-executor/core/src/factory.rs b/cita-executor/core/src/factory.rs index 3389794de..576febae8 100644 --- a/cita-executor/core/src/factory.rs +++ b/cita-executor/core/src/factory.rs @@ -14,9 +14,9 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use account_db::Factory as AccountFactory; -use cita_db::trie::TrieFactory; -use contracts::native::factory::Factory as NativeFactory; +use crate::account_db::Factory as AccountFactory; +use crate::cita_db::trie::TrieFactory; +use crate::contracts::native::factory::Factory as NativeFactory; use evm::Factory as EvmFactory; /// Collection of factories. diff --git a/cita-executor/core/src/lib.rs b/cita-executor/core/src/lib.rs index f3eb06db6..fa86c4566 100644 --- a/cita-executor/core/src/lib.rs +++ b/cita-executor/core/src/lib.rs @@ -97,7 +97,7 @@ pub mod snapshot; mod spec; -pub use cita_db::journaldb; +pub use crate::cita_db::journaldb; +pub use crate::factory::*; +pub use crate::types::*; pub use evm::Error; -pub use factory::*; -pub use types::*; diff --git a/cita-executor/core/src/libexecutor/auto_exec.rs b/cita-executor/core/src/libexecutor/auto_exec.rs index 150737da2..fabe60507 100644 --- a/cita-executor/core/src/libexecutor/auto_exec.rs +++ b/cita-executor/core/src/libexecutor/auto_exec.rs @@ -15,23 +15,23 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use crate::contracts::native::factory::Factory as NativeFactory; +use crate::contracts::tools::method as method_tools; +use crate::engines::NullEngine; +use crate::externalities::{Externalities, OriginInfo, OutputPolicy}; +use crate::libexecutor::economical_model::EconomicalModel; +use crate::state::State; +use crate::state::Substate; +use crate::state_db::StateDB; +use crate::trace::Tracer; +use crate::trace::{NoopTracer, NoopVMTracer}; +use crate::types::reserved_addresses; use cita_types::{Address, H160, U256}; -use contracts::native::factory::Factory as NativeFactory; -use contracts::tools::method as method_tools; -use engines::NullEngine; use evm::action_params::{ActionParams, ActionValue}; use evm::call_type::CallType; use evm::env_info::EnvInfo; use evm::{Factory, Finalize, VMType}; -use externalities::{Externalities, OriginInfo, OutputPolicy}; -use libexecutor::economical_model::EconomicalModel; -use state::State; -use state::Substate; -use state_db::StateDB; use std::str::FromStr; -use trace::Tracer; -use trace::{NoopTracer, NoopVMTracer}; -use types::reserved_addresses; use util::BytesRef; const AUTO_EXEC: &[u8] = &*b"autoExec()"; diff --git a/cita-executor/core/src/libexecutor/block.rs b/cita-executor/core/src/libexecutor/block.rs index a332f6ab1..c508f3216 100644 --- a/cita-executor/core/src/libexecutor/block.rs +++ b/cita-executor/core/src/libexecutor/block.rs @@ -15,27 +15,27 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use basic_types::LogBloom; +use crate::basic_types::LogBloom; +use crate::engines::Engine; +use crate::error::Error; +use crate::factory::Factories; +use crate::libexecutor::auto_exec::auto_exec; +use crate::libexecutor::sys_config::BlockSysConfig; +use crate::receipt::Receipt; +use crate::state::State; +use crate::state_db::StateDB; +use crate::trace::FlatTrace; +pub use crate::types::block::{Block, BlockBody, OpenBlock}; +use crate::types::transaction::SignedTransaction; use cita_merklehash; use cita_types::{Address, H256, U256}; -use engines::Engine; -use error::Error; use evm::env_info::{EnvInfo, LastHashes}; -use factory::Factories; use hashable::Hashable; -use libexecutor::auto_exec::auto_exec; -use libexecutor::sys_config::BlockSysConfig; use libproto::executor::{ExecutedInfo, ReceiptWithOption}; -use receipt::Receipt; use rlp::*; -use state::State; -use state_db::StateDB; use std::collections::HashMap; use std::ops::{Deref, DerefMut}; use std::sync::Arc; -use trace::FlatTrace; -pub use types::block::{Block, BlockBody, OpenBlock}; -use types::transaction::SignedTransaction; lazy_static! { /// Block Reward diff --git a/cita-executor/core/src/libexecutor/command.rs b/cita-executor/core/src/libexecutor/command.rs index 41965ee34..84b630df0 100644 --- a/cita-executor/core/src/libexecutor/command.rs +++ b/cita-executor/core/src/libexecutor/command.rs @@ -18,30 +18,32 @@ use super::economical_model::EconomicalModel; use super::executor::{make_consensus_config, Executor}; use super::sys_config::GlobalSysConfig; +use crate::call_analytics::CallAnalytics; +use crate::contracts::solc::{ + sys_config::ChainId, PermissionManagement, SysConfig, VersionManager, +}; +use crate::engines::NullEngine; +use crate::error::CallError; +use crate::executive::{Executed, Executive, TransactOptions}; +pub use crate::libexecutor::block::*; +use crate::libexecutor::call_request::CallRequest; +use crate::state::State; +use crate::state_db::StateDB; +use crate::types::ids::BlockId; +use crate::types::transaction::{Action, SignedTransaction, Transaction}; pub use byteorder::{BigEndian, ByteOrder}; -use call_analytics::CallAnalytics; use cita_types::traits::LowerHex; use cita_types::{Address, H256, U256}; -use contracts::solc::{sys_config::ChainId, PermissionManagement, SysConfig, VersionManager}; use crossbeam_channel::{Receiver, Sender}; -use engines::NullEngine; -use error::CallError; use evm::env_info::EnvInfo; -use executive::{Executed, Executive, TransactOptions}; use jsonrpc_types::rpc_types::{ BlockNumber, BlockTag, EconomicalModel as RpcEconomicalModel, MetaData, }; -pub use libexecutor::block::*; -use libexecutor::call_request::CallRequest; use libproto::ExecutedResult; use serde_json; -use state::State; -use state_db::StateDB; use std::convert::{From, Into}; use std::fmt; use std::sync::Arc; -use types::ids::BlockId; -use types::transaction::{Action, SignedTransaction, Transaction}; use util::Bytes; use util::RwLock; diff --git a/cita-executor/core/src/libexecutor/executor.rs b/cita-executor/core/src/libexecutor/executor.rs index 5a4eea018..586903d9b 100644 --- a/cita-executor/core/src/libexecutor/executor.rs +++ b/cita-executor/core/src/libexecutor/executor.rs @@ -18,30 +18,30 @@ use super::command::{Command, CommandResp, Commander}; use super::fsm::FSM; use super::sys_config::GlobalSysConfig; -use bloomchain::group::{BloomGroup, BloomGroupDatabase, GroupPosition}; +use crate::bloomchain::group::{BloomGroup, BloomGroupDatabase, GroupPosition}; +use crate::cita_db::kvdb::{DBTransaction, Database, DatabaseConfig}; +use crate::cita_db::trie::{TrieFactory, TrieSpec}; +use crate::cita_db::{journaldb, KeyValueDB}; +use crate::contracts::{native::factory::Factory as NativeFactory, solc::NodeManager}; +use crate::db; +use crate::db::*; +use crate::engines::{Engine, NullEngine}; +use crate::factory::*; +use crate::header::*; +pub use crate::libexecutor::block::*; +use crate::libexecutor::genesis::Genesis; +use crate::state_db::StateDB; +use crate::types::extras::*; +use crate::types::ids::BlockId; pub use byteorder::{BigEndian, ByteOrder}; -use cita_db::kvdb::{DBTransaction, Database, DatabaseConfig}; -use cita_db::trie::{TrieFactory, TrieSpec}; -use cita_db::{journaldb, KeyValueDB}; use cita_types::H256; -use contracts::{native::factory::Factory as NativeFactory, solc::NodeManager}; use crossbeam_channel::{Receiver, Sender}; -use db; -use db::*; -use engines::{Engine, NullEngine}; use evm::env_info::LastHashes; use evm::Factory as EvmFactory; -use factory::*; -use header::*; -pub use libexecutor::block::*; -use libexecutor::genesis::Genesis; use libproto::{ConsensusConfig, ExecutedResult}; -use state_db::StateDB; use std::convert::{From, Into}; use std::sync::Arc; use std::time::Instant; -use types::extras::*; -use types::ids::BlockId; use util::RwLock; use util::UtilError; @@ -467,24 +467,24 @@ pub fn make_consensus_config(sys_config: GlobalSysConfig) -> ConsensusConfig { mod tests { extern crate cita_logger as logger; extern crate tempdir; + use crate::libexecutor::command::Commander; + use crate::libexecutor::command::{Command, CommandResp}; + use crate::libexecutor::fsm::FSM; + use crate::tests::helpers; + use crate::types::ids::BlockId; use cita_crypto::{CreateKey, KeyPair}; use cita_types::Address; - use libexecutor::command::Commander; - use libexecutor::command::{Command, CommandResp}; - use libexecutor::fsm::FSM; use std::thread; use std::time::Duration; - use tests::helpers; - use types::ids::BlockId; #[test] #[cfg(feature = "sha3hash")] fn test_chain_name_valid_block_number() { + use crate::contracts::solc::sys_config::SysConfig; + use crate::types::reserved_addresses; use cita_types::H256; - use contracts::solc::sys_config::SysConfig; use rustc_hex::FromHex; use std::str::FromStr; - use types::reserved_addresses; let privkey = H256::from("0x5f0258a4778057a8a7d97809bd209055b2fbafa654ce7d31ec7191066b9225e6"); diff --git a/cita-executor/core/src/libexecutor/fsm.rs b/cita-executor/core/src/libexecutor/fsm.rs index 1f87dcdd5..fd2c2f1bd 100644 --- a/cita-executor/core/src/libexecutor/fsm.rs +++ b/cita-executor/core/src/libexecutor/fsm.rs @@ -142,17 +142,17 @@ impl FSM for Executor { #[cfg(test)] mod tests { use super::ExecutedBlock; + use crate::libexecutor::block::OpenBlock; + use crate::libexecutor::executor::Executor; + use crate::libexecutor::fsm::{StatusOfFSM, FSM}; + use crate::tests::helpers::{ + create_block, generate_block_body, generate_block_header, generate_contract, init_executor, + init_executor2, + }; use cita_crypto::{CreateKey, KeyPair}; use cita_types::Address; - use libexecutor::block::OpenBlock; - use libexecutor::executor::Executor; - use libexecutor::fsm::{StatusOfFSM, FSM}; use std::thread; use std::time::Duration; - use tests::helpers::{ - create_block, generate_block_body, generate_block_header, generate_contract, init_executor, - init_executor2, - }; fn generate_empty_block() -> OpenBlock { let block_body = generate_block_body(); diff --git a/cita-executor/core/src/libexecutor/genesis.rs b/cita-executor/core/src/libexecutor/genesis.rs index 74fc32e00..dbad1ac00 100644 --- a/cita-executor/core/src/libexecutor/genesis.rs +++ b/cita-executor/core/src/libexecutor/genesis.rs @@ -15,25 +15,25 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use cita_db::kvdb::KeyValueDB; +use crate::cita_db::kvdb::KeyValueDB; +use crate::db::{self as db, Writable}; +use crate::factory::Factories; +use crate::libexecutor::block::Block; +use crate::state::State; +use crate::state_db::StateDB; +use crate::types::extras::*; use cita_types::traits::ConvertType; use cita_types::{clean_0x, Address, H256, U256}; use crypto::digest::Digest; use crypto::md5::Md5; -use db::{self as db, Writable}; -use factory::Factories; -use libexecutor::block::Block; use rustc_hex::FromHex; use serde_json; -use state::State; -use state_db::StateDB; use std::collections::HashMap; use std::fs::File; use std::io::BufReader; use std::io::Read; use std::path::Path; use std::sync::Arc; -use types::extras::*; #[cfg(feature = "privatetx")] use zktx::set_param_path; @@ -187,8 +187,8 @@ impl Genesis { #[cfg(test)] mod test { + use crate::libexecutor::genesis::{Contract, Spec}; use cita_types::{H256, U256}; - use libexecutor::genesis::{Contract, Spec}; use serde_json; use std::collections::HashMap; use std::str::FromStr; diff --git a/cita-executor/core/src/libexecutor/mod.rs b/cita-executor/core/src/libexecutor/mod.rs index 4f6b43ab6..afe1963bf 100644 --- a/cita-executor/core/src/libexecutor/mod.rs +++ b/cita-executor/core/src/libexecutor/mod.rs @@ -28,5 +28,5 @@ pub mod lru_cache; pub mod sys_config; pub use self::genesis::Genesis; -pub use cita_db::journaldb; +pub use crate::cita_db::journaldb; pub use libproto::*; diff --git a/cita-executor/core/src/libexecutor/sys_config.rs b/cita-executor/core/src/libexecutor/sys_config.rs index 71d5e2f8f..a53f01280 100644 --- a/cita-executor/core/src/libexecutor/sys_config.rs +++ b/cita-executor/core/src/libexecutor/sys_config.rs @@ -16,14 +16,14 @@ // along with this program. If not, see . use super::executor::Executor; -use cita_types::{Address, U256}; -use contracts::solc::{ +use crate::contracts::solc::{ AccountQuotaLimit, EmergencyBrake, NodeManager, PermissionManagement, PriceManagement, QuotaManager, Resource, SysConfig, UserManagement, VersionManager, AUTO_EXEC_QL_VALUE, }; -use libexecutor::economical_model::EconomicalModel; +use crate::libexecutor::economical_model::EconomicalModel; +use crate::types::ids::BlockId; +use cita_types::{Address, U256}; use std::collections::HashMap; -use types::ids::BlockId; #[derive(Serialize, Deserialize, PartialEq, Debug, Clone)] pub struct GlobalSysConfig { diff --git a/cita-executor/core/src/pod_account.rs b/cita-executor/core/src/pod_account.rs index f91e4a557..87b839a6f 100644 --- a/cita-executor/core/src/pod_account.rs +++ b/cita-executor/core/src/pod_account.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -use account_db::AccountDBMut; -use cita_db::{sec_trie_root, HashDB, TrieFactory}; +use crate::account_db::AccountDBMut; +use crate::cita_db::{sec_trie_root, HashDB, TrieFactory}; +use crate::state::Account; use cita_types::{H256, U256}; use hashable::Hashable; use rlp::{self, RlpStream}; -use state::Account; use std::collections::BTreeMap; use std::fmt; use util::*; diff --git a/cita-executor/core/src/snapshot/account.rs b/cita-executor/core/src/snapshot/account.rs index 16fb5d61c..c1f79ca9a 100644 --- a/cita-executor/core/src/snapshot/account.rs +++ b/cita-executor/core/src/snapshot/account.rs @@ -16,15 +16,15 @@ //! Account state encoding and decoding -use account_db::{AccountDB, AccountDBMut}; -use cita_db::hashdb::HashDB; -use cita_db::{Trie, TrieDB, TrieDBMut, TrieMut}; +use crate::account_db::{AccountDB, AccountDBMut}; +use crate::cita_db::hashdb::HashDB; +use crate::cita_db::{Trie, TrieDB, TrieDBMut, TrieMut}; +use crate::snapshot::Error; +use crate::types::basic_account::BasicAccount; use cita_types::{Address, H256, U256}; use hashable::{HASH_EMPTY, HASH_NULL_RLP}; use rlp::{RlpStream, UntrustedRlp}; -use snapshot::Error; use std::collections::HashSet; -use types::basic_account::BasicAccount; use util::Bytes; // An empty account -- these were replaced with RLP null data for a space optimization in v1. diff --git a/cita-executor/core/src/snapshot/error.rs b/cita-executor/core/src/snapshot/error.rs index 805209c60..17dff3cb1 100644 --- a/cita-executor/core/src/snapshot/error.rs +++ b/cita-executor/core/src/snapshot/error.rs @@ -18,9 +18,9 @@ use std::fmt; -use types::ids::BlockId; +use crate::types::ids::BlockId; -use cita_db::trie::TrieError; +use crate::cita_db::trie::TrieError; use cita_types::{Address, H256}; use rlp::DecoderError; use snappy::SnappyError; diff --git a/cita-executor/core/src/snapshot/io.rs b/cita-executor/core/src/snapshot/io.rs index adeccb472..39bfdeabb 100644 --- a/cita-executor/core/src/snapshot/io.rs +++ b/cita-executor/core/src/snapshot/io.rs @@ -299,7 +299,7 @@ pub struct LooseReader { impl LooseReader { /// Create a new `LooseReader` which will read the manifest and chunk data from /// the given directory. - pub fn create(mut dir: PathBuf) -> Result { + pub fn create(mut dir: PathBuf) -> Result { let mut manifest_buf = Vec::new(); dir.push("MANIFEST"); diff --git a/cita-executor/core/src/snapshot/mod.rs b/cita-executor/core/src/snapshot/mod.rs index 980433798..8faa45ee7 100644 --- a/cita-executor/core/src/snapshot/mod.rs +++ b/cita-executor/core/src/snapshot/mod.rs @@ -19,17 +19,17 @@ // chunks around 4MB before compression const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024; -use account_db::{AccountDB, AccountDBMut}; - -use cita_db::hashdb::DBValue; -use cita_db::journaldb::{self, Algorithm, JournalDB}; -use cita_db::kvdb::{DBTransaction, Database, KeyValueDB}; -use cita_db::{HashDB, Trie, TrieDB, TrieDBMut, TrieMut}; +use crate::account_db::{AccountDB, AccountDBMut}; + +use crate::cita_db::hashdb::DBValue; +use crate::cita_db::journaldb::{self, Algorithm, JournalDB}; +use crate::cita_db::kvdb::{DBTransaction, Database, KeyValueDB}; +use crate::cita_db::{HashDB, Trie, TrieDB, TrieDBMut, TrieMut}; +use crate::db::{Writable, COL_EXTRA, COL_HEADERS, COL_STATE}; +use crate::libexecutor::executor::Executor; use cita_types::{Address, H256, U256}; -use db::{Writable, COL_EXTRA, COL_HEADERS, COL_STATE}; use hashable::Hashable; use hashable::{HASH_EMPTY, HASH_NULL_RLP}; -use libexecutor::executor::Executor; use rlp::{DecoderError, Encodable, RlpStream, UntrustedRlp}; use snappy; use std::collections::{HashMap, HashSet, VecDeque}; @@ -46,17 +46,17 @@ pub use self::error::Error; use self::io::SnapshotReader; use self::io::SnapshotWriter; use self::service::Service; -use snapshot::service::SnapshotService; -pub use types::basic_account::BasicAccount; -use types::ids::BlockId; +use crate::snapshot::service::SnapshotService; +pub use crate::types::basic_account::BasicAccount; +use crate::types::ids::BlockId; use super::state::backend::Backend; use super::state::Account as StateAccount; use super::state_db::StateDB; +use crate::header::Header; use ethcore_bloom_journal::Bloom; -use header::Header; -use types::extras::CurrentHash; +use crate::types::extras::CurrentHash; /// A sink for produced chunks. pub type ChunkSink<'a> = FnMut(&[u8]) -> Result<(), Error> + 'a; @@ -518,7 +518,7 @@ impl StateRebuilder { } /// Feed an uncompressed state chunk into the rebuilder. - pub fn feed(&mut self, chunk: &[u8], flag: &AtomicBool) -> Result<(), ::error::Error> { + pub fn feed(&mut self, chunk: &[u8], flag: &AtomicBool) -> Result<(), crate::error::Error> { let rlp = UntrustedRlp::new(chunk); let empty_rlp = StateAccount::new_basic(U256::zero(), U256::zero()).rlp(); let mut pairs = Vec::with_capacity(rlp.item_count()?); @@ -609,7 +609,7 @@ impl StateRebuilder { /// Finalize the restoration. Check for accounts missing code and make a dummy /// journal entry. /// Once all chunks have been fed, there should be nothing missing. - pub fn finalize(mut self, era: u64, id: H256) -> Result, ::error::Error> { + pub fn finalize(mut self, era: u64, id: H256) -> Result, crate::error::Error> { let mut batch = self.db.backing().transaction(); self.db.journal_under(&mut batch, era, &id)?; self.db.backing().write_buffered(batch); @@ -643,7 +643,7 @@ fn rebuild_accounts( known_abi: &HashMap, known_storage_roots: &mut HashMap, abort_flag: &AtomicBool, -) -> Result { +) -> Result { let mut status = RebuiltStatus::default(); for (account_rlp, out) in account_fat_rlps.into_iter().zip(out_chunk.iter_mut()) { if !abort_flag.load(Ordering::SeqCst) { @@ -760,7 +760,11 @@ impl BlockRebuilder { } /// Feed an uncompressed state chunk into the rebuilder. - pub fn feed(&mut self, chunk: &[u8], abort_flag: &AtomicBool) -> Result<(), ::error::Error> { + pub fn feed( + &mut self, + chunk: &[u8], + abort_flag: &AtomicBool, + ) -> Result<(), crate::error::Error> { let rlp = UntrustedRlp::new(chunk); let item_count = rlp.item_count()?; let num_blocks = (item_count - 2) as u64; @@ -840,7 +844,7 @@ impl BlockRebuilder { } /// Glue together any disconnected chunks and check that the chain is complete. - fn finalize(&self) -> Result<(), ::error::Error> { + fn finalize(&self) -> Result<(), crate::error::Error> { let mut batch = self.db.transaction(); let genesis_header = self .executor diff --git a/cita-executor/core/src/snapshot/service.rs b/cita-executor/core/src/snapshot/service.rs index c1925ea89..aeb83e15d 100644 --- a/cita-executor/core/src/snapshot/service.rs +++ b/cita-executor/core/src/snapshot/service.rs @@ -27,14 +27,14 @@ use std::sync::Arc; use super::io::{LooseReader, LooseWriter, SnapshotReader, SnapshotWriter}; use super::{BlockRebuilder, ManifestData, RestorationStatus, StateRebuilder}; -use error::Error; +use crate::error::Error; +use crate::libexecutor::executor::Executor; use cita_types::H256; -use libexecutor::executor::Executor; -use cita_db::journaldb::Algorithm; -use cita_db::kvdb::{Database, DatabaseConfig, KeyValueDB}; -use cita_db::TrieError; +use crate::cita_db::journaldb::Algorithm; +use crate::cita_db::kvdb::{Database, DatabaseConfig, KeyValueDB}; +use crate::cita_db::TrieError; use snappy; use util::Bytes; use util::UtilError; diff --git a/cita-executor/core/src/spec/builtin.rs b/cita-executor/core/src/spec/builtin.rs index 5340436ea..4d6e2de05 100644 --- a/cita-executor/core/src/spec/builtin.rs +++ b/cita-executor/core/src/spec/builtin.rs @@ -53,8 +53,8 @@ pub struct Builtin { #[cfg(test)] mod tests { + use crate::spec::builtin::{Builtin, Linear, Pricing}; use serde_json; - use spec::builtin::{Builtin, Linear, Pricing}; #[test] fn builtin_deserialization() { diff --git a/cita-executor/core/src/state/account.rs b/cita-executor/core/src/state/account.rs index 70804ff91..20ceac16a 100644 --- a/cita-executor/core/src/state/account.rs +++ b/cita-executor/core/src/state/account.rs @@ -19,12 +19,13 @@ //! Single account in the system. -use cita_db::{trie, DBValue, HashDB, Trie, TrieFactory}; +use crate::cita_db::{trie, DBValue, HashDB, Trie, TrieFactory}; +use crate::pod_account::*; +use crate::types::basic_account::BasicAccount; use cita_types::traits::LowerHex; use cita_types::{Address, H256, U256}; use hashable::{Hashable, HASH_EMPTY, HASH_NULL_RLP}; use lru_cache::LruCache; -use pod_account::*; use rlp::*; use std::cell::{Cell, RefCell}; use std::collections::BTreeMap; @@ -32,7 +33,6 @@ use std::collections::HashMap; use std::convert::Into; use std::fmt; use std::sync::Arc; -use types::basic_account::BasicAccount; use util::*; const STORAGE_CACHE_ITEMS: usize = 8192; @@ -720,8 +720,8 @@ impl fmt::Debug for Account { #[cfg(test)] mod tests { use super::*; - use account_db::*; - use cita_db::MemoryDB; + use crate::account_db::*; + use crate::cita_db::MemoryDB; use rlp::{Compressible, RlpType, UntrustedRlp}; #[test] diff --git a/cita-executor/core/src/state/backend.rs b/cita-executor/core/src/state/backend.rs index 7058cdf55..8205d9c39 100644 --- a/cita-executor/core/src/state/backend.rs +++ b/cita-executor/core/src/state/backend.rs @@ -16,9 +16,9 @@ use std::sync::Arc; -use cita_db::HashDB; +use crate::cita_db::HashDB; +use crate::state::Account; use cita_types::{Address, H256}; -use state::Account; /// State backend. See module docs for more details. pub trait Backend: Send { diff --git a/cita-executor/core/src/state/mod.rs b/cita-executor/core/src/state/mod.rs index 7220c4479..424e27e94 100644 --- a/cita-executor/core/src/state/mod.rs +++ b/cita-executor/core/src/state/mod.rs @@ -19,19 +19,21 @@ //! Unconfirmed sub-states are managed with `checkpoint`s which may be canonicalized //! or rolled back. -use cita_db::{trie, HashDB, Trie, TrieError}; +use crate::cita_db::{trie, HashDB, Trie, TrieError}; +use crate::engines::Engine; +use crate::error::{Error, ExecutionError}; +use crate::executive::{Executive, TransactOptions}; +use crate::factory::Factories; +use crate::libexecutor::economical_model::EconomicalModel; +use crate::libexecutor::sys_config::BlockSysConfig; +use crate::receipt::{Receipt, ReceiptError}; +use crate::trace::FlatTrace; +use crate::types::transaction::SignedTransaction; use cita_types::{Address, H256, U256}; -use engines::Engine; -use error::{Error, ExecutionError}; use evm::env_info::EnvInfo; use evm::Error as EvmError; use evm::Schedule; -use executive::{Executive, TransactOptions}; -use factory::Factories; use hashable::HASH_EMPTY; -use libexecutor::economical_model::EconomicalModel; -use libexecutor::sys_config::BlockSysConfig; -use receipt::{Receipt, ReceiptError}; use rlp::{self, Encodable}; use std::cell::{Ref, RefCell, RefMut}; use std::cmp; @@ -39,8 +41,6 @@ use std::collections::hash_map::Entry; use std::collections::{HashMap, HashSet}; use std::fmt; use std::sync::Arc; -use trace::FlatTrace; -use types::transaction::SignedTransaction; use util::*; pub mod account; @@ -48,7 +48,7 @@ pub mod backend; pub use self::account::Account; use self::backend::*; -pub use substate::Substate; +pub use crate::substate::Substate; /// Used to return information about an `State::apply` operation. pub struct ApplyOutcome { @@ -1211,15 +1211,15 @@ mod tests { use self::libproto::blockchain; use self::rustc_hex::FromHex; use super::*; + use crate::engines::NullEngine; + use crate::libexecutor::sys_config::BlockSysConfig; + use crate::tests::helpers::*; use cita_crypto::KeyPair; use cita_crypto_trait::CreateKey; use cita_types::traits::LowerHex; use cita_types::{Address, H256}; - use engines::NullEngine; use evm::env_info::EnvInfo; - use libexecutor::sys_config::BlockSysConfig; use std::sync::Arc; - use tests::helpers::*; #[test] #[ignore] @@ -1276,7 +1276,7 @@ mod tests { gas_used: 0.into(), account_gas_limit: 1844674.into(), }; - let contract_address = ::executive::contract_address(&signed.sender(), &U256::from(1)); + let contract_address = crate::executive::contract_address(&signed.sender(), &U256::from(1)); let engine = NullEngine::cita(); println!("contract_address {:?}", contract_address); diff --git a/cita-executor/core/src/state_db.rs b/cita-executor/core/src/state_db.rs index 0f272ac7a..3afffcf21 100644 --- a/cita-executor/core/src/state_db.rs +++ b/cita-executor/core/src/state_db.rs @@ -17,15 +17,15 @@ // CITA, Copyright 2016-2017 Cryptape Technologies LLC. // Remove some hf code. +use crate::cita_db::{DBTransaction, HashDB, JournalDB, KeyValueDB}; +use crate::db::COL_ACCOUNT_BLOOM; +use crate::header::BlockNumber; +use crate::state::backend::*; +use crate::state::Account; use byteorder::{ByteOrder, LittleEndian}; -use cita_db::{DBTransaction, HashDB, JournalDB, KeyValueDB}; use cita_types::{Address, H256}; -use db::COL_ACCOUNT_BLOOM; use ethcore_bloom_journal::{Bloom, BloomJournal}; -use header::BlockNumber; use lru_cache::LruCache; -use state::backend::*; -use state::Account; use std::collections::{HashSet, VecDeque}; use std::sync::Arc; use util::cache::MemoryLruCache; diff --git a/cita-executor/core/src/substate.rs b/cita-executor/core/src/substate.rs index 1494760b9..81087f0b7 100644 --- a/cita-executor/core/src/substate.rs +++ b/cita-executor/core/src/substate.rs @@ -16,8 +16,8 @@ //! Execution environment substate. +use crate::log_entry::LogEntry; use cita_types::{Address, U256}; -use log_entry::LogEntry; use std::collections::HashSet; /// State changes which should be applied in finalize, @@ -60,7 +60,7 @@ impl Substate { #[cfg(test)] mod tests { use super::Substate; - use log_entry::LogEntry; + use crate::log_entry::LogEntry; #[test] fn created() { diff --git a/cita-executor/core/src/tests/amend_data_test.rs b/cita-executor/core/src/tests/amend_data_test.rs index 4e6beea66..802e82c2f 100644 --- a/cita-executor/core/src/tests/amend_data_test.rs +++ b/cita-executor/core/src/tests/amend_data_test.rs @@ -16,26 +16,26 @@ // along with this program. If not, see . use super::helpers::*; +use crate::executive::Executive; +use crate::libexecutor::economical_model::EconomicalModel; +use crate::reserved_addresses; +use crate::state::State; +use crate::state_db::*; use cita_types::{Address, H256, U256}; use evm; use evm::action_params::{ActionParams, ActionValue}; -use executive::Executive; -use libexecutor::economical_model::EconomicalModel; -use reserved_addresses; -use state::State; -use state_db::*; use util::{Bytes, BytesRef}; fn call_vm( state: &mut State, params: ActionParams, ) -> evm::Result { - use contracts::native::factory::Factory as NativeFactory; - use engines::NullEngine; + use crate::contracts::native::factory::Factory as NativeFactory; + use crate::engines::NullEngine; + use crate::state::Substate; + use crate::trace::{ExecutiveTracer, ExecutiveVMTracer}; use evm::env_info::EnvInfo; use evm::{Factory, VMType}; - use state::Substate; - use trace::{ExecutiveTracer, ExecutiveVMTracer}; let factory = Factory::new(VMType::Interpreter, 1024 * 32); let native_factory = NativeFactory::default(); let mut tracer = ExecutiveTracer::default(); diff --git a/cita-executor/core/src/tests/grpc_test.rs b/cita-executor/core/src/tests/grpc_test.rs index ecce136b0..425bd5be6 100644 --- a/cita-executor/core/src/tests/grpc_test.rs +++ b/cita-executor/core/src/tests/grpc_test.rs @@ -16,23 +16,23 @@ // along with this program. If not, see . use super::helpers::*; -use cita_types::{Address, U256}; -use contracts::{ +use crate::contracts::{ grpc::{ contract::{contract_creation_address, low_contract_address}, service_registry, }, native::factory::Factory as NativeFactory, }; -use engines::NullEngine; +use crate::engines::NullEngine; +use crate::executive::Executive; +use crate::libexecutor::economical_model::EconomicalModel; +use crate::state::Substate; +use crate::trace::{ExecutiveTracer, ExecutiveVMTracer}; +use cita_types::{Address, U256}; use evm; use evm::action_params::{ActionParams, ActionValue}; use evm::env_info::EnvInfo; use evm::{Factory, VMType}; -use executive::Executive; -use libexecutor::economical_model::EconomicalModel; -use state::Substate; -use trace::{ExecutiveTracer, ExecutiveVMTracer}; use util::BytesRef; mod grpc_service { diff --git a/cita-executor/core/src/tests/helpers.rs b/cita-executor/core/src/tests/helpers.rs index 16f0a2a08..becc834a4 100644 --- a/cita-executor/core/src/tests/helpers.rs +++ b/cita-executor/core/src/tests/helpers.rs @@ -20,21 +20,23 @@ extern crate tempdir; use self::rustc_serialize::hex::FromHex; use self::tempdir::TempDir; +use crate::cita_db::kvdb::{self, Database, DatabaseConfig}; +use crate::cita_db::KeyValueDB; +use crate::db; +use crate::journaldb; +use crate::libexecutor::block::{BlockBody, ClosedBlock, OpenBlock}; +use crate::libexecutor::command; +use crate::libexecutor::executor::Executor; +use crate::state::State; +use crate::state_db::*; +use crate::types::header::OpenHeader; +use crate::types::transaction::SignedTransaction; use cita_crypto::PrivKey; -use cita_db::kvdb::{self, Database, DatabaseConfig}; -use cita_db::KeyValueDB; use cita_types::traits::LowerHex; use cita_types::{Address, U256}; use core::libchain::chain; use crossbeam_channel::{Receiver, Sender}; -use db; -use journaldb; -use libexecutor::block::{BlockBody, ClosedBlock, OpenBlock}; -use libexecutor::command; -use libexecutor::executor::Executor; use libproto::blockchain; -use state::State; -use state_db::*; use std::env; use std::fs::File; use std::io::Read; @@ -43,8 +45,6 @@ use std::path::Path; use std::process::Command; use std::sync::Arc; use std::time::UNIX_EPOCH; -use types::header::OpenHeader; -use types::transaction::SignedTransaction; use util::AsMillis; const CHAIN_CONFIG: &str = "chain.toml"; @@ -61,7 +61,7 @@ fn new_db() -> Arc { pub fn get_temp_state_db() -> StateDB { let db = new_db(); - let journal_db = journaldb::new(db, journaldb::Algorithm::Archive, ::db::COL_STATE); + let journal_db = journaldb::new(db, journaldb::Algorithm::Archive, crate::db::COL_STATE); StateDB::new(journal_db, 5 * 1024 * 1024) } @@ -220,7 +220,7 @@ pub fn generate_block_header() -> OpenHeader { pub fn generate_block_body() -> BlockBody { let mut stx = SignedTransaction::default(); - use types::transaction::SignedTransaction; + use crate::types::transaction::SignedTransaction; stx.data = vec![1; 200]; let transactions = vec![stx; 200]; BlockBody { transactions } diff --git a/cita-executor/core/src/trace/config.rs b/cita-executor/core/src/trace/config.rs index 745b88113..f7252adbe 100644 --- a/cita-executor/core/src/trace/config.rs +++ b/cita-executor/core/src/trace/config.rs @@ -16,7 +16,7 @@ //! Traces config. -use bloomchain::Config as BloomConfig; +use crate::bloomchain::Config as BloomConfig; /// Traces config. #[derive(Debug, PartialEq, Clone, Copy)] diff --git a/cita-executor/core/src/trace/db.rs b/cita-executor/core/src/trace/db.rs index a8b0f9bd0..0dfda5f5d 100644 --- a/cita-executor/core/src/trace/db.rs +++ b/cita-executor/core/src/trace/db.rs @@ -17,20 +17,20 @@ //! Trace database. use super::flat::{FlatBlockTraces, FlatTrace, FlatTransactionTraces}; -use bloomchain::group::{BloomGroup, BloomGroupChain, BloomGroupDatabase, GroupPosition}; -use bloomchain::{Bloom, Config as BloomChainConfig, Number as BloomChainNumber}; -use cache_manager::CacheManager; -use cita_db::{DBTransaction, KeyValueDB}; +use crate::bloomchain::group::{BloomGroup, BloomGroupChain, BloomGroupDatabase, GroupPosition}; +use crate::bloomchain::{Bloom, Config as BloomChainConfig, Number as BloomChainNumber}; +use crate::cache_manager::CacheManager; +use crate::cita_db::{DBTransaction, KeyValueDB}; +use crate::db::{self, CacheUpdatePolicy, Key, Readable, Writable}; +use crate::header::BlockNumber; +use crate::log_blooms::LogBloomGroup; +use crate::trace::{ + Config, Database as TraceDatabase, DatabaseExtras, Filter, ImportRequest, LocalizedTrace, +}; use cita_types::{H256, H264}; -use db::{self, CacheUpdatePolicy, Key, Readable, Writable}; -use header::BlockNumber; -use log_blooms::LogBloomGroup; use std::collections::{HashMap, VecDeque}; use std::ops::Deref; use std::sync::Arc; -use trace::{ - Config, Database as TraceDatabase, DatabaseExtras, Filter, ImportRequest, LocalizedTrace, -}; use util::{HeapSizeOf, RwLock}; const TRACE_DB_VER: &[u8] = b"1.0"; @@ -490,16 +490,16 @@ where #[cfg(test)] mod tests { - use cita_db::{kvdb, DBTransaction, KeyValueDB}; + use crate::cita_db::{kvdb, DBTransaction, KeyValueDB}; + use crate::header::BlockNumber; + use crate::trace::flat::{FlatBlockTraces, FlatTrace, FlatTransactionTraces}; + use crate::trace::trace::{Action, Call, Res}; + use crate::trace::{AddressesFilter, Filter, LocalizedTrace, TraceError}; + use crate::trace::{Config, Database as TraceDatabase, DatabaseExtras, ImportRequest, TraceDB}; use cita_types::{Address, H256, U256}; use evm::call_type::CallType; - use header::BlockNumber; use std::collections::HashMap; use std::sync::Arc; - use trace::flat::{FlatBlockTraces, FlatTrace, FlatTransactionTraces}; - use trace::trace::{Action, Call, Res}; - use trace::{AddressesFilter, Filter, LocalizedTrace, TraceError}; - use trace::{Config, Database as TraceDatabase, DatabaseExtras, ImportRequest, TraceDB}; struct NoopExtras; @@ -549,7 +549,7 @@ mod tests { } fn new_db() -> Arc { - Arc::new(kvdb::in_memory(::db::NUM_COLUMNS.unwrap_or(0))) + Arc::new(kvdb::in_memory(crate::db::NUM_COLUMNS.unwrap_or(0))) } #[test] diff --git a/cita-executor/core/src/trace/executive_tracer.rs b/cita-executor/core/src/trace/executive_tracer.rs index a856af215..694c48f1a 100644 --- a/cita-executor/core/src/trace/executive_tracer.rs +++ b/cita-executor/core/src/trace/executive_tracer.rs @@ -16,13 +16,13 @@ //! Simple executive tracer. -use cita_types::{Address, U256}; -use evm::action_params::ActionParams; -use trace::trace::{ +use crate::trace::trace::{ Action, Call, CallResult, Create, CreateResult, MemoryDiff, Res, StorageDiff, Suicide, VMExecutedOperation, VMOperation, VMTrace, }; -use trace::{FlatTrace, TraceError, Tracer, VMTracer}; +use crate::trace::{FlatTrace, TraceError, Tracer, VMTracer}; +use cita_types::{Address, U256}; +use evm::action_params::ActionParams; use util::Bytes; /// Simple executive tracer. Traces all calls and creates. Ignores delegatecalls. diff --git a/cita-executor/core/src/trace/import.rs b/cita-executor/core/src/trace/import.rs index 8951e8198..d22c91f4f 100644 --- a/cita-executor/core/src/trace/import.rs +++ b/cita-executor/core/src/trace/import.rs @@ -16,9 +16,9 @@ //! Traces import request. +use crate::header::BlockNumber; +use crate::trace::FlatBlockTraces; use cita_types::H256; -use header::BlockNumber; -use trace::FlatBlockTraces; /// Traces import request. pub struct ImportRequest { diff --git a/cita-executor/core/src/trace/mod.rs b/cita-executor/core/src/trace/mod.rs index 4f5c53067..822f04776 100644 --- a/cita-executor/core/src/trace/mod.rs +++ b/cita-executor/core/src/trace/mod.rs @@ -37,10 +37,10 @@ pub use self::types::filter::{AddressesFilter, Filter}; pub use self::types::flat::{FlatBlockTraces, FlatTrace, FlatTransactionTraces}; pub use self::types::trace::{MemoryDiff, StorageDiff, VMExecutedOperation, VMOperation, VMTrace}; pub use self::types::{filter, flat, localized, trace}; -use cita_db::DBTransaction; +use crate::cita_db::DBTransaction; +use crate::header::BlockNumber; use cita_types::{Address, H256, U256}; use evm::action_params::ActionParams; -use header::BlockNumber; use util::Bytes; /// This trait is used by executive to build traces. diff --git a/cita-executor/core/src/trace/noop_tracer.rs b/cita-executor/core/src/trace/noop_tracer.rs index f10eb970f..70acfcc12 100644 --- a/cita-executor/core/src/trace/noop_tracer.rs +++ b/cita-executor/core/src/trace/noop_tracer.rs @@ -16,10 +16,10 @@ //! Nonoperative tracer. +use crate::trace::trace::{Call, Create, VMTrace}; +use crate::trace::{FlatTrace, TraceError, Tracer, VMTracer}; use cita_types::{Address, U256}; use evm::action_params::ActionParams; -use trace::trace::{Call, Create, VMTrace}; -use trace::{FlatTrace, TraceError, Tracer, VMTracer}; use util::Bytes; /// Nonoperative tracer. Does not trace anything. diff --git a/cita-executor/core/src/trace/types/filter.rs b/cita-executor/core/src/trace/types/filter.rs index d7799a77e..87fb5de9e 100644 --- a/cita-executor/core/src/trace/types/filter.rs +++ b/cita-executor/core/src/trace/types/filter.rs @@ -17,12 +17,12 @@ //! Trace filters type definitions use super::trace::{Action, Res}; -use basic_types::LogBloom; -use bloomchain::{Bloom, Filter as BloomFilter, Number}; +use crate::basic_types::LogBloom; +use crate::bloomchain::{Bloom, Filter as BloomFilter, Number}; +use crate::trace::flat::FlatTrace; use cita_types::traits::BloomTools; use cita_types::Address; use std::ops::Range; -use trace::flat::FlatTrace; /// Addresses filter. /// @@ -146,13 +146,13 @@ impl Filter { #[cfg(test)] mod tests { - use basic_types::LogBloom; + use crate::basic_types::LogBloom; + use crate::trace::flat::FlatTrace; + use crate::trace::trace::{Action, Call, Create, CreateResult, Res, Suicide}; + use crate::trace::{AddressesFilter, Filter, TraceError}; use cita_types::traits::BloomTools; use cita_types::Address; use evm::call_type::CallType; - use trace::flat::FlatTrace; - use trace::trace::{Action, Call, Create, CreateResult, Res, Suicide}; - use trace::{AddressesFilter, Filter, TraceError}; #[test] fn empty_trace_filter_bloom_possibilities() { diff --git a/cita-executor/core/src/trace/types/flat.rs b/cita-executor/core/src/trace/types/flat.rs index af2d2a5a5..49a6f2c8b 100644 --- a/cita-executor/core/src/trace/types/flat.rs +++ b/cita-executor/core/src/trace/types/flat.rs @@ -17,7 +17,7 @@ //! Flat trace module use super::trace::{Action, Res}; -use basic_types::LogBloom; +use crate::basic_types::LogBloom; use rlp::*; use std::collections::VecDeque; use util::HeapSizeOf; @@ -165,9 +165,9 @@ impl Into> for FlatBlockTraces { #[cfg(test)] mod tests { use super::{FlatBlockTraces, FlatTrace, FlatTransactionTraces}; + use crate::trace::trace::{Action, Call, CallResult, Res, Suicide}; use evm::call_type::CallType; use rlp::*; - use trace::trace::{Action, Call, CallResult, Res, Suicide}; #[test] fn encode_flat_transaction_traces() { diff --git a/cita-executor/core/src/trace/types/localized.rs b/cita-executor/core/src/trace/types/localized.rs index da653e5e4..17cd0d3ce 100644 --- a/cita-executor/core/src/trace/types/localized.rs +++ b/cita-executor/core/src/trace/types/localized.rs @@ -17,8 +17,8 @@ //! Localized traces type definitions use super::trace::{Action, Res}; +use crate::header::BlockNumber; use cita_types::H256; -use header::BlockNumber; /// Localized trace. #[derive(Debug, PartialEq, Clone)] diff --git a/cita-executor/core/src/trace/types/trace.rs b/cita-executor/core/src/trace/types/trace.rs index ca4205e8b..19420d3b2 100644 --- a/cita-executor/core/src/trace/types/trace.rs +++ b/cita-executor/core/src/trace/types/trace.rs @@ -18,7 +18,7 @@ use super::error::Error; -use basic_types::LogBloom; +use crate::basic_types::LogBloom; use cita_types::traits::BloomTools; use cita_types::{Address, U256}; use evm::action_params::ActionParams; From c5c1e58c8dad0b506b67678c7dca5b9cbd6bc18d Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Fri, 21 Jun 2019 16:16:55 +0800 Subject: [PATCH 77/91] Update core to 2018 edition. [skip travis] --- cita-chain/core/Cargo.toml | 1 + cita-chain/core/src/env_info.rs | 2 +- cita-chain/core/src/error.rs | 8 ++--- cita-chain/core/src/filters/eth_filter.rs | 6 ++-- cita-chain/core/src/lib.rs | 4 +-- cita-chain/core/src/libchain/chain.rs | 38 +++++++++++------------ cita-chain/core/src/libchain/mod.rs | 4 +-- cita-chain/core/src/snapshot/error.rs | 4 +-- cita-chain/core/src/snapshot/io.rs | 4 +-- cita-chain/core/src/snapshot/mod.rs | 32 +++++++++++-------- cita-chain/core/src/snapshot/service.rs | 8 ++--- 11 files changed, 59 insertions(+), 52 deletions(-) diff --git a/cita-chain/core/Cargo.toml b/cita-chain/core/Cargo.toml index 93d988614..ea0f94ef7 100644 --- a/cita-chain/core/Cargo.toml +++ b/cita-chain/core/Cargo.toml @@ -2,6 +2,7 @@ name = "core" version = "0.1.0" authors = ["Cryptape Technologies ", "Parity Technologies "] +edition = "2018" [dependencies] byteorder = { version = "1", default-features = false } diff --git a/cita-chain/core/src/env_info.rs b/cita-chain/core/src/env_info.rs index 371af4cd1..f19178efb 100644 --- a/cita-chain/core/src/env_info.rs +++ b/cita-chain/core/src/env_info.rs @@ -14,8 +14,8 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . +use crate::header::BlockNumber; use cita_types::{Address, H256, U256}; -use header::BlockNumber; use std::sync::Arc; /// Simple vector of hashes, should be at most 256 items large, can be smaller if being used diff --git a/cita-chain/core/src/error.rs b/cita-chain/core/src/error.rs index deb22f612..541889999 100644 --- a/cita-chain/core/src/error.rs +++ b/cita-chain/core/src/error.rs @@ -16,14 +16,14 @@ //! General error types for use in ethcore. -use basic_types::LogBloom; +use crate::basic_types::LogBloom; use cita_ed25519::Error as EthkeyError; -use cita_db::TrieError; +use crate::cita_db::TrieError; +use crate::header::BlockNumber; +use crate::snapshot::error::Error as SnapshotError; use cita_types::{H256, U256, U512}; -use header::BlockNumber; use snappy; -use snapshot::error::Error as SnapshotError; use std::fmt; use util::*; diff --git a/cita-chain/core/src/filters/eth_filter.rs b/cita-chain/core/src/filters/eth_filter.rs index cd1d8ec53..68bdc04b1 100644 --- a/cita-chain/core/src/filters/eth_filter.rs +++ b/cita-chain/core/src/filters/eth_filter.rs @@ -15,11 +15,11 @@ // along with Parity. If not, see . use super::{limit_logs, PollFilter, PollId}; +use crate::libchain::chain::Chain; +use crate::types::filter::Filter as EthcoreFilter; +use crate::types::ids::BlockId; use cita_types::H256; use jsonrpc_types::rpc_types::{Filter, FilterChanges, Log}; -use libchain::chain::Chain; -use types::filter::Filter as EthcoreFilter; -use types::ids::BlockId; pub trait EthFilter { fn new_filter(&self, filter: Filter) -> PollId; diff --git a/cita-chain/core/src/lib.rs b/cita-chain/core/src/lib.rs index f2c373110..54be60040 100644 --- a/cita-chain/core/src/lib.rs +++ b/cita-chain/core/src/lib.rs @@ -58,5 +58,5 @@ pub mod error; pub mod filters; pub mod libchain; pub mod snapshot; -pub use cita_db::journaldb; -pub use types::*; +pub use crate::cita_db::journaldb; +pub use crate::types::*; diff --git a/cita-chain/core/src/libchain/chain.rs b/cita-chain/core/src/libchain/chain.rs index 976706ff5..7908664ac 100644 --- a/cita-chain/core/src/libchain/chain.rs +++ b/cita-chain/core/src/libchain/chain.rs @@ -15,49 +15,49 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use basic_types::{LogBloom, LogBloomGroup}; -use bloomchain::group::{ +use crate::basic_types::{LogBloom, LogBloomGroup}; +use crate::bloomchain::group::{ BloomGroup, BloomGroupChain, BloomGroupDatabase, GroupPosition as BloomGroupPosition, }; -use bloomchain::{Bloom, Config as BloomChainConfig, Number as BloomChainNumber}; +use crate::bloomchain::{Bloom, Config as BloomChainConfig, Number as BloomChainNumber}; +use crate::db; +use crate::db::*; pub use byteorder::{BigEndian, ByteOrder}; -use db; -use db::*; -use filters::{PollFilter, PollManager}; -use header::*; -use libchain::cache::CacheSize; -use libchain::status::Status; +use crate::filters::{PollFilter, PollManager}; +use crate::header::*; +use crate::libchain::cache::CacheSize; +use crate::libchain::status::Status; +pub use crate::types::block::*; +use crate::types::extras::*; use libproto::blockchain::{ AccountGasLimit as ProtoAccountGasLimit, Proof as ProtoProof, ProofType, RichStatus as ProtoRichStatus, StateSignal, }; -pub use types::block::*; -use types::extras::*; -use cita_db::kvdb::*; +use crate::cita_db::kvdb::*; +use crate::header::Header; +use crate::receipt::{LocalizedReceipt, Receipt}; +use crate::types::cache_manager::CacheManager; +use crate::types::filter::Filter; +use crate::types::ids::{BlockId, TransactionId}; +use crate::types::log_entry::{LocalizedLogEntry, LogEntry}; +use crate::types::transaction::{Action, SignedTransaction}; use cita_merklehash; use cita_types::traits::LowerHex; use cita_types::{Address, H256, U256}; use hashable::Hashable; -use header::Header; use libproto::executor::ExecutedResult; use libproto::router::{MsgType, RoutingKey, SubModules}; use libproto::TryInto; use libproto::{BlockTxHashes, FullTransaction, Message}; use proof::BftProof; use pubsub::channel::Sender; -use receipt::{LocalizedReceipt, Receipt}; use rlp::{self, Encodable}; use std::collections::{BTreeMap, HashMap, HashSet}; use std::convert::Into; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; -use types::cache_manager::CacheManager; -use types::filter::Filter; -use types::ids::{BlockId, TransactionId}; -use types::log_entry::{LocalizedLogEntry, LogEntry}; -use types::transaction::{Action, SignedTransaction}; use util::HeapSizeOf; use util::{Mutex, RwLock}; diff --git a/cita-chain/core/src/libchain/mod.rs b/cita-chain/core/src/libchain/mod.rs index 09115d095..d57620aa9 100644 --- a/cita-chain/core/src/libchain/mod.rs +++ b/cita-chain/core/src/libchain/mod.rs @@ -19,5 +19,5 @@ pub mod cache; pub mod chain; pub mod rich_status; pub mod status; -pub use cita_db::journaldb; -pub use types::block::*; +pub use crate::cita_db::journaldb; +pub use crate::types::block::*; diff --git a/cita-chain/core/src/snapshot/error.rs b/cita-chain/core/src/snapshot/error.rs index 2b607ef75..6d0988a47 100644 --- a/cita-chain/core/src/snapshot/error.rs +++ b/cita-chain/core/src/snapshot/error.rs @@ -18,9 +18,9 @@ use std::fmt; -use types::ids::BlockId; +use crate::types::ids::BlockId; -use cita_db::trie::TrieError; +use crate::cita_db::trie::TrieError; use cita_types::H256; use rlp::DecoderError; use snappy::SnappyError; diff --git a/cita-chain/core/src/snapshot/io.rs b/cita-chain/core/src/snapshot/io.rs index 16c2591ca..f0c44f832 100644 --- a/cita-chain/core/src/snapshot/io.rs +++ b/cita-chain/core/src/snapshot/io.rs @@ -185,7 +185,7 @@ impl PackedReader { /// Create a new `PackedReader` for the file at the given path. /// This will fail if any io errors are encountered or the file /// is not a valid packed snapshot. - pub fn create(path: &Path) -> Result, ::error::Error> { + pub fn create(path: &Path) -> Result, crate::error::Error> { let mut file = File::open(path)?; let file_len = file.metadata()?.len(); if file_len < 8 { @@ -270,7 +270,7 @@ pub struct LooseReader { impl LooseReader { /// Create a new `LooseReader` which will read the manifest and chunk data from /// the given directory. - pub fn create(mut dir: PathBuf) -> Result { + pub fn create(mut dir: PathBuf) -> Result { let mut manifest_buf = Vec::new(); dir.push("MANIFEST"); diff --git a/cita-chain/core/src/snapshot/mod.rs b/cita-chain/core/src/snapshot/mod.rs index 085789879..e81ef3785 100644 --- a/cita-chain/core/src/snapshot/mod.rs +++ b/cita-chain/core/src/snapshot/mod.rs @@ -28,7 +28,7 @@ const PREFERRED_CHUNK_SIZE: usize = 4 * 1024 * 1024; // Snappy::decompressed_len estimation may sometimes yield results greater // than PREFERRED_CHUNK_SIZE so allow some threshold here. //const MAX_CHUNK_SIZE: usize = PREFERRED_CHUNK_SIZE / 4 * 5; -use header::Header; +use crate::header::Header; use cita_types::H256; use rlp::{DecoderError, Encodable, RlpStream, UntrustedRlp}; @@ -37,31 +37,33 @@ use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; use std::time::Duration; -use cita_db::kvdb::{DBTransaction, KeyValueDB}; +use crate::cita_db::kvdb::{DBTransaction, KeyValueDB}; use hashable::Hashable; use snappy; use util::{Bytes, Mutex, BLOCKLIMIT}; -use basic_types::{LogBloom, LogBloomGroup}; -use bloomchain::group::BloomGroupChain; -use bloomchain::{Bloom, Number as BloomChainNumber}; +use crate::basic_types::{LogBloom, LogBloomGroup}; +use crate::bloomchain::group::BloomGroupChain; +use crate::bloomchain::{Bloom, Number as BloomChainNumber}; pub use self::error::Error; use self::io::SnapshotReader; use self::io::SnapshotWriter; use self::service::{Service, SnapshotService}; use super::header::BlockNumber; -use db::{CacheUpdatePolicy, Writable, COL_BODIES, COL_EXTRA, COL_HEADERS}; +use crate::db::{CacheUpdatePolicy, Writable, COL_BODIES, COL_EXTRA, COL_HEADERS}; -use types::ids::BlockId; +use crate::types::ids::BlockId; -use libchain::chain::Chain; -use types::block::{Block, BlockBody}; -use types::extras::{BlockReceipts, CurrentHash, CurrentHeight, CurrentProof, LogGroupPosition}; +use crate::libchain::chain::Chain; +use crate::types::block::{Block, BlockBody}; +use crate::types::extras::{ + BlockReceipts, CurrentHash, CurrentHeight, CurrentProof, LogGroupPosition, +}; use libproto::Proof; -use receipt::Receipt; +use crate::receipt::Receipt; //#[cfg(test)] //mod tests; @@ -443,7 +445,11 @@ impl BlockRebuilder { } /// Feed an uncompressed state chunk into the rebuilder. - pub fn feed(&mut self, chunk: &[u8], abort_flag: &AtomicBool) -> Result<(), ::error::Error> { + pub fn feed( + &mut self, + chunk: &[u8], + abort_flag: &AtomicBool, + ) -> Result<(), crate::error::Error> { let rlp = UntrustedRlp::new(chunk); let item_count = rlp.item_count()?; let num_blocks = (item_count - 2) as u64; @@ -684,7 +690,7 @@ impl BlockRebuilder { } /// Glue together any disconnected chunks and check that the chain is complete. - fn finalize(&self) -> Result<(), ::error::Error> { + fn finalize(&self) -> Result<(), crate::error::Error> { let mut batch = self.db.transaction(); let genesis_block = self diff --git a/cita-chain/core/src/snapshot/service.rs b/cita-chain/core/src/snapshot/service.rs index e422238b0..2118f64ce 100644 --- a/cita-chain/core/src/snapshot/service.rs +++ b/cita-chain/core/src/snapshot/service.rs @@ -27,18 +27,18 @@ use std::usize::MAX; use super::io::{LooseReader, LooseWriter, SnapshotReader, SnapshotWriter}; use super::{BlockRebuilder, ManifestData, RestorationStatus}; +use crate::error::Error; use cita_types::H256; -use error::Error; -use cita_db::kvdb::{Database, DatabaseConfig}; +use crate::cita_db::kvdb::{Database, DatabaseConfig}; use snappy; use util::Bytes; use util::UtilError; use util::{Mutex, RwLock, RwLockReadGuard}; -use libchain::chain::{get_chain, get_chain_body_height, Chain}; +use crate::libchain::chain::{get_chain, get_chain_body_height, Chain}; -use filters::PollManager; +use crate::filters::PollManager; /// External database restoration handler pub trait DatabaseRestore: Send + Sync { From d4c4feb4637ba0838f10d6a7cdfc08b762c8662b Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 24 Jun 2019 10:28:22 +0800 Subject: [PATCH 78/91] Chore about name of test function. [skip travis] --- cita-executor/core/src/contracts/solc/price_manager.rs | 2 +- cita-executor/core/src/contracts/solc/version_management.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cita-executor/core/src/contracts/solc/price_manager.rs b/cita-executor/core/src/contracts/solc/price_manager.rs index 8b8a6917c..030d50b7c 100644 --- a/cita-executor/core/src/contracts/solc/price_manager.rs +++ b/cita-executor/core/src/contracts/solc/price_manager.rs @@ -68,7 +68,7 @@ mod tests { use cita_types::U256; #[test] - fn test_state() { + fn test_quota_price() { let executor = init_executor(); let price_management = PriceManagement::new(&executor); let price = price_management.quota_price(BlockId::Pending).unwrap(); diff --git a/cita-executor/core/src/contracts/solc/version_management.rs b/cita-executor/core/src/contracts/solc/version_management.rs index 94c98976f..701807406 100644 --- a/cita-executor/core/src/contracts/solc/version_management.rs +++ b/cita-executor/core/src/contracts/solc/version_management.rs @@ -76,7 +76,7 @@ mod tests { use crate::types::ids::BlockId; #[test] - fn test_state() { + fn test_get_version() { let executor = init_executor(); let version_management = VersionManager::new(&executor); let version = version_management.get_version(BlockId::Pending).unwrap(); From ec2eab7dc3f2264978b6a55dc305e8ca47eff739 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 24 Jun 2019 10:41:33 +0800 Subject: [PATCH 79/91] Rename config_example to default_config. [skip travis] --- .../config_tool/{config_example => default_config}/auth.toml | 0 .../config_tool/{config_example => default_config}/chain.toml | 0 .../{config_example => default_config}/consensus.toml | 0 .../{config_example => default_config}/executor.toml | 0 .../config_tool/{config_example => default_config}/forever.toml | 0 .../{config_example => default_config}/forever_mock.toml | 0 .../config_tool/{config_example => default_config}/jsonrpc.toml | 0 scripts/create_cita_config.py | 2 +- 8 files changed, 1 insertion(+), 1 deletion(-) rename scripts/config_tool/{config_example => default_config}/auth.toml (100%) rename scripts/config_tool/{config_example => default_config}/chain.toml (100%) rename scripts/config_tool/{config_example => default_config}/consensus.toml (100%) rename scripts/config_tool/{config_example => default_config}/executor.toml (100%) rename scripts/config_tool/{config_example => default_config}/forever.toml (100%) rename scripts/config_tool/{config_example => default_config}/forever_mock.toml (100%) rename scripts/config_tool/{config_example => default_config}/jsonrpc.toml (100%) diff --git a/scripts/config_tool/config_example/auth.toml b/scripts/config_tool/default_config/auth.toml similarity index 100% rename from scripts/config_tool/config_example/auth.toml rename to scripts/config_tool/default_config/auth.toml diff --git a/scripts/config_tool/config_example/chain.toml b/scripts/config_tool/default_config/chain.toml similarity index 100% rename from scripts/config_tool/config_example/chain.toml rename to scripts/config_tool/default_config/chain.toml diff --git a/scripts/config_tool/config_example/consensus.toml b/scripts/config_tool/default_config/consensus.toml similarity index 100% rename from scripts/config_tool/config_example/consensus.toml rename to scripts/config_tool/default_config/consensus.toml diff --git a/scripts/config_tool/config_example/executor.toml b/scripts/config_tool/default_config/executor.toml similarity index 100% rename from scripts/config_tool/config_example/executor.toml rename to scripts/config_tool/default_config/executor.toml diff --git a/scripts/config_tool/config_example/forever.toml b/scripts/config_tool/default_config/forever.toml similarity index 100% rename from scripts/config_tool/config_example/forever.toml rename to scripts/config_tool/default_config/forever.toml diff --git a/scripts/config_tool/config_example/forever_mock.toml b/scripts/config_tool/default_config/forever_mock.toml similarity index 100% rename from scripts/config_tool/config_example/forever_mock.toml rename to scripts/config_tool/default_config/forever_mock.toml diff --git a/scripts/config_tool/config_example/jsonrpc.toml b/scripts/config_tool/default_config/jsonrpc.toml similarity index 100% rename from scripts/config_tool/config_example/jsonrpc.toml rename to scripts/config_tool/default_config/jsonrpc.toml diff --git a/scripts/create_cita_config.py b/scripts/create_cita_config.py index de9fa931c..5f787473c 100755 --- a/scripts/create_cita_config.py +++ b/scripts/create_cita_config.py @@ -343,7 +343,7 @@ def run_subcmd_create(args, work_dir): info = ChainInfo(args.chain_name, work_dir) info.template_create_from_arguments( args, os.path.join(work_dir, 'scripts/contracts'), - os.path.join(work_dir, 'scripts/config_tool/config_example')) + os.path.join(work_dir, 'scripts/config_tool/default_config')) info.create_init_data(args.super_admin, args.contract_arguments) info.create_genesis(args.timestamp, args.init_token, args.resource_dir) info.enable_tls = args.enable_tls From eadfd5309b5094195990a7fae28eab06d8669372 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 24 Jun 2019 15:45:52 +0800 Subject: [PATCH 80/91] Typo: editon -> edition. --- cita-executor/core/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cita-executor/core/Cargo.toml b/cita-executor/core/Cargo.toml index dd7a14365..c136610e4 100644 --- a/cita-executor/core/Cargo.toml +++ b/cita-executor/core/Cargo.toml @@ -2,7 +2,7 @@ name = "core-executor" version = "0.1.0" authors = ["Parity Technologies ", "Cryptape Technologies "] -editon = "2018" +edition = "2018" [dependencies] cita-logger = "0.1.0" From 1f643aeae17776e1cbb599e1ff0b594980764d1c Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 24 Jun 2019 16:03:34 +0800 Subject: [PATCH 81/91] Fix unit test at 2018 edition. [skip travis] --- cita-executor/core/src/tests/grpc_test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cita-executor/core/src/tests/grpc_test.rs b/cita-executor/core/src/tests/grpc_test.rs index 425bd5be6..90d04fafc 100644 --- a/cita-executor/core/src/tests/grpc_test.rs +++ b/cita-executor/core/src/tests/grpc_test.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -69,7 +69,7 @@ mod grpc_service { (*count).to_string() } "count" => { - let mut count = self.init_count.lock().unwrap(); + let count = self.init_count.lock().unwrap(); (*count).to_string() } "hello" => "hello".to_string(), From b50e57a364b228aaff203af8e42073fd1c728125 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 24 Jun 2019 15:31:19 +0800 Subject: [PATCH 82/91] Rename brake to intervention. --- cita-auth/src/block_verify.rs | 2 +- cita-chain/types/src/reserved_addresses.rs | 6 +++--- ...ncy_brake.rs => emergency_intervention.rs} | 20 +++++++++---------- cita-executor/core/src/contracts/solc/mod.rs | 6 +++--- .../contracts/solc/permission_management.rs | 6 +++--- .../core/src/libexecutor/executor.rs | 2 +- .../core/src/libexecutor/sys_config.rs | 12 +++++------ scripts/config_tool/genesis | 2 +- scripts/contracts/contracts.yml | 8 ++++---- scripts/contracts/interaction | 2 +- ...ncyBrake.sol => EmergencyIntervention.sol} | 4 ++-- tools/create-genesis/src/contracts.rs | 20 +++++++++---------- 12 files changed, 45 insertions(+), 45 deletions(-) rename cita-executor/core/src/contracts/solc/{emergency_brake.rs => emergency_intervention.rs} (78%) rename scripts/contracts/src/system/{EmergencyBrake.sol => EmergencyIntervention.sol} (72%) diff --git a/cita-auth/src/block_verify.rs b/cita-auth/src/block_verify.rs index 2bbaa4444..0a6d1c46a 100644 --- a/cita-auth/src/block_verify.rs +++ b/cita-auth/src/block_verify.rs @@ -79,7 +79,7 @@ impl<'a> BlockVerify<'a> { unimplemented!(); } - pub fn verify_emergency_brake() -> bool { + pub fn verify_emergency_intervention() -> bool { unimplemented!() } } diff --git a/cita-chain/types/src/reserved_addresses.rs b/cita-chain/types/src/reserved_addresses.rs index 40289104d..7b80bc51e 100644 --- a/cita-chain/types/src/reserved_addresses.rs +++ b/cita-chain/types/src/reserved_addresses.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -103,7 +103,7 @@ pub const GROUP_CREATOR: &str = "ffffffffffffffffffffffffffffffffff02000b"; pub const ADMIN: &str = "ffffffffffffffffffffffffffffffffff02000c"; pub const ROLE_AUTH: &str = "ffffffffffffffffffffffffffffffffff02000d"; pub const BATCH_TX: &str = "ffffffffffffffffffffffffffffffffff02000e"; -pub const EMERGENCY_BRAKE: &str = "ffffffffffffffffffffffffffffffffff02000f"; +pub const EMERGENCY_INTERVENTION: &str = "ffffffffffffffffffffffffffffffffff02000f"; pub const PRICE_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff020010"; pub const VERSION_MANAGEMENT: &str = "ffffffffffffffffffffffffffffffffff020011"; pub const ALL_GROUPS: &str = "ffffffffffffffffffffffffffffffffff020012"; @@ -130,7 +130,7 @@ pub const PERMISSION_UPDATE_NODE: &str = "ffffffffffffffffffffffffffffffffff0210 pub const PERMISSION_ACCOUNT_QUOTA: &str = "ffffffffffffffffffffffffffffffffff021023"; pub const PERMISSION_BLOCK_QUOTA: &str = "ffffffffffffffffffffffffffffffffff021024"; pub const PERMISSION_BATCH_TX: &str = "ffffffffffffffffffffffffffffffffff021025"; -pub const PERMISSION_EMERGENCY_BRAKE: &str = "ffffffffffffffffffffffffffffffffff021026"; +pub const PERMISSION_EMERGENCY_INTERVENTION: &str = "ffffffffffffffffffffffffffffffffff021026"; pub const PERMISSION_QUOTA_PRICE: &str = "ffffffffffffffffffffffffffffffffff021027"; pub const PERMISSION_VERSION: &str = "ffffffffffffffffffffffffffffffffff021028"; diff --git a/cita-executor/core/src/contracts/solc/emergency_brake.rs b/cita-executor/core/src/contracts/solc/emergency_intervention.rs similarity index 78% rename from cita-executor/core/src/contracts/solc/emergency_brake.rs rename to cita-executor/core/src/contracts/solc/emergency_intervention.rs index 777f48a58..211a5c4dc 100644 --- a/cita-executor/core/src/contracts/solc/emergency_brake.rs +++ b/cita-executor/core/src/contracts/solc/emergency_intervention.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -15,7 +15,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -//! Emergency Break +//! Emergency Intervention use std::str::FromStr; @@ -31,17 +31,17 @@ use ethabi::{decode, ParamType}; lazy_static! { static ref STATE_HASH: Vec = method_tools::encode_to_vec(b"state()"); static ref CONTRACT_ADDRESS: Address = - Address::from_str(reserved_addresses::EMERGENCY_BRAKE).unwrap(); + Address::from_str(reserved_addresses::EMERGENCY_INTERVENTION).unwrap(); } /// Configuration items from system contract -pub struct EmergencyBrake<'a> { +pub struct EmergencyIntervention<'a> { executor: &'a Executor, } -impl<'a> EmergencyBrake<'a> { +impl<'a> EmergencyIntervention<'a> { pub fn new(executor: &'a Executor) -> Self { - EmergencyBrake { executor } + EmergencyIntervention { executor } } pub fn state(&self, block_id: BlockId) -> Option { @@ -55,22 +55,22 @@ impl<'a> EmergencyBrake<'a> { } pub fn default_state() -> bool { - info!("Use default emergency break state."); + info!("Use default emergency intervention state."); false } } #[cfg(test)] mod tests { - use super::EmergencyBrake; + use super::EmergencyIntervention; use crate::tests::helpers::init_executor; use crate::types::ids::BlockId; #[test] fn test_state() { let executor = init_executor(); - let emergency_brake = EmergencyBrake::new(&executor); - let state = emergency_brake.state(BlockId::Pending).unwrap(); + let emergency_intervention = EmergencyIntervention::new(&executor); + let state = emergency_intervention.state(BlockId::Pending).unwrap(); assert_eq!(state, false); } } diff --git a/cita-executor/core/src/contracts/solc/mod.rs b/cita-executor/core/src/contracts/solc/mod.rs index ccbdfc996..f6a4fae51 100644 --- a/cita-executor/core/src/contracts/solc/mod.rs +++ b/cita-executor/core/src/contracts/solc/mod.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2017 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public @@ -19,7 +19,7 @@ pub mod admin; pub mod chain_manager; -pub mod emergency_brake; +pub mod emergency_intervention; pub mod node_manager; pub mod permission_management; pub mod price_manager; @@ -29,7 +29,7 @@ pub mod user_management; pub mod version_management; pub use self::chain_manager::ChainManagement; -pub use self::emergency_brake::EmergencyBrake; +pub use self::emergency_intervention::EmergencyIntervention; pub use self::node_manager::NodeManager; pub use self::permission_management::{PermissionManagement, Resource}; pub use self::price_manager::PriceManagement; diff --git a/cita-executor/core/src/contracts/solc/permission_management.rs b/cita-executor/core/src/contracts/solc/permission_management.rs index 623be62a9..120b91e56 100644 --- a/cita-executor/core/src/contracts/solc/permission_management.rs +++ b/cita-executor/core/src/contracts/solc/permission_management.rs @@ -327,7 +327,7 @@ mod tests { Address::from_str(reserved_addresses::PERMISSION_ACCOUNT_QUOTA).unwrap(), Address::from_str(reserved_addresses::PERMISSION_BLOCK_QUOTA).unwrap(), Address::from_str(reserved_addresses::PERMISSION_BATCH_TX).unwrap(), - Address::from_str(reserved_addresses::PERMISSION_EMERGENCY_BRAKE).unwrap(), + Address::from_str(reserved_addresses::PERMISSION_EMERGENCY_INTERVENTION).unwrap(), Address::from_str(reserved_addresses::PERMISSION_QUOTA_PRICE).unwrap(), Address::from_str(reserved_addresses::PERMISSION_VERSION).unwrap(), ]; @@ -494,9 +494,9 @@ mod tests { cont: H160::from_str(reserved_addresses::BATCH_TX).unwrap(), func: method_tools::encode_to_vec(MULTI_TXS), }, - // emergencyBrake + // emergencyIntervention Resource { - cont: H160::from_str(reserved_addresses::EMERGENCY_BRAKE).unwrap(), + cont: H160::from_str(reserved_addresses::EMERGENCY_INTERVENTION).unwrap(), func: method_tools::encode_to_vec(SET_STATE), }, // quotaPrice diff --git a/cita-executor/core/src/libexecutor/executor.rs b/cita-executor/core/src/libexecutor/executor.rs index 586903d9b..874afa13a 100644 --- a/cita-executor/core/src/libexecutor/executor.rs +++ b/cita-executor/core/src/libexecutor/executor.rs @@ -452,7 +452,7 @@ pub fn make_consensus_config(sys_config: GlobalSysConfig) -> ConsensusConfig { consensus_config.set_check_quota(sys_config.block_sys_config.check_options.quota); consensus_config.set_block_interval(sys_config.block_interval); consensus_config.set_version(sys_config.block_sys_config.chain_version); - if sys_config.emergency_brake { + if sys_config.emergency_intervention { let super_admin_account = sys_config .block_sys_config .super_admin_account diff --git a/cita-executor/core/src/libexecutor/sys_config.rs b/cita-executor/core/src/libexecutor/sys_config.rs index a53f01280..6eaf093f5 100644 --- a/cita-executor/core/src/libexecutor/sys_config.rs +++ b/cita-executor/core/src/libexecutor/sys_config.rs @@ -17,7 +17,7 @@ use super::executor::Executor; use crate::contracts::solc::{ - AccountQuotaLimit, EmergencyBrake, NodeManager, PermissionManagement, PriceManagement, + AccountQuotaLimit, EmergencyIntervention, NodeManager, PermissionManagement, PriceManagement, QuotaManager, Resource, SysConfig, UserManagement, VersionManager, AUTO_EXEC_QL_VALUE, }; use crate::libexecutor::economical_model::EconomicalModel; @@ -34,7 +34,7 @@ pub struct GlobalSysConfig { pub changed_height: usize, /// Interval time for creating a block (milliseconds) pub block_interval: u64, - pub emergency_brake: bool, + pub emergency_intervention: bool, pub block_sys_config: BlockSysConfig, } @@ -47,7 +47,7 @@ impl Default for GlobalSysConfig { delay_active_interval: 1, changed_height: 0, block_interval: 3000, - emergency_brake: false, + emergency_intervention: false, block_sys_config: BlockSysConfig::default(), } } @@ -133,10 +133,10 @@ impl GlobalSysConfig { .set_specific_quota_limit(specific); conf.changed_height = executor.get_current_height() as usize; - let emergency_manager = EmergencyBrake::new(executor); - conf.emergency_brake = emergency_manager + let emergency_manager = EmergencyIntervention::new(executor); + conf.emergency_intervention = emergency_manager .state(block_id) - .unwrap_or_else(EmergencyBrake::default_state); + .unwrap_or_else(EmergencyIntervention::default_state); let version_manager = VersionManager::new(executor); conf.block_sys_config.chain_version = version_manager diff --git a/scripts/config_tool/genesis b/scripts/config_tool/genesis index 8e99bb0f9..0ab5c9947 160000 --- a/scripts/config_tool/genesis +++ b/scripts/config_tool/genesis @@ -1 +1 @@ -Subproject commit 8e99bb0f914e7be836c725caf6a68a165e940639 +Subproject commit 0ab5c9947df48e55dfc16d2b375c5509a58d5aeb diff --git a/scripts/contracts/contracts.yml b/scripts/contracts/contracts.yml index 3092b8681..fb261855c 100644 --- a/scripts/contracts/contracts.yml +++ b/scripts/contracts/contracts.yml @@ -44,9 +44,9 @@ NormalContracts: BatchTx: address: '0xffffffffffffffffffffffffffffffffff02000e' file: system/BatchTx.sol - EmergencyBrake: + EmergencyIntervention: address: '0xffffffffffffffffffffffffffffffffff02000f' - file: system/EmergencyBrake.sol + file: system/EmergencyIntervention.sol PriceManager: address: '0xffffffffffffffffffffffffffffffffff020010' file: system/PriceManager.sol @@ -205,10 +205,10 @@ PermissionContracts: - BatchTx functions: - 'multiTxs(bytes)' - emergencyBrake: + emergencyIntervention: address: '0xffffffffffffffffffffffffffffffffff021026' contracts: - - EmergencyBrake + - EmergencyIntervention functions: - 'setState(bool)' quotaPrice: diff --git a/scripts/contracts/interaction b/scripts/contracts/interaction index 0e9339061..0be3ed1ab 160000 --- a/scripts/contracts/interaction +++ b/scripts/contracts/interaction @@ -1 +1 @@ -Subproject commit 0e93390618f988ba43de2a89264bf0055ae559a2 +Subproject commit 0be3ed1ab06e69f032c6d5b5fee0d54c108f3a0f diff --git a/scripts/contracts/src/system/EmergencyBrake.sol b/scripts/contracts/src/system/EmergencyIntervention.sol similarity index 72% rename from scripts/contracts/src/system/EmergencyBrake.sol rename to scripts/contracts/src/system/EmergencyIntervention.sol index 7067440ff..adecdfc88 100644 --- a/scripts/contracts/src/system/EmergencyBrake.sol +++ b/scripts/contracts/src/system/EmergencyIntervention.sol @@ -2,9 +2,9 @@ pragma solidity 0.4.24; import "../common/Admin.sol"; import "../common/ReservedAddrPublic.sol"; -import "../../interaction/interface/IEmergencyBrake.sol"; +import "../../interaction/interface/IEmergencyIntervention.sol"; -contract EmergencyBrake is IEmergencyBrake, ReservedAddrPublic { +contract EmergencyIntervention is IEmergencyIntervention, ReservedAddrPublic { bool public state; Admin admin = Admin(adminAddr); diff --git a/tools/create-genesis/src/contracts.rs b/tools/create-genesis/src/contracts.rs index a4a6b1929..a5835ffa4 100644 --- a/tools/create-genesis/src/contracts.rs +++ b/tools/create-genesis/src/contracts.rs @@ -70,8 +70,8 @@ pub struct NormalContracts { #[serde(rename = "BatchTx")] pub batch_tx: Info, - #[serde(rename = "EmergencyBrake")] - pub emergency_brake: Info, + #[serde(rename = "EmergencyIntervention")] + pub emergency_intervention: Info, #[serde(rename = "PriceManager")] pub price_manager: Info, @@ -104,7 +104,7 @@ impl NormalContracts { normal_contracts.insert("Admin", self.admin.clone()); normal_contracts.insert("RoleAuth", self.role_auth.clone()); normal_contracts.insert("BatchTx", self.batch_tx.clone()); - normal_contracts.insert("EmergencyBrake", self.emergency_brake.clone()); + normal_contracts.insert("EmergencyIntervention", self.emergency_intervention.clone()); normal_contracts.insert("PriceManager", self.price_manager.clone()); normal_contracts.insert("VersionManager", self.version_manager.clone()); normal_contracts.insert("AllGroups", self.all_groups.clone()); @@ -224,8 +224,8 @@ pub struct Contracts { #[serde(rename = "batchTx")] pub batch_tx: ContractsInfo, - #[serde(rename = "emergencyBrake")] - pub emergency_brake: ContractsInfo, + #[serde(rename = "emergencyIntervention")] + pub emergency_intervention: ContractsInfo, #[serde(rename = "quotaPrice")] pub quota_price: ContractsInfo, @@ -256,7 +256,7 @@ impl Contracts { contracts.insert("accountQuota", self.account_quota.clone()); contracts.insert("blockQuota", self.block_quota.clone()); contracts.insert("batchTx", self.batch_tx.clone()); - contracts.insert("emergencyBrake", self.emergency_brake.clone()); + contracts.insert("emergencyIntervention", self.emergency_intervention.clone()); contracts.insert("quotaPrice", self.quota_price.clone()); contracts.insert("version", self.version.clone()); contracts @@ -355,9 +355,9 @@ mod tests { BatchTx: address: '0xffffffffffffffffffffffffffffffffff02000e' file: system/BatchTx.sol - EmergencyBrake: + EmergencyIntervention: address: '0xffffffffffffffffffffffffffffffffff02000f' - file: system/EmergencyBrake.sol + file: system/EmergencyIntervention.sol PriceManager: address: '0xffffffffffffffffffffffffffffffffff020010' file: system/PriceManager.sol @@ -515,10 +515,10 @@ mod tests { - BatchTx functions: - 'multiTxs(bytes)' - emergencyBrake: + emergencyIntervention: address: '0xffffffffffffffffffffffffffffffffff021026' contracts: - - EmergencyBrake + - EmergencyIntervention functions: - 'setState(bool)' quotaPrice: From ba6147bddaf50f094655f0b9ba673ef049b29e1f Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 24 Jun 2019 20:43:32 +0800 Subject: [PATCH 83/91] Chore about the doc. [skip ci] --- README-CN.md | 2 +- README.md | 2 +- cita-jsonrpc/README.md | 16 ++++------------ scripts/config_tool/README.md | 7 ------- 4 files changed, 6 insertions(+), 21 deletions(-) delete mode 100755 scripts/config_tool/README.md diff --git a/README-CN.md b/README-CN.md index 148ef3ad3..22c27816c 100644 --- a/README-CN.md +++ b/README-CN.md @@ -88,7 +88,7 @@ GPLv3 license ## 权益归属 - + 秘猿科技团队 :heart: diff --git a/README.md b/README.md index 41f21ff96..5f6c31c67 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ CITA is currently under the GPLv3 license. See the LICENSE file for details. ## Credits - + CITA is created by Cryptape team with :heart:. diff --git a/cita-jsonrpc/README.md b/cita-jsonrpc/README.md index 634bcc725..3cc4111c6 100644 --- a/cita-jsonrpc/README.md +++ b/cita-jsonrpc/README.md @@ -1,19 +1,11 @@ ## JSON-RPC -[在线文档](https://cryptape.github.io/cita/zh/usage-guide/rpc/index.html) +[在线文档](https://docs.citahub.com/zh-CN/next/cita/rpc-guide/rpc) -[online doc](https://cryptape.github.io/cita/en/usage-guide/rpc/index.html) - -文档路径: `docs/docs/zh/usage-guide/rpc.md` - -Path of doc: `docs/docs/en/usage-guide/rpc.md` +[online doc](https://docs.citahub.com/en-US/next/cita/rpc-guide/rpc) ## JSON-RPC ERROR CODE -[在线文档](https://cryptape.github.io/cita/zh/usage-guide/rpc_error_code/index.html) - -[online doc](https://cryptape.github.io/cita/en/usage-guide/rpc_error_code/index.html) - -文档路径: `docs/docs/zh/usage-guide/rpc_error_code.md` +[在线文档](https://docs.citahub.com/zh-CN/next/cita/rpc-guide/rpc-error-code) -Path of doc: `docs/docs/en/usage-guide/rpc_error_code.md` +[online doc](https://docs.citahub.com/en-US/next/cita/rpc-guide/rpc-error-code) diff --git a/scripts/config_tool/README.md b/scripts/config_tool/README.md deleted file mode 100755 index ac3915a89..000000000 --- a/scripts/config_tool/README.md +++ /dev/null @@ -1,7 +0,0 @@ -[在线文档](https://cryptape.github.io/cita/zh/usage-guide/admintool/index.html) - -[online doc](https://cryptape.github.io/cita/en/usage-guide/admintool/index.html) - -文档路径: `docs/docs/zh/usage-guide/admintool.md` - -Path of doc: `docs/docs/en/usage-guide/admintool.md` From 22d762bf16da2d720c10ed4a5948b2200ca6f359 Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Tue, 25 Jun 2019 11:06:26 +0800 Subject: [PATCH 84/91] add edition 2018 --- tools/relayer-parser/Cargo.toml | 1 + tools/relayer-parser/src/communication.rs | 2 +- tools/relayer-parser/src/configuration.rs | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tools/relayer-parser/Cargo.toml b/tools/relayer-parser/Cargo.toml index f586e63bd..ad19d56f4 100644 --- a/tools/relayer-parser/Cargo.toml +++ b/tools/relayer-parser/Cargo.toml @@ -2,6 +2,7 @@ name = "cita-relayer-parser" version = "0.1.0" authors = ["Cryptape Technologies "] +edition = "2018" [dependencies] cita-logger = "0.1.0" diff --git a/tools/relayer-parser/src/communication.rs b/tools/relayer-parser/src/communication.rs index abbb59edb..13227eee3 100644 --- a/tools/relayer-parser/src/communication.rs +++ b/tools/relayer-parser/src/communication.rs @@ -25,8 +25,8 @@ use serde_json; use std::convert::Into; use tokio_core::reactor::{Core, Timeout}; +use crate::configuration::UpStream; use cita_types::{H256, U256}; -use configuration::UpStream; use jsonrpc_types::{rpc_request, rpc_types}; use libproto::blockchain::UnverifiedTransaction; diff --git a/tools/relayer-parser/src/configuration.rs b/tools/relayer-parser/src/configuration.rs index 1a97bf30a..9f0bada00 100644 --- a/tools/relayer-parser/src/configuration.rs +++ b/tools/relayer-parser/src/configuration.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public From 2910b3c3cf21779b78a4bb1dfbf7881f9266f79d Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Tue, 25 Jun 2019 11:10:22 +0800 Subject: [PATCH 85/91] remove useless extern import --- tools/relayer-parser/src/arguments.rs | 3 +-- tools/relayer-parser/src/configuration.rs | 5 ++--- tools/relayer-parser/src/main.rs | 13 ------------- 3 files changed, 3 insertions(+), 18 deletions(-) diff --git a/tools/relayer-parser/src/arguments.rs b/tools/relayer-parser/src/arguments.rs index 723187265..abd383868 100644 --- a/tools/relayer-parser/src/arguments.rs +++ b/tools/relayer-parser/src/arguments.rs @@ -15,11 +15,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use cita_types::{H256, U256}; use clap; use std::str::FromStr; -use cita_types::{H256, U256}; - pub struct AppArgs { pub cfg_file: String, pub chain_id: U256, diff --git a/tools/relayer-parser/src/configuration.rs b/tools/relayer-parser/src/configuration.rs index 9f0bada00..96880752a 100644 --- a/tools/relayer-parser/src/configuration.rs +++ b/tools/relayer-parser/src/configuration.rs @@ -15,13 +15,12 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . +use cita_crypto::PrivKey; +use cita_types::U256; use serde_json; use std::collections::HashMap; use std::time::Duration; -use cita_crypto::PrivKey; -use cita_types::U256; - #[derive(Debug, Deserialize, Clone)] pub struct UpStream { pub url: String, diff --git a/tools/relayer-parser/src/main.rs b/tools/relayer-parser/src/main.rs index 6bff5efdf..dda1fa559 100644 --- a/tools/relayer-parser/src/main.rs +++ b/tools/relayer-parser/src/main.rs @@ -15,23 +15,10 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -extern crate cita_crypto; #[macro_use] extern crate clap; -extern crate ethabi; -extern crate futures; -extern crate hyper; -extern crate parking_lot; -extern crate serde; #[macro_use] extern crate serde_derive; -extern crate serde_json; -extern crate tokio_core; - -extern crate cita_types; -extern crate core; -extern crate jsonrpc_types; -extern crate libproto; #[macro_use] extern crate cita_logger as logger; From 30b543322ef577f7df14afbb9af39907a0a1f8fb Mon Sep 17 00:00:00 2001 From: ouwenkg <2630582710@qq.com> Date: Tue, 25 Jun 2019 11:11:09 +0800 Subject: [PATCH 86/91] chores: 2018 to 2019[skip travis] --- tools/relayer-parser/src/arguments.rs | 2 +- tools/relayer-parser/src/communication.rs | 2 +- tools/relayer-parser/src/transaction.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/relayer-parser/src/arguments.rs b/tools/relayer-parser/src/arguments.rs index abd383868..bfcee20cf 100644 --- a/tools/relayer-parser/src/arguments.rs +++ b/tools/relayer-parser/src/arguments.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/tools/relayer-parser/src/communication.rs b/tools/relayer-parser/src/communication.rs index 13227eee3..59b756083 100644 --- a/tools/relayer-parser/src/communication.rs +++ b/tools/relayer-parser/src/communication.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public diff --git a/tools/relayer-parser/src/transaction.rs b/tools/relayer-parser/src/transaction.rs index d04803c27..1779cebd8 100644 --- a/tools/relayer-parser/src/transaction.rs +++ b/tools/relayer-parser/src/transaction.rs @@ -1,5 +1,5 @@ // CITA -// Copyright 2016-2018 Cryptape Technologies LLC. +// Copyright 2016-2019 Cryptape Technologies LLC. // This program is free software: you can redistribute it // and/or modify it under the terms of the GNU General Public From 4434fc21cb25f5b13dfa9eb8123493db629f318c Mon Sep 17 00:00:00 2001 From: yubo Date: Wed, 22 May 2019 16:03:48 +0800 Subject: [PATCH 87/91] modify pubsub netmsg transform network working normally on new protocol new add add retranse operation simple impl of gossip dismession add consensus topology judgement retrans and broadcast msg judgement modify retranse policy modify random select use new p2p lib fix comments modify for review add judgement for self message being retransfed modify for only retranse consensus info --- Cargo.lock | 106 ++++--- cita-network/Cargo.toml | 2 +- cita-network/src/cita_protocol.rs | 183 ++++++++---- cita-network/src/main.rs | 5 +- cita-network/src/mq_agent.rs | 1 + cita-network/src/network.rs | 8 +- cita-network/src/node_manager.rs | 347 ++++++++++++++++------ cita-network/src/p2p_protocol/mod.rs | 6 + cita-network/src/p2p_protocol/transfer.rs | 38 ++- 9 files changed, 488 insertions(+), 208 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d739a4cd8..cfd66c793 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -86,7 +86,7 @@ name = "ansi_term" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -112,6 +112,16 @@ dependencies = [ "nodrop 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "attohttpc" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "atty" version = "0.2.11" @@ -119,7 +129,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -159,7 +169,7 @@ dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -616,7 +626,7 @@ dependencies = [ "dotenv 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", "error 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.12.16 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-proto 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -688,7 +698,7 @@ dependencies = [ "serde_derive 1.0.89 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "tentacle 0.2.0-alpha.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tentacle 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "tentacle-discovery 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "util 0.6.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)", @@ -1139,7 +1149,7 @@ dependencies = [ "openssl-sys 0.9.39 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "vcpkg 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1547,7 +1557,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1678,7 +1688,7 @@ dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "slab 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1702,7 +1712,7 @@ name = "heapsize" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -1741,7 +1751,7 @@ dependencies = [ [[package]] name = "http" -version = "0.1.13" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1816,7 +1826,7 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "h2 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -2019,7 +2029,7 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2175,7 +2185,7 @@ dependencies = [ "serde_yaml 0.8.6 (registry+https://github.com/rust-lang/crates.io-index)", "thread-id 3.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2344,7 +2354,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2375,7 +2385,7 @@ dependencies = [ "mio 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.2.7 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2613,7 +2623,7 @@ dependencies = [ "rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "smallvec 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2784,7 +2794,7 @@ dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2796,7 +2806,7 @@ dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2814,7 +2824,7 @@ dependencies = [ "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2870,7 +2880,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -2883,7 +2893,7 @@ dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3021,7 +3031,7 @@ name = "remove_dir_all" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3446,24 +3456,27 @@ dependencies = [ "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "tentacle" -version = "0.2.0-alpha.14" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "flatbuffers 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "flatbuffers-verifier 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", + "igd 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "parity-multiaddr 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "tentacle-secio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-threadpool 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "tokio-yamux 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-yamux 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3479,7 +3492,7 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", - "tentacle 0.2.0-alpha.14 (registry+https://github.com/rust-lang/crates.io-index)", + "tentacle 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "tokio 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -3549,7 +3562,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3583,7 +3596,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.46 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -3854,7 +3867,7 @@ dependencies = [ [[package]] name = "tokio-yamux" -version = "0.1.10" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4112,7 +4125,7 @@ version = "2.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "same-file 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4141,7 +4154,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -4163,7 +4176,7 @@ name = "winapi-util" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -4176,7 +4189,7 @@ name = "wincolor" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -4206,6 +4219,22 @@ dependencies = [ "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "xml-rs" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "xmltree" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "yaml-rust" version = "0.4.2" @@ -4270,6 +4299,7 @@ dependencies = [ "checksum arc-swap 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "af192669a9f44d2fb63c691a04183c8e12428f34041449270b08c0456587f5a5" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" "checksum arrayvec 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "a1e964f9e24d588183fcb43503abda40d288c8657dfc27311516ce2f05675aef" +"checksum attohttpc 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eaf0ec4b0e00f61ee75556ca027485b7b354f4a714d88cc03f4468abd9378c86" "checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum authority_manage 0.1.0 (git+https://github.com/cryptape/cita-common.git?branch=develop)" = "" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" @@ -4400,7 +4430,7 @@ dependencies = [ "checksum hmac 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7a13f4163aa0c5ca1be584aace0e2212b2e41be5478218d4f657f5f778b2ae2a" "checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771" "checksum hmac-drbg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4fe727d41d2eec0a6574d887914347e5ff96a3b87177817e2a9820c5c87fecc2" -"checksum http 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "24f58e8c2d8e886055c3ead7b28793e1455270b5fb39650984c224bc538ba581" +"checksum http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "eed324f0f0daf6ec10c474f150505af2c143f251722bf9dbd1261bd1f2ee2c1a" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" "checksum httpbis 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7689cfa896b2a71da4f16206af167542b75d242b6906313e53857972a92d5614" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" @@ -4585,7 +4615,7 @@ dependencies = [ "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0" "checksum tempfile 3.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b86c784c88d98c801132806dadd3819ed29d8600836c4088e855cdf3e178ed8a" -"checksum tentacle 0.2.0-alpha.14 (registry+https://github.com/rust-lang/crates.io-index)" = "047295b0c9f01be1790d8c94f722c81ab59788e6576d3b2c5c95d44700bfce8d" +"checksum tentacle 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8dcddd2761682b538db6c0d20723a031d6beeac74d73656e5e9b54ff6cd25bed" "checksum tentacle-discovery 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "48f049945da9545ef3208a10a28a33ca64e9672dab762ad28cfc861262f9a770" "checksum tentacle-secio 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1f7e6cfc62a132bec2b68c0827dcbfbe7b54744783aeaf15219acaeb8e07e8cd" "checksum termcolor 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "4096add70612622289f2fdcdbd5086dc81c1e2675e6ae58d6c4f62a16c6d7f2f" @@ -4619,7 +4649,7 @@ dependencies = [ "checksum tokio-udp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "da941144b816d0dcda4db3a1ba87596e4df5e860a72b70783fe435891f80601c" "checksum tokio-uds 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "65ae5d255ce739e8537221ed2942e0445f4b3b813daebac1c0050ddaaa3587f9" "checksum tokio-uds 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "037ffc3ba0e12a0ab4aca92e5234e0dedeb48fddf6ccd260f1f150a36a9f2445" -"checksum tokio-yamux 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "a6b5045fcdbb9cfe770bf5a1453f28115e23023949327607ab6e78a55a23630d" +"checksum tokio-yamux 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8787adfb7b3a984b1093478895b304d7094d4de4e919655c6b0378e921f3df" "checksum toml 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "736b60249cb25337bc196faa43ee12c705e426f3d55c214d73a4e7be06f92cb4" "checksum toml 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4a2ecc31b0351ea18b3fe11274b8db6e4d82bce861bbb22e6dbed40417902c65" "checksum traitobject 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "efd1f82c56340fdf16f2a953d7bda4f8fdffba13d93b00844c25572110b26079" @@ -4657,7 +4687,7 @@ dependencies = [ "checksum want 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "797464475f30ddb8830cc529aaaae648d581f99e2036a928877dfde027ddf6b3" "checksum which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e84a603e7e0b1ce1aa1ee2b109c7be00155ce52df5081590d1ffb93f4f515cb2" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "afc5508759c5bf4285e61feb862b6083c8480aec864fa17a81fdec6f69b461ab" @@ -4665,6 +4695,8 @@ dependencies = [ "checksum wincolor 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "561ed901ae465d6185fa7864d63fbd5720d0ef718366c9a4dc83cf6170d7e9ba" "checksum ws 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "329d3e6dd450a9c5c73024e1047f0be7e24121a68484eb0b5368977bee3cf8c3" "checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +"checksum xml-rs 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3c1cb601d29fe2c2ac60a2b2e5e293994d87a1f6fa9687a31a15270f909be9c2" +"checksum xmltree 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff8eaee9d17062850f1e6163b509947969242990ee59a35801af437abe041e70" "checksum yaml-rust 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "95acf0db5515d07da9965ec0e0ba6cc2d825e2caeb7303b66ca441729801254e" "checksum yasna 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3a31ff5b5f5fcc70c5da4fcbdcbd91d541bb95b0b2517a3ca5cdc49fd3692cbb" "checksum zktx 0.0.1 (git+https://github.com/cryptape/zktx.git)" = "" diff --git a/cita-network/Cargo.toml b/cita-network/Cargo.toml index c18be746a..27b564956 100644 --- a/cita-network/Cargo.toml +++ b/cita-network/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] tentacle-discovery = "0.2.4" -tentacle = "0.2.0-alpha.14" +tentacle = "0.2.1" tokio = "0.1.14" futures = "0.1.25" cita-logger = "0.1.0" diff --git a/cita-network/src/cita_protocol.rs b/cita-network/src/cita_protocol.rs index 1cc05e59b..d509e46df 100644 --- a/cita-network/src/cita_protocol.rs +++ b/cita-network/src/cita_protocol.rs @@ -18,8 +18,8 @@ //! A multiplexed cita protocol use byteorder::{ByteOrder, NetworkEndian}; -use bytes::BufMut; -use bytes::BytesMut; +use bytes::{BufMut, Bytes, BytesMut}; +use cita_types::Address; use logger::{error, warn}; use std::str; @@ -36,8 +36,12 @@ use std::str; /// +------------------------+--------------------------+ /// | Symbol for Start | \xDEADBEEF | /// | Length of Full Payload | u32 | -/// +------------------------+--------------------------+ +/// | Version | u64 | +/// | Address | u8;20 | /// | Length of Key | u8 | +/// | TTL | u8 | +/// | Reserved | u8;2 | +/// +------------------------+--------------------------+ /// | Key | bytes of a str | /// +------------------------+--------------------------+ /// | Message | a serialize data | @@ -47,79 +51,115 @@ use std::str; // Start of network messages. const NETMSG_START: u64 = 0xDEAD_BEEF_0000_0000; -// According to CITA frame, defines its frame header length as: -// "Symbol for Start" + "Length of Full Payload" + "Length of Key", -// And this will consume "4 + 4 + 1" fixed-lengths of the frame. -pub const CITA_FRAME_HEADER_LEN: usize = 4 + 4 + 1; +/// According to CITA frame, defines its frame header length as: +/// "Symbol for Start" + "Length of Full Payload" + "Version"+ +/// "Address"+ "Length of Key"+"TTL"+"Reserved", +/// And this will consume "4 + 4 + 8 + 20 + 1 + 1+ 2" fixed-lengths of the frame. +pub const CITA_FRAME_HEADER_LEN: usize = 4 + 4 + 8 + 20 + 1 + 1 + 2; +pub const HEAD_VERSION_OFFSET: usize = 4 + 4; +pub const HEAD_ADDRESS_OFFSET: usize = 4 + 4 + 8; +pub const HEAD_KEY_LEN_OFFSET: usize = 4 + 4 + 8 + 20; +pub const HEAD_TTL_OFFSET: usize = 4 + 4 + 8 + 20 + 1; +pub const DEFAULT_TTL_NUM: u8 = 9; + +pub const CONSENSUS_STR: &str = "consensus"; + +#[derive(Debug, Clone)] +pub struct NetMessageUnit { + pub key: String, + pub data: Vec, + pub addr: Address, + pub version: u64, + pub ttl: u8, +} -fn opt_bytes_extend(buf: &mut Vec, data: &[u8]) { - buf.reserve(data.len()); - unsafe { - buf.bytes_mut()[..data.len()].copy_from_slice(data); - buf.advance_mut(data.len()); +impl NetMessageUnit { + pub fn new(key: String, data: Vec, addr: Address, version: u64, ttl: u8) -> Self { + NetMessageUnit { + key, + data, + addr, + version, + ttl, + } } } -pub fn pubsub_message_to_network_message(buf: &mut Vec, msg: Option<(String, Vec)>) { - let mut request_id_bytes = [0; 8]; - if let Some((key, body)) = msg { - let length_key = key.len(); - // Use 1 byte to store key length. - if length_key > u8::max_value() as usize { - error!("[CitaProtocol] The MQ message key is too long {}.", key); - return; - } - // Use 1 bytes to store the length for key, then store key, the last part is body. - let length_full = 1 + length_key + body.len(); - if length_full > u32::max_value() as usize { - error!( - "[CitaProtocol] The MQ message with key {} is too long {}.", - key, - body.len() - ); - return; +impl Default for NetMessageUnit { + fn default() -> Self { + NetMessageUnit { + key: String::default(), + data: Vec::new(), + addr: Address::zero(), + version: 0, + ttl: DEFAULT_TTL_NUM, } - let request_id = NETMSG_START + length_full as u64; - NetworkEndian::write_u64(&mut request_id_bytes, request_id); - opt_bytes_extend(buf, &request_id_bytes); - buf.put_u8(length_key as u8); - opt_bytes_extend(buf, key.as_bytes()); - opt_bytes_extend(buf, &body); - } else { - let request_id = NETMSG_START; - NetworkEndian::write_u64(&mut request_id_bytes, request_id); - opt_bytes_extend(buf, &request_id_bytes); } } -pub fn network_message_to_pubsub_message(buf: &mut BytesMut) -> Option<(String, Vec)> { - if buf.len() < 8 { +pub fn pubsub_message_to_network_message(info: &NetMessageUnit) -> Option { + let length_key = info.key.len(); + // Use 1 byte to store key length. + if length_key == 0 || length_key > u8::max_value() as usize { + error!( + "[CitaProtocol] The MQ message key is too long or empty {}.", + info.key + ); + return None; + } + let length_full = length_key + info.data.len(); + // Use 1 bytes to store the length for key, then store key, the last part is body. + if length_full > u32::max_value() as usize { + error!( + "[CitaProtocol] The MQ message with key {} is too long {}.", + info.key, + info.data.len() + ); + return None; + } + + let mut buf = BytesMut::with_capacity(length_full + CITA_FRAME_HEADER_LEN); + let request_id = NETMSG_START + length_full as u64; + buf.put_u64_be(request_id); + buf.put_u64_be(info.version); + buf.put(info.addr.to_vec()); + buf.put_u8(length_key as u8); + buf.put_u8(info.ttl); + buf.put_u16_be(0); + + buf.put(info.key.as_bytes()); + buf.put_slice(&info.data); + + Some(buf.into()) +} + +pub fn network_message_to_pubsub_message(buf: &mut BytesMut) -> Option { + if buf.len() < CITA_FRAME_HEADER_LEN { return None; } - let request_id = NetworkEndian::read_u64(buf.as_ref()); + let head_buf = buf.split_to(CITA_FRAME_HEADER_LEN); + + let request_id = NetworkEndian::read_u64(&head_buf); let netmsg_start = request_id & 0xffff_ffff_0000_0000; let length_full = (request_id & 0x0000_0000_ffff_ffff) as usize; if netmsg_start != NETMSG_START { return None; } - if length_full + 8 > buf.len() { + if length_full > buf.len() || length_full == 0 { return None; } - let _request_id_buf = buf.split_to(8); - if length_full == 0 { - return None; - } - let mut payload_buf = buf.split_to(length_full); + let addr = Address::from_slice(&head_buf[HEAD_ADDRESS_OFFSET..]); + let version = NetworkEndian::read_u64(&head_buf[HEAD_VERSION_OFFSET..]); - let length_key = payload_buf[0] as usize; - let _length_key_buf = payload_buf.split_to(1); + let length_key = head_buf[HEAD_KEY_LEN_OFFSET] as usize; + let ttl = head_buf[HEAD_TTL_OFFSET]; if length_key == 0 { error!("[CitaProtocol] Network message key is empty."); return None; } - if length_key > payload_buf.len() { + if length_key > buf.len() { error!( "[CitaProtocol] Buffer is not enough for key {} > {}.", length_key, @@ -127,7 +167,7 @@ pub fn network_message_to_pubsub_message(buf: &mut BytesMut) -> Option<(String, ); return None; } - let key_buf = payload_buf.split_to(length_key); + let key_buf = buf.split_to(length_key); let key_str_result = str::from_utf8(&key_buf); if key_str_result.is_err() { error!( @@ -137,35 +177,46 @@ pub fn network_message_to_pubsub_message(buf: &mut BytesMut) -> Option<(String, return None; } let key = key_str_result.unwrap().to_string(); - if length_full == 1 + length_key { + if length_full == length_key { warn!("[CitaProtocol] Network message is empty."); } - Some((key, payload_buf.to_vec())) + Some(NetMessageUnit { + key, + data: buf.to_vec(), + addr, + version, + ttl, + }) } #[cfg(test)] mod test { - use super::{network_message_to_pubsub_message, pubsub_message_to_network_message}; + use super::{ + network_message_to_pubsub_message, pubsub_message_to_network_message, NetMessageUnit, + }; use bytes::BytesMut; #[test] fn convert_empty_message() { - let mut buf = Vec::with_capacity(4 + 4); - pubsub_message_to_network_message(&mut buf, None); - let pub_msg_opt = network_message_to_pubsub_message(&mut BytesMut::from(buf)); + let buf = pubsub_message_to_network_message(&NetMessageUnit::default()); + let pub_msg_opt = network_message_to_pubsub_message(&mut BytesMut::new()); assert!(pub_msg_opt.is_none()); + assert!(buf.is_none()); } #[test] fn convert_messages() { + let mut msg = NetMessageUnit::default(); let key = "this-is-the-key".to_string(); - let msg: Vec = vec![1, 3, 5, 7, 9]; - let mut buf = Vec::with_capacity(4 + 4 + 1 + key.len() + msg.len()); - pubsub_message_to_network_message(&mut buf, Some((key.clone(), msg.clone()))); - let pub_msg_opt = network_message_to_pubsub_message(&mut BytesMut::from(buf)); + let data = vec![1, 3, 5, 7, 9]; + msg.key = key.clone(); + msg.data = data.clone(); + + let buf = pubsub_message_to_network_message(&msg).unwrap(); + let pub_msg_opt = network_message_to_pubsub_message(&mut buf.try_mut().unwrap()); assert!(pub_msg_opt.is_some()); - let (key_new, msg_new) = pub_msg_opt.unwrap(); - assert_eq!(key, key_new); - assert_eq!(msg, msg_new); + let info = pub_msg_opt.unwrap(); + assert_eq!(key, info.key); + assert_eq!(data, info.data); } } diff --git a/cita-network/src/main.rs b/cita-network/src/main.rs index 4f40b4241..fa2cd4955 100644 --- a/cita-network/src/main.rs +++ b/cita-network/src/main.rs @@ -171,7 +171,8 @@ fn main() { mq_agent.set_nodes_mgr_client(nodes_mgr.client()); mq_agent.set_network_client(network_mgr.client()); - let transfer_meta = create_transfer_meta(network_mgr.client(), nodes_mgr.client()); + let transfer_meta = + create_transfer_meta(network_mgr.client(), nodes_mgr.client(), own_addr.addr); let mut service_cfg = ServiceBuilder::default() .insert_protocol(transfer_meta) .forever(true); @@ -190,7 +191,7 @@ fn main() { }); } - if nodes_mgr.is_enable_tls() { + if config.enable_tls.unwrap_or(false) { service_cfg = service_cfg.key_pair(SecioKeyPair::secp256k1_generated()); } let mut service = service_cfg.build(SHandle::new(nodes_mgr.client())); diff --git a/cita-network/src/mq_agent.rs b/cita-network/src/mq_agent.rs index 42708c471..f88d4662d 100644 --- a/cita-network/src/mq_agent.rs +++ b/cita-network/src/mq_agent.rs @@ -66,6 +66,7 @@ impl MqAgent { "network", routing_key!([ Chain >> Status, + Chain >> RichStatus, Chain >> SyncResponse, Jsonrpc >> RequestNet, Jsonrpc >> RequestPeersInfo, diff --git a/cita-network/src/network.rs b/cita-network/src/network.rs index dd6e652ad..c118516dd 100644 --- a/cita-network/src/network.rs +++ b/cita-network/src/network.rs @@ -17,7 +17,8 @@ use crate::mq_agent::{MqAgentClient, PubMessage}; use crate::node_manager::{ - BroadcastReq, GetPeerCountReq, GetPeersInfoReq, NodesManagerClient, SingleTxReq, + BroadcastReq, DealRichStatusReq, GetPeerCountReq, GetPeersInfoReq, NodesManagerClient, + SingleTxReq, }; use crate::synchronizer::{SynchronizerClient, SynchronizerMessage}; use jsonrpc_types::rpc_types::PeersInfo; @@ -137,6 +138,11 @@ impl LocalMessage { .sync_client .handle_local_status(SynchronizerMessage::new(self.key, self.data)); } + routing_key!(Chain >> RichStatus) => { + let msg = ProtoMessage::try_from(&self.data).unwrap(); + let req = DealRichStatusReq::new(msg); + service.nodes_mgr_client.deal_rich_status(req); + } routing_key!(Chain >> SyncResponse) => { let msg = ProtoMessage::try_from(&self.data).unwrap(); send_message( diff --git a/cita-network/src/node_manager.rs b/cita-network/src/node_manager.rs index 8de3d6277..30ddfb8c2 100644 --- a/cita-network/src/node_manager.rs +++ b/cita-network/src/node_manager.rs @@ -15,16 +15,20 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::cita_protocol::{pubsub_message_to_network_message, CITA_FRAME_HEADER_LEN}; +use crate::cita_protocol::{pubsub_message_to_network_message, NetMessageUnit, CONSENSUS_STR}; use crate::config::NetConfig; use crate::p2p_protocol::transfer::TRANSFER_PROTOCOL_ID; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use cita_types::Address; use fnv::FnvHashMap as HashMap; -use libproto::{Message as ProtoMessage, TryInto}; +use libproto::routing_key; +use libproto::{ + router::{MsgType, RoutingKey, SubModules}, + Message as ProtoMessage, TryInto, +}; use notify::DebouncedEvent; use pubsub::channel::{select, tick, unbounded, Receiver, Sender}; -use rand; +use rand::{thread_rng, Rng}; use std::sync::mpsc::Receiver as StdReceiver; use std::{ collections::{BTreeMap, BTreeSet}, @@ -126,14 +130,66 @@ impl TransformAddr { } } +#[derive(Default, Debug)] +pub struct ConsensusNodeTopology { + pub linked_nodes: BTreeSet
, + pub validator_nodes: BTreeSet
, + //pub consensus_threshold_linked : bool, + pub consensus_all_linked: bool, + pub height: u64, +} + +impl ConsensusNodeTopology { + pub fn new(self_address: Address) -> ConsensusNodeTopology { + let mut top = ConsensusNodeTopology::default(); + top.linked_nodes.insert(self_address); + top + } + + fn validator_subset_linked(&self) -> bool { + self.validator_nodes.is_subset(&self.linked_nodes) + } + + pub fn update_validators(&mut self, height: u64, validators: BTreeSet
) { + if height < self.height || validators == self.validator_nodes { + debug!("No need update validator height {} self height {} validator {:?} self validator {:?}", + height,self.height,validators,self.validator_nodes); + + if height > self.height { + self.height = height; + } + return; + } + self.validator_nodes = validators; + self.consensus_all_linked = self.validator_subset_linked(); + } + + pub fn add_linked_nodes(&mut self, linked_node: Address) { + if self.linked_nodes.insert(linked_node) { + self.consensus_all_linked = self.validator_subset_linked(); + } + } + + pub fn del_linked_nodes(&mut self, linked_node: &Address) { + if self.linked_nodes.remove(linked_node) { + self.consensus_all_linked = self.validator_subset_linked(); + } + } + + pub fn consensus_all_linked(&self) -> bool { + self.consensus_all_linked + } + //pub fn consensus_threshold_linked(&self) -> bool {self.consensus_threshold_linked} +} + pub struct NodesManager { known_addrs: HashMap, config_addrs: BTreeMap>, - connected_addrs: HashMap, - pending_connected_addrs: HashMap, + connected_addrs: BTreeMap, + pending_connected_addrs: BTreeMap, - connected_peer_keys: HashMap, + connected_peer_keys: BTreeMap, check_connected_nodes: Receiver, max_connects: usize, @@ -141,27 +197,49 @@ pub struct NodesManager { nodes_manager_service_receiver: Receiver, service_ctrl: Option, peer_key: Address, - enable_tls: bool, + + gossip_key_version: HashMap, + consensus_topology: ConsensusNodeTopology, + + self_version: u64, + dialing_node: Option, self_addr: Option, } impl NodesManager { - pub fn new(known_addrs: HashMap) -> Self { - let mut node_mgr = NodesManager::default(); - node_mgr.known_addrs = known_addrs; - node_mgr + fn new(peer_key: Address) -> NodesManager { + let (tx, rx) = unbounded(); + let ticker = tick(CHECK_CONNECTED_NODES); + let client = NodesManagerClient { sender: tx }; + + // Set enable_tls = false as default. + NodesManager { + check_connected_nodes: ticker, + known_addrs: HashMap::default(), + config_addrs: BTreeMap::default(), + connected_addrs: BTreeMap::default(), + connected_peer_keys: BTreeMap::default(), + pending_connected_addrs: BTreeMap::default(), + max_connects: DEFAULT_MAX_CONNECTS, + nodes_manager_client: client, + nodes_manager_service_receiver: rx, + service_ctrl: None, + peer_key, + dialing_node: None, + self_addr: None, + gossip_key_version: HashMap::default(), + self_version: 0, + consensus_topology: ConsensusNodeTopology::new(peer_key), + } } pub fn from_config(cfg: NetConfig, key: Address) -> Self { - let mut node_mgr = NodesManager::default(); + let mut node_mgr = NodesManager::new(key); let max_connects = cfg.max_connects.unwrap_or(DEFAULT_MAX_CONNECTS); node_mgr.max_connects = max_connects; node_mgr.peer_key = key; - if let Some(enable_tls) = cfg.enable_tls { - node_mgr.enable_tls = enable_tls; - } if let Some(cfg_addrs) = cfg.peers { for addr in cfg_addrs { if let (Some(ip), Some(port)) = (addr.ip, addr.port) { @@ -247,12 +325,16 @@ impl NodesManager { // If connected node has not reach MAX, select a node from known_addrs to dial. if self.connected_addrs.len() < self.max_connects { - for (key, value) in self.known_addrs.iter_mut() { + let mut socks: Vec<_> = self.known_addrs.keys().cloned().collect(); + thread_rng().shuffle(&mut socks); + + for key in socks { + let value = self.known_addrs.get_mut(&key).unwrap(); // Node has been connected if let Some(session_id) = value.session_id { debug!( "[NodeManager] Address {:?} has been connected on : {:?}.", - *key, session_id + key, session_id ); // Node keep on line, reward KEEP_ON_LINE_SCORE. @@ -264,19 +346,8 @@ impl NodesManager { continue; } - // Give 50% probability to select this node, this design can avoid two nodes - // simultaneously dialing each other. - let selected_miss: bool = (rand::random::() % 2) != 0; - if selected_miss { - debug!( - "[NodeManager] Address {:?} selects miss in this round.", - *key - ); - continue; - } - if let Some(self_addr) = self.self_addr { - if *key == self_addr { + if key == self_addr { debug!( "[NodeManager] Trying to connected self: {:?}, skip it", self_addr @@ -289,7 +360,7 @@ impl NodesManager { if value.score < MIN_DIALING_SCORE { debug!( "[NodeManager] Address {:?} has to low score ({:?}) to dial.", - *key, value.score + key, value.score ); // The node will get time sugar, the nodes which in config file can get 2, and the @@ -304,9 +375,9 @@ impl NodesManager { // Dial this address if let Some(ref mut ctrl) = self.service_ctrl { - self.dialing_node = Some(*key); + self.dialing_node = Some(key); info!("Trying to dial: {:?}", self.dialing_node); - match ctrl.dial(socketaddr_to_multiaddr(*key), DialProtocol::All) { + match ctrl.dial(socketaddr_to_multiaddr(key), DialProtocol::All) { Ok(_) => { // Need DIALING_SCORE for every dial. value.score -= DIALING_SCORE; @@ -336,10 +407,6 @@ impl NodesManager { self.service_ctrl = Some(ctrl); } - pub fn is_enable_tls(&self) -> bool { - self.enable_tls - } - pub fn translate_address(&mut self) { for (key, value) in self.config_addrs.iter_mut() { // The address has translated. @@ -369,32 +436,6 @@ impl NodesManager { } } -impl Default for NodesManager { - fn default() -> NodesManager { - let (tx, rx) = unbounded(); - let ticker = tick(CHECK_CONNECTED_NODES); - let client = NodesManagerClient { sender: tx }; - - // Set enable_tls = false as default. - NodesManager { - check_connected_nodes: ticker, - known_addrs: HashMap::default(), - config_addrs: BTreeMap::default(), - connected_addrs: HashMap::default(), - connected_peer_keys: HashMap::default(), - pending_connected_addrs: HashMap::default(), - max_connects: DEFAULT_MAX_CONNECTS, - nodes_manager_client: client, - nodes_manager_service_receiver: rx, - service_ctrl: None, - peer_key: Address::zero(), - enable_tls: false, - dialing_node: None, - self_addr: None, - } - } -} - #[derive(Clone, Debug)] pub struct NodesManagerClient { sender: Sender, @@ -437,6 +478,10 @@ impl NodesManagerClient { self.send_req(NodesManagerMessage::Broadcast(req)); } + pub fn retrans_net_msg(&self, req: RetransNetMsgReq) { + self.send_req(NodesManagerMessage::RetransNetMsg(req)); + } + pub fn send_message(&self, req: SingleTxReq) { self.send_req(NodesManagerMessage::SingleTxReq(req)); } @@ -461,6 +506,10 @@ impl NodesManagerClient { self.send_req(NodesManagerMessage::ModifiedConfigPeers(req)); } + pub fn deal_rich_status(&self, req: DealRichStatusReq) { + self.send_req(NodesManagerMessage::DealRichStatus(req)); + } + fn send_req(&self, req: NodesManagerMessage) { if let Err(e) = self.sender.try_send(req) { warn!( @@ -479,6 +528,7 @@ pub enum NodesManagerMessage { PendingConnectedNodeReq(PendingConnectedNodeReq), DelConnectedNodeReq(DelConnectedNodeReq), Broadcast(BroadcastReq), + RetransNetMsg(RetransNetMsgReq), SingleTxReq(SingleTxReq), GetPeerCount(GetPeerCountReq), NetworkInit(NetworkInitReq), @@ -487,6 +537,7 @@ pub enum NodesManagerMessage { ConnectedSelf(ConnectedSelfReq), GetPeersInfo(GetPeersInfoReq), ModifiedConfigPeers(ModifiedConfigPeersReq), + DealRichStatus(DealRichStatusReq), } impl NodesManagerMessage { @@ -506,6 +557,8 @@ impl NodesManagerMessage { NodesManagerMessage::ConnectedSelf(req) => req.handle(service), NodesManagerMessage::GetPeersInfo(req) => req.handle(service), NodesManagerMessage::ModifiedConfigPeers(req) => req.handle(service), + NodesManagerMessage::RetransNetMsg(req) => req.handle(service), + NodesManagerMessage::DealRichStatus(req) => req.handle(service), } } } @@ -632,6 +685,9 @@ impl AddConnectedNodeReq { let _ = service .connected_peer_keys .insert(self.init_msg.peer_key, self.session_id); + service + .consensus_topology + .add_linked_nodes(self.init_msg.peer_key); info!( "[NodeManager] connected_addrs info: {:?}", @@ -665,23 +721,24 @@ impl NetworkInitReq { pub fn handle(self, service: &mut NodesManager) { let peer_key = service.peer_key; - let send_key = "network.init".to_string(); let init_msg = InitMsg { chain_id: 0, peer_key, }; - let msg_bytes: Vec = init_msg.into(); - let mut buf = Vec::with_capacity(CITA_FRAME_HEADER_LEN + send_key.len() + msg_bytes.len()); - pubsub_message_to_network_message(&mut buf, Some((send_key, msg_bytes))); + let mut msg_unit = NetMessageUnit::default(); + msg_unit.key = "network.init".to_string(); + msg_unit.data = init_msg.into(); + msg_unit.ttl = 0; - if let Some(ref mut ctrl) = service.service_ctrl { - // FIXME: handle the error! - let ret = ctrl.send_message_to(self.session_id, TRANSFER_PROTOCOL_ID, buf.into()); - info!( - "[NodeManager] Send network init message!, id: {:?}, peer_addr: {:?}, ret: {:?}", - self.session_id, peer_key, ret, - ); + if let Some(buf) = pubsub_message_to_network_message(&msg_unit) { + if let Some(ref mut ctrl) = service.service_ctrl { + let ret = ctrl.send_message_to(self.session_id, TRANSFER_PROTOCOL_ID, buf); + info!( + "[NodeManager] Send network init message!, id: {:?}, peer_addr: {:?}, ret: {:?}", + self.session_id, peer_key, ret, + ); + } } } } @@ -787,7 +844,9 @@ impl GetRandomNodesReq { } pub fn handle(self, service: &mut NodesManager) { - let addrs = service.known_addrs.keys().take(self.num).cloned().collect(); + let mut addrs: Vec<_> = service.known_addrs.keys().cloned().collect(); + thread_rng().shuffle(&mut addrs); + addrs.truncate(self.num); if let Err(e) = self.return_channel.try_send(addrs) { warn!( @@ -853,15 +912,21 @@ impl DelConnectedNodeReq { self.fix_node_status(trans_addr, service); // Remove connected peer keys - for (key, value) in service.connected_peer_keys.iter() { - if self.session_id == *value { - info!( - "[NodeManager] Remove session [{:?}] from connected_peer_keys.", - *value - ); - service.connected_peer_keys.remove(&key.clone()); - break; + let key = { + if let Some((&key, _)) = service + .connected_peer_keys + .iter() + .find(|(_, &v)| v == self.session_id) + { + Some(key) + } else { + None } + }; + + if let Some(key) = key { + service.consensus_topology.del_linked_nodes(&key); + service.connected_peer_keys.remove(&key); } } @@ -896,6 +961,84 @@ impl DelConnectedNodeReq { } } +#[derive(Debug)] +pub struct RetransNetMsgReq { + msg_unit: NetMessageUnit, + incomming_session_id: SessionId, +} + +impl RetransNetMsgReq { + pub fn new(msg_unit: NetMessageUnit, incomming_session_id: SessionId) -> Self { + RetransNetMsgReq { + msg_unit, + incomming_session_id, + } + } + + pub fn handle(mut self, service: &mut NodesManager) { + let msg_version = self.msg_unit.version; + let in_id = self.incomming_session_id; + + trace!( + "[NodeManager] RetranseReq msg.key {:?}, from session {},version {} self current version {} ttl {}", + self.msg_unit.key, + self.incomming_session_id, + msg_version, + service.self_version, + self.msg_unit.ttl, + ); + + let saved_version = service + .gossip_key_version + .entry(self.msg_unit.addr) + .or_insert(0); + if msg_version == 0 || *saved_version < msg_version { + *saved_version = msg_version; + let mut ids: Vec<_> = service.connected_addrs.keys().cloned().collect(); + ids.retain(|id| *id != in_id); + + if service.consensus_topology.consensus_all_linked + && self.msg_unit.key.contains(CONSENSUS_STR) + { + self.msg_unit.ttl = 0; + } + + if let Some(buf) = pubsub_message_to_network_message(&self.msg_unit) { + if let Some(ref mut ctrl) = service.service_ctrl { + let _ = + ctrl.filter_broadcast(TargetSession::Multi(ids), TRANSFER_PROTOCOL_ID, buf); + } + } + } + } +} + +#[derive(Debug)] +pub struct DealRichStatusReq { + msg: ProtoMessage, +} + +impl DealRichStatusReq { + pub fn new(msg: ProtoMessage) -> Self { + DealRichStatusReq { msg } + } + + pub fn handle(mut self, service: &mut NodesManager) { + let rich_status = self.msg.take_rich_status().unwrap(); + info!("DealRichStatusReq rich status {:?}", rich_status); + + let validators: BTreeSet
= rich_status + .get_validators() + .iter() + .map(|node| Address::from_slice(node)) + .collect(); + + service + .consensus_topology + .update_validators(rich_status.get_height(), validators); + } +} + #[derive(Debug)] pub struct BroadcastReq { key: String, @@ -913,12 +1056,27 @@ impl BroadcastReq { self.msg, self.key ); - let msg_bytes: Vec = self.msg.try_into().unwrap(); - let mut buf = Vec::with_capacity(CITA_FRAME_HEADER_LEN + self.key.len() + msg_bytes.len()); - pubsub_message_to_network_message(&mut buf, Some((self.key, msg_bytes))); - if let Some(ref mut ctrl) = service.service_ctrl { - let _ = ctrl.filter_broadcast(TargetSession::All, TRANSFER_PROTOCOL_ID, buf.into()); + let mut info = NetMessageUnit::default(); + info.key = self.key; + info.data = self.msg.try_into().unwrap(); + info.addr = service.peer_key; + info.version = service.self_version; + service.self_version += 1; + + let cur_status: String = routing_key!(Synchronizer >> Status).into(); + + // Synchronizer >> Status for declaring myself status,only send to neighbors + // If consensus node all be connected,consensus msg and tx msg only be sent once + // No need to resend tx info + if service.consensus_topology.consensus_all_linked() || info.key == cur_status { + info.ttl = 0; + } + + if let Some(buf) = pubsub_message_to_network_message(&info) { + if let Some(ref mut ctrl) = service.service_ctrl { + let _ = ctrl.filter_broadcast(TargetSession::All, TRANSFER_PROTOCOL_ID, buf); + } } } } @@ -941,13 +1099,16 @@ impl SingleTxReq { self.dst, self.key ); - let msg_bytes: Vec = self.msg.try_into().unwrap(); + let dst = self.dst; + let mut msg_unit = NetMessageUnit::default(); + msg_unit.key = self.key; + msg_unit.data = self.msg.try_into().unwrap(); + msg_unit.ttl = 0; - let mut buf = Vec::with_capacity(CITA_FRAME_HEADER_LEN + self.key.len() + msg_bytes.len()); - pubsub_message_to_network_message(&mut buf, Some((self.key, msg_bytes))); - if let Some(ref mut ctrl) = service.service_ctrl { - // FIXME: handle the error! - let _ = ctrl.send_message_to(self.dst, TRANSFER_PROTOCOL_ID, buf.into()); + if let Some(buf) = pubsub_message_to_network_message(&msg_unit) { + if let Some(ref mut ctrl) = service.service_ctrl { + let _ = ctrl.send_message_to(dst, TRANSFER_PROTOCOL_ID, buf); + } } } } diff --git a/cita-network/src/p2p_protocol/mod.rs b/cita-network/src/p2p_protocol/mod.rs index f711af299..4c33aa874 100644 --- a/cita-network/src/p2p_protocol/mod.rs +++ b/cita-network/src/p2p_protocol/mod.rs @@ -125,6 +125,12 @@ impl ServiceHandle for SHandle { proto_id, error ); } + ServiceError::SessionBlocked { session_context } => { + warn!( + "[P2pProtocol] ServiceError::SessionBlocked session_context {:?}", + session_context + ); + } } } diff --git a/cita-network/src/p2p_protocol/transfer.rs b/cita-network/src/p2p_protocol/transfer.rs index 4dddefdff..23ebafa60 100644 --- a/cita-network/src/p2p_protocol/transfer.rs +++ b/cita-network/src/p2p_protocol/transfer.rs @@ -15,10 +15,13 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::cita_protocol::network_message_to_pubsub_message; +use crate::cita_protocol::{network_message_to_pubsub_message, CONSENSUS_STR}; use crate::network::{NetworkClient, RemoteMessage}; -use crate::node_manager::{AddConnectedNodeReq, InitMsg, NetworkInitReq, NodesManagerClient}; +use crate::node_manager::{ + AddConnectedNodeReq, InitMsg, NetworkInitReq, NodesManagerClient, RetransNetMsgReq, +}; use bytes::BytesMut; +use cita_types::Address; use libproto::{Message as ProtoMessage, TryFrom, TryInto}; use tentacle::{ builder::MetaBuilder, @@ -40,6 +43,7 @@ struct TransferProtocol { connected_session_ids: Vec, network_client: NetworkClient, nodes_mgr_client: NodesManagerClient, + self_address: Address, } impl ServiceProtocol for TransferProtocol { @@ -79,18 +83,34 @@ impl ServiceProtocol for TransferProtocol { fn received(&mut self, env: ProtocolContextMutRef, data: bytes::Bytes) { let mut data = BytesMut::from(data); - if let Some((key, message)) = network_message_to_pubsub_message(&mut data) { - if key.eq(&"network.init".to_string()) { - let msg = InitMsg::from(message); + if let Some(mut info) = network_message_to_pubsub_message(&mut data) { + if info.key.eq(&"network.init".to_string()) { + let msg = InitMsg::from(info.data); let req = AddConnectedNodeReq::new(env.session.id, env.session.ty, msg); self.nodes_mgr_client.add_connected_node(req); return; } - let mut msg = ProtoMessage::try_from(&message).unwrap(); - msg.set_origin(env.session.id.value() as u32); + if info.addr == self.self_address { + debug!("[Transfer] Recieve myself {:?} message", info.addr); + return; + } + + let sid = env.session.id; + let mut msg = ProtoMessage::try_from(&info.data).unwrap(); + msg.set_origin(sid.value() as u32); self.network_client - .handle_remote_message(RemoteMessage::new(key, msg.try_into().unwrap())); + .handle_remote_message(RemoteMessage::new( + info.key.clone(), + msg.try_into().unwrap(), + )); + + // Now only consensus need be retransfered + if info.ttl > 0 && info.key.contains(CONSENSUS_STR) { + info.ttl -= 1; + let req = RetransNetMsgReq::new(info, sid); + self.nodes_mgr_client.retrans_net_msg(req); + } } else { warn!("[Transfer] Cannot convert network message to pubsub message!"); } @@ -100,6 +120,7 @@ impl ServiceProtocol for TransferProtocol { pub fn create_transfer_meta( network_client: NetworkClient, nodes_mgr_client: NodesManagerClient, + self_address: Address, ) -> ProtocolMeta { MetaBuilder::default() .id(TRANSFER_PROTOCOL_ID) @@ -114,6 +135,7 @@ pub fn create_transfer_meta( connected_session_ids: Vec::default(), network_client: network_client.clone(), nodes_mgr_client: nodes_mgr_client.clone(), + self_address, }); ProtocolHandle::Callback(handle) }) From ae69df3ec30896139a504bd2c707847c4a427b55 Mon Sep 17 00:00:00 2001 From: yubo Date: Tue, 25 Jun 2019 03:52:39 +0000 Subject: [PATCH 88/91] fix cargo.lock --- Cargo.lock | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index cfd66c793..26dc596ca 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1853,6 +1853,20 @@ dependencies = [ "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "igd" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "attohttpc 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "http 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "xmltree 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "impl-rlp" version = "0.2.0" @@ -4437,6 +4451,7 @@ dependencies = [ "checksum hyper 0.11.22 (git+https://github.com/cryptape/hyper.git?branch=reuse_port)" = "" "checksum hyper 0.12.16 (registry+https://github.com/rust-lang/crates.io-index)" = "0aeedb8ca5f0f96be00f84073c6d0d5f962ecad020ef543dff99a7c12717a60e" "checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" +"checksum igd 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "96f0f346ff76d5143011b2de50fbe72c3e521304868dfbd0d781b4f262a75dd5" "checksum impl-rlp 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f39b9963cf5f12fcc4ae4b30a6927ed67d6b4ea4cbe7d17a41131163b401303b" "checksum impl-serde 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7d26be4b97d738552ea423f76c4f681012ff06c3fa36fa968656b3679f60b4a1" "checksum indexmap 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7e81a7c05f79578dbc15793d8b619db9ba32b4577003ef3af1a91c416798c58d" From b596aba206ded7d5cf64b34ff9450aba1e81a603 Mon Sep 17 00:00:00 2001 From: yubo Date: Tue, 25 Jun 2019 06:46:59 +0000 Subject: [PATCH 89/91] fix for modify default ttl num --- cita-network/src/cita_protocol.rs | 3 ++- cita-network/src/node_manager.rs | 19 +++++++------------ 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/cita-network/src/cita_protocol.rs b/cita-network/src/cita_protocol.rs index d509e46df..0ad3b62c9 100644 --- a/cita-network/src/cita_protocol.rs +++ b/cita-network/src/cita_protocol.rs @@ -60,8 +60,9 @@ pub const HEAD_VERSION_OFFSET: usize = 4 + 4; pub const HEAD_ADDRESS_OFFSET: usize = 4 + 4 + 8; pub const HEAD_KEY_LEN_OFFSET: usize = 4 + 4 + 8 + 20; pub const HEAD_TTL_OFFSET: usize = 4 + 4 + 8 + 20 + 1; -pub const DEFAULT_TTL_NUM: u8 = 9; +pub const DEFAULT_TTL_NUM: u8 = 0; +pub const CONSENSUS_TTL_NUM: u8 = 9; pub const CONSENSUS_STR: &str = "consensus"; #[derive(Debug, Clone)] diff --git a/cita-network/src/node_manager.rs b/cita-network/src/node_manager.rs index 30ddfb8c2..81b81ff16 100644 --- a/cita-network/src/node_manager.rs +++ b/cita-network/src/node_manager.rs @@ -15,17 +15,15 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::cita_protocol::{pubsub_message_to_network_message, NetMessageUnit, CONSENSUS_STR}; +use crate::cita_protocol::{ + pubsub_message_to_network_message, NetMessageUnit, CONSENSUS_STR, CONSENSUS_TTL_NUM, +}; use crate::config::NetConfig; use crate::p2p_protocol::transfer::TRANSFER_PROTOCOL_ID; use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; use cita_types::Address; use fnv::FnvHashMap as HashMap; -use libproto::routing_key; -use libproto::{ - router::{MsgType, RoutingKey, SubModules}, - Message as ProtoMessage, TryInto, -}; +use libproto::{Message as ProtoMessage, TryInto}; use notify::DebouncedEvent; use pubsub::channel::{select, tick, unbounded, Receiver, Sender}; use rand::{thread_rng, Rng}; @@ -729,7 +727,6 @@ impl NetworkInitReq { let mut msg_unit = NetMessageUnit::default(); msg_unit.key = "network.init".to_string(); msg_unit.data = init_msg.into(); - msg_unit.ttl = 0; if let Some(buf) = pubsub_message_to_network_message(&msg_unit) { if let Some(ref mut ctrl) = service.service_ctrl { @@ -1064,13 +1061,12 @@ impl BroadcastReq { info.version = service.self_version; service.self_version += 1; - let cur_status: String = routing_key!(Synchronizer >> Status).into(); - + // Broadcast msg with three types: // Synchronizer >> Status for declaring myself status,only send to neighbors // If consensus node all be connected,consensus msg and tx msg only be sent once // No need to resend tx info - if service.consensus_topology.consensus_all_linked() || info.key == cur_status { - info.ttl = 0; + if !service.consensus_topology.consensus_all_linked() && info.key.contains(CONSENSUS_STR) { + info.ttl = CONSENSUS_TTL_NUM; } if let Some(buf) = pubsub_message_to_network_message(&info) { @@ -1103,7 +1099,6 @@ impl SingleTxReq { let mut msg_unit = NetMessageUnit::default(); msg_unit.key = self.key; msg_unit.data = self.msg.try_into().unwrap(); - msg_unit.ttl = 0; if let Some(buf) = pubsub_message_to_network_message(&msg_unit) { if let Some(ref mut ctrl) = service.service_ctrl { From 4e634e513d7916cabd73336c98930ddad6a7c997 Mon Sep 17 00:00:00 2001 From: kaikai1024 Date: Mon, 24 Jun 2019 11:09:38 +0800 Subject: [PATCH 90/91] Update changelog. [skip ci] --- CHANGELOG.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab84ff6ff..f617907cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,48 @@ All notable changes to this project will be documented in this file. And this pr ## [Unreleased] +### Framework + +- [Optimization] Bump Rust toolchain to `1.34.2`. [@kaikai1024] +- [Optimization] Use Rust 2018 edition. [@kaikai1024] [@ouwenkg] +- [Optimization] Use `cita-logger` crate. [@kaikai1024] + +### Network + +- [Fix] Fix the bug that save wrong session. [@leeyr338] +- [Fix] Should not unwrap on handle_remote_msg. [@leeyr338] +- [Fix] Fix the operation of repeated peer key. [@jerry-yu] +- [Feature] Add retransfer message for P2P network. [@jerry-yu] + +### System Contracts + +- [Fix] Fix the import path. [@ouwenkg] +- [Optimization] Use `protocol version` instead of version. [@kaikai1024] +- [Optimization] Rename `emergency brake` to `emergency intervention`. [@kaikai1024] + +### Tools + +- [Refactor] Rewrite the tool of creating genesis using Rust. [@ouwenkg] + +### Test + +- [Refactor] Refactor scripts of integrate test. [@kaikai1024] +- [Optimization] Add quota unit test in travisCI. [@ouwenkg] + +### Scripts + +- [Fix] Node path should not consider bin path. [@rainchen] +- [Refactor] Refactor the `cita.sh` script. [@kaikai1024] +- [Fix] Fix amend help info and latest version. [@leeyr338] +- [Optimization] Rename `config_example` to `default_config`. [@kaikai1024] + +### Doc + +- [Doc] Add file naming style doc. [@kaikai1024] +- [Doc] New CITA contents structure of CITAHub-Docs. [@kaikai1024] [@zhouyun-zoe] [@ouwenkg] [@leeyr338] [@wuyuyue] +- [Doc] Add wiki about RocksDB. [@leeyr338] +- [Doc] Update the description about `getTransactionCount`. [@ouwenkg] + ## [v0.24.1] - 2019-06-14 Fix the issue about memory leak in cita-executor. @@ -854,6 +896,7 @@ Release the first version of CITA. [@leeyr338]: https://github.com/leeyr338 [@luqz]: https://github.com/luqz [@ouwenkg]: https://github.com/ouwenkg +[@rainchen]: https://github.com/rainchen [@rev-chaos]: https://github.com/rev-chaos [@rink1969]: https://github.com/rink1969 [@u2]: https://github.com/u2 From 0b4a694211bddc1b1a92a681794b5ebb9cfd8a8c Mon Sep 17 00:00:00 2001 From: yubo Date: Tue, 25 Jun 2019 07:35:05 +0000 Subject: [PATCH 91/91] remove consensus str --- cita-network/src/node_manager.rs | 4 +--- cita-network/src/p2p_protocol/transfer.rs | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cita-network/src/node_manager.rs b/cita-network/src/node_manager.rs index 81b81ff16..af3f06723 100644 --- a/cita-network/src/node_manager.rs +++ b/cita-network/src/node_manager.rs @@ -994,9 +994,7 @@ impl RetransNetMsgReq { let mut ids: Vec<_> = service.connected_addrs.keys().cloned().collect(); ids.retain(|id| *id != in_id); - if service.consensus_topology.consensus_all_linked - && self.msg_unit.key.contains(CONSENSUS_STR) - { + if service.consensus_topology.consensus_all_linked { self.msg_unit.ttl = 0; } diff --git a/cita-network/src/p2p_protocol/transfer.rs b/cita-network/src/p2p_protocol/transfer.rs index 23ebafa60..95a13db22 100644 --- a/cita-network/src/p2p_protocol/transfer.rs +++ b/cita-network/src/p2p_protocol/transfer.rs @@ -15,7 +15,7 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use crate::cita_protocol::{network_message_to_pubsub_message, CONSENSUS_STR}; +use crate::cita_protocol::network_message_to_pubsub_message; use crate::network::{NetworkClient, RemoteMessage}; use crate::node_manager::{ AddConnectedNodeReq, InitMsg, NetworkInitReq, NodesManagerClient, RetransNetMsgReq, @@ -106,7 +106,7 @@ impl ServiceProtocol for TransferProtocol { )); // Now only consensus need be retransfered - if info.ttl > 0 && info.key.contains(CONSENSUS_STR) { + if info.ttl > 0 { info.ttl -= 1; let req = RetransNetMsgReq::new(info, sid); self.nodes_mgr_client.retrans_net_msg(req);