diff --git a/contracts/enumivo.coin/enumivo.token-transfer-rc.md b/contracts/enumivo.coin/enumivo.token-transfer-rc.md new file mode 100644 index 00000000000..9c098d20d0e --- /dev/null +++ b/contracts/enumivo.coin/enumivo.token-transfer-rc.md @@ -0,0 +1,13 @@ +## Transfer Terms & Conditions + +I, {{from}}, certify the following to be true to the best of my knowledge: + +1. I know the person(s) who transferred {{quantity}} to '{{from}}'. +2. I know the owner(s) of the '{{to}}' account. +3. I certify that {{quantity}} is not the proceeds of fraudulent or violent activities. +4. I certify that, to the best of my knowledge, {{to}} is not supporting initiation of violence against others. +5. I have disclosed any contractual terms & conditions with respect to {{quantity}} to {{to}}. + +I understand that funds transfers are not reversible after the {{transaction.delay}} seconds or other delay as configured by {{from}}'s permissions. + +If this action fails to be irreversibly confirmed after receiving goods or services from '{{to}}', I agree to either return the goods or services or resend {{quantity}} in a timely manner. diff --git a/contracts/enumivo.system/enumivo.system-buyrambytes-rc.md b/contracts/enumivo.system/enumivo.system-buyrambytes-rc.md index 3b1d248a639..63a60e83f58 100644 --- a/contracts/enumivo.system/enumivo.system-buyrambytes-rc.md +++ b/contracts/enumivo.system/enumivo.system-buyrambytes-rc.md @@ -1,19 +1,16 @@ # Action - `{{ buyrambytes }}` -This Contract is legally binding and can be used in the event of a dispute. Disputes shall be settled through the standard arbitration process established by Enumivo. - ### Description -The `{{ buyrambytes }}` action... - -### Inputs and Input Types - -The `{{ buyrambytes }}` action requires the following `inputs` and `input types`: +This action will attempt to reserve about {{bytes}} bytes of RAM on behalf of {{receiver}}. -| Action | Input | Input Type | -|:--|:--|:--| -| `{{ buyrambytes }}` | `{{ payerVar }}`
`{{ receiverVar }}`
`{{ bytesVar }}` | `{{ account_name }}`
`{{ account_name }}`
`{{ uint32 }}` | +{{buyer}} authorizes this conrtact to transfer sufficient SYS tokens to buy the RAM based upon the current price as determined by the market maker algorithm. -As an authorized party I {{ signer }} wish to buy {{ bytesVar }} bytes of RAM at the current price using the funds of {{ payerVar }} with the RAM to be owned by and be the property of {{ receiverVar }}. +{{buyer}} accepts that a 0.5% fee will be charged on the SYS spent and that the actual RAM received may be slightly less than requested due to the approximations necessary to enable this service. +{{buyer}} accepts that a 0.5% fee will be charged if and when they sell the RAM received. +{{buyer}} accepts that rounding errors resulting from limits of computational precision may result in less RAM being allocated. +{{buyer}} acknowledges that the supply of RAM may be increased at any time up to the limits of off-the-shelf computer equipment and that this may result in RAM selling for less than purchase price. +{{buyer}} acknowledges that the price of RAM may increase or decrease over time according to supply and demand. +{{buyer}} acknowledges that RAM is non-transferrable. +{{buyer}} acknowledges RAM currently in use by their account cannot be sold until it is freed and that freeing RAM may be subject to terms of other contracts. -All disputes arising from this contract shall be resolved in the Enumivo Core Arbitration Forum. diff --git a/contracts/enumivo.system/enumivo.system-clause-constitution-rc.md b/contracts/enumivo.system/enumivo.system-clause-constitution-rc.md new file mode 100644 index 00000000000..0f4057b026a --- /dev/null +++ b/contracts/enumivo.system/enumivo.system-clause-constitution-rc.md @@ -0,0 +1,58 @@ +This Constitution is a multi-party contract entered into by the Members by virtue of their use of this blockchain. + +# Article I - No Initiation of Violence +Members shall not initiate violence or the threat of violence against another Member. + +# Article II - No Perjury +Members shall be liable for losses caused by false or misleading attestations and shall forfeit any profit gained thereby. + +# Article III - Rights +The Members grant the right of contract and of private property to each other, therefore no property shall change hands except with the consent of the owner, by a valid Arbitrator’s order, or via community referendum. This Constitution creates no positive rights for or between any Members. + +# Article IV - No Vote Buying +No Member shall offer nor accept anything of value in exchange for a vote of any type, nor shall any Member unduly influence the vote of another. + +# Article V - No Fiduciary +No Member nor SYS token holder shall have fiduciary responsibility to support the value of the SYS token. The Members do not authorize anyone to hold assets, borrow, nor contract on behalf of SYS token holders collectively. This blockchain has no owners, managers or fiduciaries; therefore, no Member shall have beneficial interest in more than 10% of the SYS token supply. + +# Article VI - Restitution +Each Member agrees that penalties for breach of contract may include, but are not limited to, fines, loss of account, and other restitution. + +# Article VII - Open Source +Each Member who makes available a smart contract on this blockchain shall be a Developer. Each Developer shall offer their smart contracts via a free and open source license, and each smart contract shall be documented with a Ricardian Contract stating the intent of all parties and naming the Arbitration Forum that will resolve disputes arising from that contract. + +# Article VIII - Language +Multi-lingual contracts must specify one prevailing language in case of dispute and the author of any translation shall be liable for losses due to their false, misleading, or ambiguous attested translations. + +# Article IX - Dispute Resolution +All disputes arising out of or in connection with this Constitution shall be finally settled under the Rules of Arbitration of the International Chamber of Commerce by one or more arbitrators appointed in accordance with the said Rules. + +# Article X - Choice of Law +Choice of law for disputes shall be, in order of precedence, this Constitution and the Maxims of Equity. + +# Article XI - Amending +This Constitution and its subordinate documents shall not be amended except by a vote of the token holders with no less than 15% vote participation among tokens and no fewer than 10% more Yes than No votes, sustained for 30 continuous days within a 120 day period. + +# Article XII - Publishing +Members may only publish information to the Blockchain that is within their right to publish. Furthermore, Members voluntarily consent for all Members to permanently and irrevocably retain a copy, analyze, and distribute all broadcast transactions and derivative information. + +# Article XIII - Informed Consent +All service providers who produce tools to facilitate the construction and signing of transactions on behalf of other Members shall present to said other Members the full Ricardian contract terms of this Constitution and other referenced contracts. Service providers shall be liable for losses resulting from failure to disclose the full Ricardian contract terms to users. + +# Article XIV - Severability +If any part of this Constitution is declared unenforceable or invalid, the remainder will continue to be valid and enforceable. + +# Article XV - Termination of Agreement +A Member is automatically released from all revocable obligations under this Constitution 3 years after the last transaction signed by that Member is incorporated into the blockchain. After 3 years of inactivity an account may be put up for auction and the proceeds distributed to all Members according to the system contract provisions then in effect for such redistribution. + +# Article XVI - Developer Liability +Members agree to hold software developers harmless for unintentional mistakes made in the expression of contractual intent, whether or not said mistakes were due to actual or perceived negligence. + +# Article XVII - Consideration +All rights and obligations under this Constitution are mutual and reciprocal and of equally significant value and cost to all parties. + +# Article XVIII - Acceptance +A contract is deemed accepted when a member signs a transaction which incorporates a TAPOS proof of a block whose implied state incorporates an ABI of said contract and said transaction is incorporated into the blockchain. + +# Article XIX - Counterparts +This Constitution may be executed in any number of counterparts, each of which when executed and delivered shall constitute a duplicate original, but all counterparts together shall constitute a single agreement. diff --git a/contracts/enumivo.system/enumivo.system-regproducer-rc.md b/contracts/enumivo.system/enumivo.system-regproducer-rc.md index e28885bc780..a74472a7be0 100644 --- a/contracts/enumivo.system/enumivo.system-regproducer-rc.md +++ b/contracts/enumivo.system/enumivo.system-regproducer-rc.md @@ -1,15 +1,62 @@ # enumivo.system regproducer -This Ricardian contract for the system action *regproducer* is legally binding and can be used in the event of a dispute. +I, {{producer}}, hereby nominate myself for consideration as an elected block producer. -## regproducer - ( const account_name producer - , const public_key& producer_key - , const std::string& url - , uint16_t location ); +If {{producer}} is selected to produce blocks by the enumivo contract, I will sign blocks with {{producer_key}} and I hereby attest that I will keep this key secret and secure. -_Intent: create a producer-config and producer-info object for 'producer'_ +If {{producer}} is unable to perform obligations under this contract I will resign my position by resubmitting this contract with the null producer key. -As an authorized party I {{ signer }} wish to register a producer candidate named {{ account_name }} and identified with {{ producer_key }} located at {{ url }} and located at {{ location }}. +I acknowledge that a block is 'objectively valid' if it conforms to the deterministic blockchain rules in force at the time of its creation, and is 'objectively invalid' if it fails to conform to those rules. -All disputes arising from this contract shall be resolved in the Enumivo Core Arbitration Forum. +{{producer}} hereby agrees to only use {{producer_key}} to sign messages under the following scenarios: + +1. proposing an objectively valid block at the time appointed by the block scheduling algorithm +2. pre-confirming a block produced by another producer in the schedule when I find said block objectively valid +3. confirming a block for which {{producer}} has received 2/3+ pre-confirmation messages from other producers + +I hereby accept liability for any and all provable damages that result from my: + +1. signing two different block proposals with the same timestamp with {{producer_key} +2. signing two different block proposals with the same block number with {{producer_key} +3. signing any block proposal which builds off of an objectively invalid block +4. signing a pre-confirmation for an objectively invalid block +5. signing a confirmation for a block for which I do not possess pre-confirmation messages from 2/3+ other producers + +I hereby agree that double-signing for a timestamp or block number in concert with 2 or more other producers shall automatically be deemed malicious and subject to a fine equal to the past year of compensation received and imediate disqualification from being a producer, and other damages. An exception may be made if {{producer}} can demonstrate that the double-signing occured due to a bug in the reference software; the burden of proof is on {{producer}}. + +I hereby agree not to interfere with the producer election process. I agree to process all producer election transactions that occur in blocks I create, to sign all objectively valid blocks I create that contain election transactions, and to sign all pre-confirmations and confirmations necessary to facilitate transfer of control to the next set of producers as determined by the system contract. + +I hereby acknowledge that 2/3+ other elected producers may vote to disqualify {{producer}} in the event {{producer}} is unable to produce blocks or is unable to be reached, according to criteria agreed to among producers. + +If {{producer}} qualifies for and chooses to collect compensation due to votes received, {{producer}} will provide a public endpoint allowing at least 100 peers to maintain synchronization with the blockchain and/or submit transactions to be included. {{producer}} shall maintain at least 1 validating node with full state and signature checking and shall report any objectively invalid blocks produced by the active block producers. Reporting shall be via a method to be agreed to among producers, said method and reports to be made public. + +The community agrees to allow {{producer}} to authenticate peers as necessary to prevent abuse and denial of service attacks; however, {{producer}} agrees not to discriminate against non-abusive peers. + +I agree to process transactions on a FIFO best-effort basis and to honestly bill transactions for measured execution time. + +I {{producer}} agree not to manipulate the contents of blocks in order to derive profit from: + +1. the order in which transactions are included +2. the hash of the block that is produced + +I, {{producer}}, hereby agree to disclose and attest under penalty of perjury all ultimate beneficial owners of my company who own more than 1%. + +I, {{producer}}, hereby agree to cooperate with other block producers to carry out our respective and mutual obligations under this agreement, including but not limited to maintaining network stability and a valid blockchain. + +I, {{producer}}, agree to maintain a website hosted at {{url}} which contains up-to-date information on all disclosures required by this contract. + +I, {{producer}}, agree to set {{location}} such that {{producer}} is scheduled with minimal latency between my previous and next peer. + +I, {{producer}}, agree to maintain time synchronization within 10 ms of global atomic clock time, using a method agreed to among producers. + +I, {{producer}}, agree not to produce blocks before my scheduled time unless I have received all blocks produced by the prior producer. + +I, {{producer}}, agree not to publish blocks with timestamps more than 500ms in the future unless the prior block is more than 75% full by either CPU or network bandwidth metrics. + +I, {{producer}}, agree not to set the RAM supply to more RAM than my nodes contain and to resign if I am unable to provide the RAM approved by 2/3+ producers, as shown in the system parameters. + +## Constitution + +This agreement incorporates the current blockchain constitution: + +{{constitution}} diff --git a/contracts/enumivo.system/enumivo.system-setcode-rc.md b/contracts/enumivo.system/enumivo.system-setcode-rc.md index 3f83be131f4..5a0d7217a84 100644 --- a/contracts/enumivo.system/enumivo.system-setcode-rc.md +++ b/contracts/enumivo.system/enumivo.system-setcode-rc.md @@ -1,19 +1,12 @@ # Action - `{{ setcode }}` -This Contract is legally binding and can be used in the event of a dispute. - ### Description -The intention of the `{{ setcode }}` action is to load a smart contract into memory and make it available for execution. - -### Inputs and Input Types - -The `{{ setcode }}` action requires the following `inputs` and `input types`: - -| Action | Input | Input Type | -|:--|:--|:--| -| `{{ setcode }}` | `{{ accountVar }}`
`{{ vmtypeVar }}`
`{{ vmversionVar }}`
`{{ codeVar }}` | `{{ account_name }}`
`{{ uint8 }}`
`{{ uint8 }}`
`{{ bytes }}` | +This action updates the code that will run in response to delivered actions. It may be performed by the account upon which the code is being deployed. -As an authorized party I {{ signer }} wish to store in memory owned by {{ accountVar }} the code {{ codeVar }} which shall use VM Type {{ vmtypeVar }} version {{ vmversionVar }}. +By deploying this code you certify that: -All disputes arising from this contract shall be resolved in the Enumivo Core Arbitration Forum. +1. the code is not malicious +2. you are authorized to perform the actions automated by the code +3. the code is consistant with the ABI deployed and intent of the contract +4. updates to the code are consistant with the prior code's intent diff --git a/contracts/enumivo.system/enumivo.system-setram-rc.md b/contracts/enumivo.system/enumivo.system-setram-rc.md index 39de26fdfa8..e9a3ce66572 100644 --- a/contracts/enumivo.system/enumivo.system-setram-rc.md +++ b/contracts/enumivo.system/enumivo.system-setram-rc.md @@ -1,19 +1,8 @@ # Action - `{{ setram }}` -This Contract is legally binding and can be used in the event of a dispute. - ### Description -The intent of the `{{ setram }}` action is ... - -### Input and Input Type - -The `{{ setram }}` action requires the following `input` and `input type`: - -| Action | Input | Input Type | -|:--|:--|:--| -| `{{ setram }}` | `{{ max_ram_sizeVar }}` | `{{ uint64 }}` | - -As an authorized party I {{ signer }} wish to UNKNOWN +This action sets the total RAM that may be allocated for use by accounts. It may only increase. -All disputes arising from this contract shall be resolved in the Enumivo Core Arbitration Forum. +Only the controller of this contract may update the RAM availablity. If the owner is a multi-sig collective, the +parties to the multi-sig each certify that off-the-shelf machines exist capable of supporting the available RAM. diff --git a/contracts/enumivo.system/enumivo.system-unregprod-rc.md b/contracts/enumivo.system/enumivo.system-unregprod-rc.md index 2337f28cd67..be04a2e47e0 100644 --- a/contracts/enumivo.system/enumivo.system-unregprod-rc.md +++ b/contracts/enumivo.system/enumivo.system-unregprod-rc.md @@ -1,7 +1,5 @@ # Action - `{{ unregprod }}` -This Contract is legally binding and can be used in the event of a dispute. - ### Description The `{{ unregprod }}` action... diff --git a/contracts/enumivo.system/enumivo.system.abi b/contracts/enumivo.system/enumivo.system.abi index ba55397d0ef..d91d024233f 100644 --- a/contracts/enumivo.system/enumivo.system.abi +++ b/contracts/enumivo.system/enumivo.system.abi @@ -242,27 +242,20 @@ {"name":"max_authority_depth", "type":"uint16"} ] - },{ - "name": "enumivo_parameters", - "base": "blockchain_parameters", - "fields": [ - {"name":"max_ram_size", "type":"uint64"} - ] },{ "name": "enumivo_global_state", - "base": "enumivo_parameters", + "base": "blockchain_parameters", "fields": [ + {"name":"max_ram_size", "type":"uint64"}, {"name":"total_ram_bytes_reserved", "type":"uint64"}, {"name":"total_ram_stake", "type":"int64"}, {"name":"last_producer_schedule_update", "type":"time_point_sec"}, {"name":"last_pervote_bucket_fill", "type":"uint64"}, {"name":"pervote_bucket", "type":"int64"}, {"name":"perblock_bucket", "type":"int64"}, - {"name":"savings", "type":"int64"}, {"name":"total_unpaid_blocks", "type":"uint32"}, {"name":"total_activated_stake", "type":"int64"}, {"name":"thresh_activated_stake_time", "type":"uint64"}, - {"name":"last_producer_schedule_id", "type":"checksum160"}, {"name":"last_producer_schedule_size", "type":"uint16"}, {"name":"total_producer_vote_weight", "type":"float64"}, {"name":"last_name_close", "type":"block_timestamp_type"} @@ -271,16 +264,14 @@ "name": "producer_info", "base": "", "fields": [ - {"name":"owner", "type":"account_name"}, - {"name":"total_votes", "type":"float64"}, - {"name":"producer_key", "type":"public_key"}, - {"name":"is_active", "type":"bool"}, - {"name":"url", "type":"string"}, - {"name":"unpaid_blocks", "type":"uint32"}, - {"name":"last_claim_time", "type":"uint64"}, - {"name":"location", "type":"uint16"}, - {"name":"time_became_active", "type":"uint32"}, - {"name":"last_produced_block_time", "type":"uint32"} + {"name":"owner", "type":"account_name"}, + {"name":"total_votes", "type":"float64"}, + {"name":"producer_key", "type":"public_key"}, + {"name":"is_active", "type":"bool"}, + {"name":"url", "type":"string"}, + {"name":"unpaid_blocks", "type":"uint32"}, + {"name":"last_claim_time", "type":"uint64"}, + {"name":"location", "type":"uint16"} ] },{ "name": "regproducer", @@ -346,6 +337,12 @@ {"name":"account", "type":"account_name"}, {"name":"is_priv", "type":"int8"} ] + },{ + "name": "rmvproducer", + "base": "", + "fields": [ + {"name":"producer", "type":"account_name"} + ] },{ "name": "set_account_limits", "base": "", @@ -384,7 +381,22 @@ "name": "setparams", "base": "", "fields": [ - {"name":"params", "type":"enumivo_parameters"} + {"name":"params", "type":"blockchain_parameters"} + ] + },{ + "name": "connector", + "base": "", + "fields": [ + {"name":"balance", "type":"asset"}, + {"name":"weight", "type":"float64"} + ] + },{ + "name": "exchange_state", + "base": "", + "fields": [ + {"name":"supply", "type":"asset"}, + {"name":"base", "type":"connector"}, + {"name":"quote", "type":"connector"} ] } ], @@ -480,6 +492,10 @@ "name": "setpriv", "type": "setpriv", "ricardian_contract": "" + },{ + "name": "rmvproducer", + "type": "rmvproducer", + "ricardian_contract": "" },{ "name": "setalimits", "type": "set_account_limits", @@ -525,18 +541,18 @@ "index_type": "i64", "key_names" : ["owner"], "key_types" : ["uint64"] - },{ - "name": "totalband", - "type": "total_resources", - "index_type": "i64", - "key_names" : ["owner"], - "key_types" : ["uint64"] },{ "name": "delband", "type": "delegated_bandwidth", "index_type": "i64", "key_names" : ["to"], "key_types" : ["uint64"] + },{ + "name": "rammarket", + "type": "exchange_state", + "index_type": "i64", + "key_names" : ["supply"], + "key_types" : ["uint64"] },{ "name": "refunds", "type": "refund_request", diff --git a/contracts/enumivo.system/enumivo.system.cpp b/contracts/enumivo.system/enumivo.system.cpp index d035b673f46..7bf86eb35d8 100644 --- a/contracts/enumivo.system/enumivo.system.cpp +++ b/contracts/enumivo.system/enumivo.system.cpp @@ -73,11 +73,27 @@ namespace enumivosystem { _global.set( _gstate, _self ); } + void system_contract::setparams( const enumivo::blockchain_parameters& params ) { + require_auth( N(enumivo) ); + (enumivo::blockchain_parameters&)(_gstate) = params; + enumivo_assert( 3 <= _gstate.max_authority_depth, "max_authority_depth should be at least 3" ); + set_blockchain_parameters( params ); + } + void system_contract::setpriv( account_name account, uint8_t ispriv ) { require_auth( _self ); set_privileged( account, ispriv ); } + void system_contract::rmvproducer( account_name producer ) { + require_auth( _self ); + auto prod = _producers.find( producer ); + enumivo_assert( prod != _producers.end(), "producer not found" ); + _producers.modify( prod, 0, [&](auto& p) { + p.deactivate(); + }); + } + void system_contract::bidname( account_name bidder, account_name newname, asset bid ) { require_auth( bidder ); enumivo_assert( enumivo::name_suffix(newname) == newname, "you can only bid on top-level suffix" ); @@ -165,30 +181,18 @@ namespace enumivosystem { set_resource_limits( newact, 0, 0, 0 ); } - void system_contract::setparams( const enumivo_parameters& params ) { - require_auth( N(enumivo) ); - (enumivosystem::enumivo_parameters&)(_gstate) = params; - enumivo_assert( 3 <= _gstate.max_authority_depth, "max_authority_depth should be at least 3" ); - set_blockchain_parameters( params ); - } - } /// enumivo.system ENUMIVO_ABI( enumivosystem::system_contract, - (setram) - // delegate_bandwith.cpp - (delegatebw)(undelegatebw)(refund) - (buyram)(buyrambytes)(sellram) + // native.hpp (newaccount definition is actually in enumivo.system.cpp) + (newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(canceldelay)(onerror) + // enumivo.system.cpp + (setram)(setparams)(setpriv)(rmvproducer)(bidname) + // delegate_bandwidth.cpp + (buyrambytes)(buyram)(sellram)(delegatebw)(undelegatebw)(refund) // voting.cpp + (regproducer)(unregprod)(voteproducer)(regproxy) // producer_pay.cpp - (regproxy)(regproducer)(unregprod)(voteproducer) - (claimrewards) - // native.hpp - (onblock) - (newaccount)(updateauth)(deleteauth)(linkauth)(unlinkauth)(postrecovery)(passrecovery)(vetorecovery)(onerror)(canceldelay) - //this file - (bidname) - (setpriv) - (setparams) + (onblock)(claimrewards) ) diff --git a/contracts/enumivo.system/enumivo.system.hpp b/contracts/enumivo.system/enumivo.system.hpp index c683730bba9..555542fe553 100644 --- a/contracts/enumivo.system/enumivo.system.hpp +++ b/contracts/enumivo.system/enumivo.system.hpp @@ -20,13 +20,6 @@ namespace enumivosystem { using enumivo::const_mem_fun; using enumivo::block_timestamp; - struct enumivo_parameters : enumivo::blockchain_parameters { - uint64_t max_ram_size = 64ll*1024 * 1024 * 1024; - - // explicit serialization macro is not necessary, used here only to improve compilation time - ENULIB_SERIALIZE_DERIVED( enumivo_parameters, enumivo::blockchain_parameters, (max_ram_size) ) - }; - struct name_bid { account_name newname; account_name high_bidder; @@ -42,11 +35,10 @@ namespace enumivosystem { > name_bid_table; - - - struct enumivo_global_state : enumivo_parameters { + struct enumivo_global_state : enumivo::blockchain_parameters { uint64_t free_ram()const { return max_ram_size - total_ram_bytes_reserved; } + uint64_t max_ram_size = 64ll*1024 * 1024 * 1024; uint64_t total_ram_bytes_reserved = 0; int64_t total_ram_stake = 0; @@ -54,20 +46,19 @@ namespace enumivosystem { uint64_t last_pervote_bucket_fill = 0; int64_t pervote_bucket = 0; int64_t perblock_bucket = 0; - int64_t savings = 0; uint32_t total_unpaid_blocks = 0; /// all blocks which have been produced but not paid int64_t total_activated_stake = 0; uint64_t thresh_activated_stake_time = 0; - checksum160 last_producer_schedule_id; uint16_t last_producer_schedule_size = 0; double total_producer_vote_weight = 0; /// the sum of all producer votes block_timestamp last_name_close; // explicit serialization macro is not necessary, used here only to improve compilation time - ENULIB_SERIALIZE_DERIVED( enumivo_global_state, enumivo_parameters, (total_ram_bytes_reserved)(total_ram_stake) + ENULIB_SERIALIZE_DERIVED( enumivo_global_state, enumivo::blockchain_parameters, + (max_ram_size)(total_ram_bytes_reserved)(total_ram_stake) (last_producer_schedule_update)(last_pervote_bucket_fill) - (pervote_bucket)(perblock_bucket)(savings)(total_unpaid_blocks)(total_activated_stake)(thresh_activated_stake_time) - (last_producer_schedule_id)(last_producer_schedule_size)(total_producer_vote_weight)(last_name_close) ) + (pervote_bucket)(perblock_bucket)(total_unpaid_blocks)(total_activated_stake)(thresh_activated_stake_time) + (last_producer_schedule_size)(total_producer_vote_weight)(last_name_close) ) }; struct producer_info { @@ -79,8 +70,6 @@ namespace enumivosystem { uint32_t unpaid_blocks = 0; uint64_t last_claim_time = 0; uint16_t location = 0; - block_timestamp time_became_active; - block_timestamp last_produced_block_time; uint64_t primary_key()const { return owner; } double by_votes()const { return is_active ? -total_votes : total_votes; } @@ -89,8 +78,7 @@ namespace enumivosystem { // explicit serialization macro is not necessary, used here only to improve compilation time ENULIB_SERIALIZE( producer_info, (owner)(total_votes)(producer_key)(is_active)(url) - (unpaid_blocks)(last_claim_time)(location) - (time_became_active)(last_produced_block_time) ) + (unpaid_blocks)(last_claim_time)(location) ) }; struct voter_info { @@ -157,7 +145,7 @@ namespace enumivosystem { // functions defined in delegate_bandwidth.cpp /** - * Stakes ENU from the balance of 'from' for the benfit of 'receiver'. + * Stakes ENU from the balance of 'from' for the benfit of 'receiver'. * If transfer == true, then 'receiver' can unstake to their account * Else 'from' can unstake at any time. */ @@ -171,7 +159,7 @@ namespace enumivosystem { * left to delegate. * * This will cause an immediate reduction in net/cpu bandwidth of the - * receiver. + * receiver. * * A transaction is scheduled to send the tokens back to 'from' after * the staking period has passed. If existing transaction is scheduled, it @@ -217,13 +205,15 @@ namespace enumivosystem { void regproxy( const account_name proxy, bool isproxy ); - void setparams( const enumivo_parameters& params ); + void setparams( const enumivo::blockchain_parameters& params ); // functions defined in producer_pay.cpp void claimrewards( const account_name& owner ); void setpriv( account_name account, uint8_t ispriv ); + void rmvproducer( account_name producer ); + void bidname( account_name bidder, account_name newname, asset bid ); private: void update_elected_producers( block_timestamp timestamp ); diff --git a/contracts/enumivo.system/native.hpp b/contracts/enumivo.system/native.hpp index 96c7d4f8ecd..da4b6dde122 100644 --- a/contracts/enumivo.system/native.hpp +++ b/contracts/enumivo.system/native.hpp @@ -79,7 +79,7 @@ namespace enumivosystem { * * 2. new accounts must stake a minimal number of tokens (as set in system parameters) * therefore, this method will execute an inline buyram from receiver for newacnt in - * an amount equal to the current new account creation fee. + * an amount equal to the current new account creation fee. */ void newaccount( account_name creator, account_name newact @@ -104,18 +104,9 @@ namespace enumivosystem { account_name code, action_name type*/ ) {} - void postrecovery( /*account_name account, - const authority& data, - const std::string& memo*/ ) {} - - void passrecovery( /*account_name account*/ ) {} - - void vetorecovery( /*account_name account*/ ) {} - - void onerror( /*const bytes&*/ ) {} - void canceldelay( /*permission_level canceling_auth, transaction_id_type trx_id*/ ) {} + void onerror( /*const bytes&*/ ) {} }; } diff --git a/contracts/enumivo.system/producer_pay.cpp b/contracts/enumivo.system/producer_pay.cpp index a32d260cfbb..94153e677fc 100644 --- a/contracts/enumivo.system/producer_pay.cpp +++ b/contracts/enumivo.system/producer_pay.cpp @@ -39,7 +39,6 @@ namespace enumivosystem { _gstate.total_unpaid_blocks++; _producers.modify( prod, 0, [&](auto& p ) { p.unpaid_blocks++; - p.last_produced_block_time = timestamp; }); } @@ -103,7 +102,6 @@ namespace enumivosystem { _gstate.pervote_bucket += to_per_vote_pay; _gstate.perblock_bucket += to_per_block_pay; - _gstate.savings += to_savings; _gstate.last_pervote_bucket_fill = ct; } diff --git a/contracts/enumivo.system/voting.cpp b/contracts/enumivo.system/voting.cpp index cfa2d399fb4..254c43d622b 100644 --- a/contracts/enumivo.system/voting.cpp +++ b/contracts/enumivo.system/voting.cpp @@ -80,30 +80,7 @@ namespace enumivosystem { std::vector< std::pair > top_producers; top_producers.reserve(21); - std::vector inactive_iters; for ( auto it = idx.cbegin(); it != idx.cend() && top_producers.size() < 21 && 0 < it->total_votes && it->active(); ++it ) { - - /** - If it's the first time or it's been over a day since a producer was last voted in, - update his info. Otherwise, a producer gets a grace period of 7 hours after which - he gets deactivated if he hasn't produced in 24 hours. - */ - if ( it->time_became_active.slot == 0 || - block_time.slot > it->time_became_active.slot + 23 * blocks_per_hour ) { - _producers.modify( *it, 0, [&](auto& p) { - p.time_became_active = block_time; - }); - } else if ( block_time.slot > (2 * 21 * 12 * 100) + it->time_became_active.slot && - block_time.slot > it->last_produced_block_time.slot + blocks_per_day ) { - // save producers that will be deactivated - inactive_iters.push_back(it); - continue; - } else { - _producers.modify( *it, 0, [&](auto& p) { - p.time_became_active = block_time; - }); - } - top_producers.emplace_back( std::pair({{it->owner, it->producer_key}, it->location}) ); } @@ -111,13 +88,6 @@ namespace enumivosystem { return; } - for ( const auto& it: inactive_iters ) { - _producers.modify( *it, 0, [&](auto& p) { - p.deactivate(); - p.time_became_active.slot = 0; - }); - } - /// sort by producer name std::sort( top_producers.begin(), top_producers.end() ); @@ -128,15 +98,10 @@ namespace enumivosystem { producers.push_back(item.first); bytes packed_schedule = pack(producers); - checksum160 new_id; - sha1( packed_schedule.data(), packed_schedule.size(), &new_id ); - if( new_id != _gstate.last_producer_schedule_id ) { - _gstate.last_producer_schedule_id = new_id; - set_proposed_producers( packed_schedule.data(), packed_schedule.size() ); + if( set_proposed_producers( packed_schedule.data(), packed_schedule.size() ) >= 0 ) { _gstate.last_producer_schedule_size = top_producers.size(); } - _gstate.last_producer_schedule_update = block_time; } double stake2vote( int64_t staked ) { diff --git a/enumivo_build.sh b/enumivo_build.sh index 454074380cf..8f5c4bedf2d 100755 --- a/enumivo_build.sh +++ b/enumivo_build.sh @@ -143,6 +143,7 @@ export LLVM_DIR=${HOME}/opt/wasm/lib/cmake/llvm export CMAKE=${HOME}/opt/cmake/bin/cmake export PATH=${HOME}/opt/mongodb/bin:$PATH + export BOOST_ROOT="${HOME}/opt/boost" ;; "CentOS Linux") FILE="${PWD}/scripts/enumivo_build_centos.sh" @@ -152,6 +153,7 @@ export LLVM_DIR=${HOME}/opt/wasm/lib/cmake/llvm export CMAKE=${HOME}/opt/cmake/bin/cmake export PATH=${HOME}/opt/mongodb/bin:$PATH + export BOOST_ROOT="${HOME}/opt/boost_1_67_0" ;; "elementary OS") FILE="${PWD}/scripts/enumivo_build_ubuntu.sh" @@ -159,6 +161,7 @@ C_COMPILER=clang-4.0 MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf export PATH=${HOME}/opt/mongodb/bin:$PATH + export BOOST_ROOT="${HOME}/opt/boost_1_67_0" ;; "Fedora") FILE="${PWD}/scripts/enumivo_build_fedora.sh" @@ -166,6 +169,7 @@ C_COMPILER=gcc MONGOD_CONF=/etc/mongod.conf export LLVM_DIR=${HOME}/opt/wasm/lib/cmake/llvm + export BOOST_ROOT="${HOME}/opt/boost_1_67_0" ;; "Linux Mint") FILE="${PWD}/scripts/enumivo_build_ubuntu.sh" @@ -173,6 +177,7 @@ C_COMPILER=clang-4.0 MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf export PATH=${HOME}/opt/mongodb/bin:$PATH + export BOOST_ROOT="${HOME}/opt/boost_1_67_0" ;; "Ubuntu") FILE="${PWD}/scripts/enumivo_build_ubuntu.sh" @@ -180,13 +185,13 @@ C_COMPILER=clang-4.0 MONGOD_CONF=${HOME}/opt/mongodb/mongod.conf export PATH=${HOME}/opt/mongodb/bin:$PATH + export BOOST_ROOT="${HOME}/opt/boost_1_67_0" ;; *) printf "\\n\\tUnsupported Linux Distribution. Exiting now.\\n\\n" exit 1 esac - export BOOST_ROOT="${HOME}/opt/boost_1_67_0" OPENSSL_ROOT_DIR=/usr/include/openssl WASM_ROOT="${HOME}/opt/wasm" fi diff --git a/governance/bp_agreement.md b/governance/bp_agreement.md deleted file mode 100644 index 2ac0dc88526..00000000000 --- a/governance/bp_agreement.md +++ /dev/null @@ -1,23 +0,0 @@ -# The Block Producer Agreement -As a Block Producer (BP), I/we promise to: - -1. Produce exactly the authorized number of blocks faithfully, accurately, at the appointed time in the rotation -2. Never produce and sign two or more blocks with the same block height or block interval -3. Never censor governance related transactions such as votes or Arbitration related transactions -4. Only add "good" transactions from the transaction pool to the block -5. Make a good faith effort to include as many "good" transactions as possible to the block without undue discrimination -6. Exclude "bad" transactions from the block, and publish why they were excluded -7. Show no favoritism among transactions, ordering them in a FIFO fashion or using some other ordering mechanism that is declared publicly in advance, including the default ordering provided by the unmodified software -8. Refrain from using my/our superior information to "front run" transactions nor enabling anyone else to “front run” -9. Accept as valid any Arbitrator’s order that’s - 1. signed by an Arbitrator - 2. that the chain shows was assigned to a Case, - 3. such that the order affects only the Accounts named in that Case, and - 4. the Arbitrator is in good standing with their Arbitration Forum, and - 5. the original Transaction that gave rise to the Case names that Arbitration Forum as the venue for dispute resolution -10. Only freeze accounts when authorized to do so by a valid Arbitrator’s order -11. Always file a dispute against myself/ourselves after taking initiative to act on an emergency -12. Provide at least four (4) public endpoints running full nodes (the Minimum Configuration) -13. Not requesting my/our daily Vote Bonus pay on days when I/we don’t have the Minimum Configuration running, and repaying any Vote Bonus income collected while the Minimum Configuration wasn’t running -14. Disclosing all ownership of my/our organization greater than 10% -15. Not sharing more than 10% ownership with another BP diff --git a/libraries/chain/webassembly/binaryen.cpp b/libraries/chain/webassembly/binaryen.cpp index 84d7aee2671..d506e04d31a 100644 --- a/libraries/chain/webassembly/binaryen.cpp +++ b/libraries/chain/webassembly/binaryen.cpp @@ -73,7 +73,7 @@ std::unique_ptr binaryen_runtime::instantiat table.resize(module->table.initial); for (auto& segment : module->table.segments) { Address offset = ConstantExpressionRunner(globals).visit(segment.offset).value.geti32(); - FC_ASSERT(offset + segment.data.size() <= module->table.initial); + FC_ASSERT( uint64_t(offset) + segment.data.size() <= module->table.initial); for (size_t i = 0; i != segment.data.size(); ++i) { table[offset + i] = segment.data[i]; } diff --git a/plugins/chain_plugin/chain_plugin.cpp b/plugins/chain_plugin/chain_plugin.cpp index d362a5be7f1..d6e3d209415 100644 --- a/plugins/chain_plugin/chain_plugin.cpp +++ b/plugins/chain_plugin/chain_plugin.cpp @@ -970,7 +970,11 @@ read_only::abi_bin_to_json_result read_only::abi_bin_to_json( const read_only::a read_only::get_required_keys_result read_only::get_required_keys( const get_required_keys_params& params )const { transaction pretty_input; - from_variant(params.transaction, pretty_input); + auto resolver = make_resolver(this); + try { + abi_serializer::from_variant(params.transaction, pretty_input, resolver); + } ENU_RETHROW_EXCEPTIONS(chain::transaction_type_exception, "Invalid transaction") + auto required_keys_set = db.get_authorization_manager().get_required_keys(pretty_input, params.available_keys); get_required_keys_result result; result.required_keys = required_keys_set; diff --git a/plugins/net_plugin/net_plugin.cpp b/plugins/net_plugin/net_plugin.cpp index 860bee30cb3..74fcd7d2fbe 100644 --- a/plugins/net_plugin/net_plugin.cpp +++ b/plugins/net_plugin/net_plugin.cpp @@ -1943,7 +1943,7 @@ namespace enumivo { c->socket->async_connect( current_endpoint, [weak_conn, endpoint_itr, this] ( const boost::system::error_code& err ) { auto c = weak_conn.lock(); if (!c) return; - if( !err ) { + if( !err && c->socket->is_open() ) { start_session( c ); c->send_handshake (); } else { @@ -1988,7 +1988,8 @@ namespace enumivo { if(conn->socket->is_open()) { if (conn->peer_addr.empty()) { visitors++; - if (paddr == conn->socket->remote_endpoint().address().to_v4()) { + boost::system::error_code ec; + if (paddr == conn->socket->remote_endpoint(ec).address().to_v4()) { from_addr++; } } diff --git a/plugins/producer_plugin/producer_plugin.cpp b/plugins/producer_plugin/producer_plugin.cpp index c80e2246c25..69db53ce2b3 100644 --- a/plugins/producer_plugin/producer_plugin.cpp +++ b/plugins/producer_plugin/producer_plugin.cpp @@ -685,7 +685,7 @@ producer_plugin_impl::start_block_result producer_plugin_impl::start_block() { } else if ( _pause_production ) { elog("Not producing block because production is explicitly paused"); _pending_block_mode = pending_block_mode::speculating; - } else if ( irreversible_block_age >= _max_irreversible_block_age_us ) { + } else if ( _max_irreversible_block_age_us.count() >= 0 && irreversible_block_age >= _max_irreversible_block_age_us ) { elog("Not producing block because the irreversible block is too old [age:${age}s, max:${max}s]", ("age", irreversible_block_age.count() / 1'000'000)( "max", _max_irreversible_block_age_us.count() / 1'000'000 )); _pending_block_mode = pending_block_mode::speculating; } diff --git a/plugins/wallet_api_plugin/wallet_api_plugin.cpp b/plugins/wallet_api_plugin/wallet_api_plugin.cpp index 5b4e54dbab3..3e33d318dbb 100644 --- a/plugins/wallet_api_plugin/wallet_api_plugin.cpp +++ b/plugins/wallet_api_plugin/wallet_api_plugin.cpp @@ -91,7 +91,7 @@ void wallet_api_plugin::plugin_startup() { CALL(wallet, wallet_mgr, list_wallets, INVOKE_R_V(wallet_mgr, list_wallets), 200), CALL(wallet, wallet_mgr, list_keys, - INVOKE_R_V(wallet_mgr, list_keys), 200), + INVOKE_R_R_R(wallet_mgr, list_keys, std::string, std::string), 200), CALL(wallet, wallet_mgr, get_public_keys, INVOKE_R_V(wallet_mgr, get_public_keys), 200) }); diff --git a/plugins/wallet_plugin/include/enumivo/wallet_plugin/wallet.hpp b/plugins/wallet_plugin/include/enumivo/wallet_plugin/wallet.hpp index c0c6e7e2616..68b942af3e9 100644 --- a/plugins/wallet_plugin/include/enumivo/wallet_plugin/wallet.hpp +++ b/plugins/wallet_plugin/include/enumivo/wallet_plugin/wallet.hpp @@ -91,6 +91,15 @@ class wallet_api */ void unlock(string password); + /** Checks the password of the wallet + * + * Validates the password on a wallet even if the wallet is already unlocked, + * throws if bad password given. + * @param password the password previously set with \c set_password() + * @ingroup Wallet Management + */ + void check_password(string password); + /** Sets a new password on the wallet. * * The wallet must be either 'new' or 'unlocked' to diff --git a/plugins/wallet_plugin/include/enumivo/wallet_plugin/wallet_manager.hpp b/plugins/wallet_plugin/include/enumivo/wallet_plugin/wallet_manager.hpp index aebe59e523d..0fe39ce462f 100644 --- a/plugins/wallet_plugin/include/enumivo/wallet_plugin/wallet_manager.hpp +++ b/plugins/wallet_plugin/include/enumivo/wallet_plugin/wallet_manager.hpp @@ -69,8 +69,8 @@ class wallet_manager { /// @return A list of wallet names with " *" appended if the wallet is unlocked. std::vector list_wallets(); - /// @return A list of private keys from all unlocked wallets in wif format. - map list_keys(); + /// @return A list of private keys from a wallet provided password is correct to said wallet + map list_keys(const string& name, const string& pw); /// @return A set of public keys from all unlocked wallets, use with chain_controller::get_required_keys. flat_set get_public_keys(); diff --git a/plugins/wallet_plugin/wallet.cpp b/plugins/wallet_plugin/wallet.cpp index 54038973bf2..981f4f5d96d 100644 --- a/plugins/wallet_plugin/wallet.cpp +++ b/plugins/wallet_plugin/wallet.cpp @@ -327,6 +327,16 @@ void wallet_api::unlock(string password) } ENU_RETHROW_EXCEPTIONS(chain::wallet_invalid_password_exception, "Invalid password for wallet: \"${wallet_name}\"", ("wallet_name", get_wallet_filename())) } +void wallet_api::check_password(string password) +{ try { + FC_ASSERT(password.size() > 0); + auto pw = fc::sha512::hash(password.c_str(), password.size()); + vector decrypted = fc::aes_decrypt(pw, my->_wallet.cipher_keys); + auto pk = fc::raw::unpack(decrypted); + FC_ASSERT(pk.checksum == pw); +} ENU_RETHROW_EXCEPTIONS(chain::wallet_invalid_password_exception, + "Invalid password for wallet: \"${wallet_name}\"", ("wallet_name", get_wallet_filename())) } + void wallet_api::set_password( string password ) { if( !is_new() ) diff --git a/plugins/wallet_plugin/wallet_manager.cpp b/plugins/wallet_plugin/wallet_manager.cpp index d3aba261063..4606598d264 100644 --- a/plugins/wallet_plugin/wallet_manager.cpp +++ b/plugins/wallet_plugin/wallet_manager.cpp @@ -95,18 +95,16 @@ std::vector wallet_manager::list_wallets() { return result; } -map wallet_manager::list_keys() { +map wallet_manager::list_keys(const string& name, const string& pw) { check_timeout(); - map result; - for (const auto& i : wallets) { - if (!i.second->is_locked()) { - const auto& keys = i.second->list_keys(); - for (const auto& i : keys) { - result[i.first] = i.second; - } - } - } - return result; + + if (wallets.count(name) == 0) + ENU_THROW(chain::wallet_nonexistent_exception, "Wallet not found: ${w}", ("w", name)); + auto& w = wallets.at(name); + if (w->is_locked()) + ENU_THROW(chain::wallet_locked_exception, "Wallet is locked: ${w}", ("w", name)); + w->check_password(pw); //throws if bad password + return w->list_keys(); } flat_set wallet_manager::get_public_keys() { diff --git a/programs/enucli/main.cpp b/programs/enucli/main.cpp index ae125fa479b..af599206de9 100644 --- a/programs/enucli/main.cpp +++ b/programs/enucli/main.cpp @@ -2115,12 +2115,31 @@ int main( int argc, char** argv ) { }); // list keys - auto listKeys = wallet->add_subcommand("keys", localized("List of private keys from all unlocked wallets in wif format."), false); + auto listKeys = wallet->add_subcommand("keys", localized("List of public keys from all unlocked wallets."), false); listKeys->set_callback([] { // wait for enuwallet to come up try_port(uint16_t(std::stoi(parse_url(wallet_url).port)), 2000); - const auto& v = call(wallet_url, wallet_list_keys); + const auto& v = call(wallet_url, wallet_public_keys); + std::cout << fc::json::to_pretty_string(v) << std::endl; + }); + + // list private keys + auto listPrivKeys = wallet->add_subcommand("private_keys", localized("List of private keys from an unlocked wallet in wif or PVT_R1 format."), false); + listPrivKeys->add_option("-n,--name", wallet_name, localized("The name of the wallet to list keys from"), true); + listPrivKeys->add_option("--password", wallet_pw, localized("The password returned by wallet create")); + listPrivKeys->set_callback([&wallet_name, &wallet_pw] { + if( wallet_pw.size() == 0 ) { + std::cout << localized("password: "); + fc::set_console_echo(false); + std::getline( std::cin, wallet_pw, '\n' ); + fc::set_console_echo(true); + } + // wait for enuwallet to come up + try_port(uint16_t(std::stoi(parse_url(wallet_url).port)), 2000); + + fc::variants vs = {fc::variant(wallet_name), fc::variant(wallet_pw)}; + const auto& v = call(wallet_url, wallet_list_keys, vs); std::cout << fc::json::to_pretty_string(v) << std::endl; }); diff --git a/programs/enulauncher/main.cpp b/programs/enulauncher/main.cpp index 040b3d89e4f..c31746d049a 100644 --- a/programs/enulauncher/main.cpp +++ b/programs/enulauncher/main.cpp @@ -978,7 +978,6 @@ launcher_def::write_config_file (tn_node_def &node) { exit (-1); } - cfg << "genesis-json = " << host->genesis << "\n"; cfg << "blocks-dir = " << block_dir << "\n"; cfg << "readonly = 0\n"; cfg << "send-whole-blocks = true\n"; @@ -1462,6 +1461,7 @@ launcher_def::launch (enudaemon_def &instance, string >s) { } enudaemoncmd += " --config-dir " + instance.config_dir_name + " --data-dir " + instance.data_dir_name; + enudaemoncmd += " --genesis-json " + genesis.string(); if (gts.length()) { enudaemoncmd += " --genesis-timestamp " + gts; } diff --git a/scripts/enumivo_build_amazon.sh b/scripts/enumivo_build_amazon.sh index 61f6809481e..2946a452337 100644 --- a/scripts/enumivo_build_amazon.sh +++ b/scripts/enumivo_build_amazon.sh @@ -211,6 +211,23 @@ printf "\\tCMAKE found @ %s.\\n" "${CMAKE}" fi + if [ -d "${HOME}/opt/boost_1_67_0" ]; then + if ! mv "${HOME}/opt/boost_1_67_0" "$BOOST_ROOT" + then + printf "\\n\\tUnable to move directory ${HOME}/opt/boost_1_67_0 to ${BOOST_ROOT}.\\n" + printf "\\n\\tExiting now.\\n" + exit 1 + fi + if [ -d "$BUILD_DIR" ]; then + if ! rm -rf "$BUILD_DIR" + then + printf "\\tUnable to remove directory %s. Please remove this directory and run this script %s again. 0\\n" "$BUILD_DIR" "${BASH_SOURCE[0]}" + printf "\\tExiting now.\\n\\n" + exit 1; + fi + fi + fi + printf "\\n\\tChecking boost library installation.\\n" BVERSION=$( grep "BOOST_LIB_VERSION" "${BOOST_ROOT}/include/boost/version.hpp" 2>/dev/null \ | tail -1 | tr -s ' ' | cut -d\ -f3 | sed 's/[^0-9\._]//gI' ) @@ -280,9 +297,9 @@ exit 1; fi fi - printf "\\tBoost successfully installed @ %s/opt/boost_1_67_0.\\n" "${HOME}" + printf "\\tBoost successfully installed @ %s.\\n" "${BOOST_ROOT}" else - printf "\\tBoost 1.67.0 found at %s/opt/boost_1_67_0.\\n" "${HOME}" + printf "\\tBoost 1.67.0 found at %s.\\n" "${BOOST_ROOT}" fi printf "\\n\\tChecking MongoDB installation.\\n" diff --git a/tests/distributed-transactions-remote-test.py b/tests/distributed-transactions-remote-test.py index 0ef27774849..172a13c72aa 100755 --- a/tests/distributed-transactions-remote-test.py +++ b/tests/distributed-transactions-remote-test.py @@ -22,6 +22,7 @@ def errorExit(msg="", errorCode=1): parser.add_argument("--dump-error-details", help="Upon error print etc/enumivo/node_*/config.ini and var/lib/node_*/stderr.log to stdout", action='store_true') +parser.add_argument("--kill-all", help="Kill all enunode and enuwallet instances", action='store_true') args = parser.parse_args() pnodes=args.p @@ -29,6 +30,7 @@ def errorExit(msg="", errorCode=1): debug=args.v dontKill=args.dont_kill dumpErrorDetails=args.dump_error_details +killAll=args.kill_all testUtils.Utils.Debug=debug @@ -58,7 +60,7 @@ def errorExit(msg="", errorCode=1): (fd, nodesFile) = tempfile.mkstemp() try: Print("BEGIN") - cluster.killall() + cluster.killall(allInstances=killAll) cluster.cleanup() Print ("producing nodes: %s, non-producing nodes: %d, topology: %s, delay between nodes launch(seconds): %d" % @@ -98,7 +100,7 @@ def errorExit(msg="", errorCode=1): if killEnuInstances: Print("Shut down the cluster and cleanup.") - cluster.killall() + cluster.killall(allInstances=killAll) cluster.cleanup() exit(0) diff --git a/tests/distributed-transactions-test.py b/tests/distributed-transactions-test.py index 344d2a28b10..d1844a23df9 100755 --- a/tests/distributed-transactions-test.py +++ b/tests/distributed-transactions-test.py @@ -25,6 +25,7 @@ def errorExit(msg="", errorCode=1): parser.add_argument("--dump-error-details", help="Upon error print etc/enumivo/node_*/config.ini and var/lib/node_*/stderr.log to stdout", action='store_true') +parser.add_argument("--kill-all", help="Kill all enunode and enuwallet instances", action='store_true') args = parser.parse_args() pnodes=args.p @@ -36,6 +37,7 @@ def errorExit(msg="", errorCode=1): seed=args.seed dontKill=args.dont_kill dumpErrorDetails=args.dump_error_details +killAll=args.kill_all killWallet=not dontKill killEnuInstances=not dontKill @@ -60,9 +62,9 @@ def errorExit(msg="", errorCode=1): errorExit("Failed to initilize nodes from Json string.") total_nodes=len(cluster.getNodes()) else: - cluster.killall() + cluster.killall(allInstances=killAll) cluster.cleanup() - walletMgr.killall() + walletMgr.killall(allInstances=killAll) walletMgr.cleanup() Print ("producing nodes: %s, non-producing nodes: %d, topology: %s, delay between nodes launch(seconds): %d" % @@ -77,8 +79,8 @@ def errorExit(msg="", errorCode=1): if not cluster.waitOnClusterBlockNumSync(3): errorExit("Cluster never stabilized") - Print("Stand up enuwallet") - walletMgr.killall() + Print("Stand up ENU wallet enuwallet") + walletMgr.killall(allInstances=killAll) walletMgr.cleanup() if walletMgr.launch() is False: errorExit("Failed to stand up enuwallet.") @@ -116,11 +118,11 @@ def errorExit(msg="", errorCode=1): if killEnuInstances: Print("Shut down the cluster and cleanup.") - cluster.killall() + cluster.killall(allInstances=killAll) cluster.cleanup() if killWallet: Print("Shut down the wallet and cleanup.") - walletMgr.killall() + walletMgr.killall(allInstances=killAll) walletMgr.cleanup() exit(0) diff --git a/tests/enunode_run_remote_test.py b/tests/enunode_run_remote_test.py index 2557c55d06b..53a5c23e489 100755 --- a/tests/enunode_run_remote_test.py +++ b/tests/enunode_run_remote_test.py @@ -18,12 +18,14 @@ def errorExit(msg="", errorCode=1): parser.add_argument("--dump-error-details", help="Upon error print etc/enumivo/node_*/config.ini and var/lib/node_*/stderr.log to stdout", action='store_true') +parser.add_argument("--kill-all", help="Kill all enunode and enuwallet instances", action='store_true') args = parser.parse_args() debug=args.v dontKill=args.dont_kill dumpErrorDetails=args.dump_error_details onlyBios=args.only_bios +killAll=args.kill_all testUtils.Utils.Debug=debug @@ -39,7 +41,7 @@ def errorExit(msg="", errorCode=1): cluster=testUtils.Cluster() try: Print("BEGIN") - cluster.killall() + cluster.killall(allInstances=killAll) cluster.cleanup() Print ("producing nodes: %s, non-producing nodes: %d, topology: %s, delay between nodes launch(seconds): %d" % @@ -76,7 +78,7 @@ def errorExit(msg="", errorCode=1): if killEnuInstances: Print("Shut down the cluster and cleanup.") - cluster.killall() + cluster.killall(allInstances=killAll) cluster.cleanup() exit(0) diff --git a/tests/enunode_run_test.py b/tests/enunode_run_test.py index d216101b62f..23653770450 100755 --- a/tests/enunode_run_test.py +++ b/tests/enunode_run_test.py @@ -51,6 +51,7 @@ def cmdError(name, cmdCode=0, exitNow=False): parser.add_argument("-v", help="verbose logging", action='store_true') parser.add_argument("--dont-kill", help="Leave cluster running after test finishes", action='store_true') parser.add_argument("--only-bios", help="Limit testing to bios node.", action='store_true') +parser.add_argument("--kill-all", help="Kill all enunode and enuwallet instances", action='store_true') args = parser.parse_args() testOutputFile=args.output @@ -66,6 +67,7 @@ def cmdError(name, cmdCode=0, exitNow=False): dontKill=args.dont_kill prodCount=args.prod_count onlyBios=args.only_bios +killAll=args.kill_all testUtils.Utils.Debug=debug localTest=True if server == LOCAL_HOST else False @@ -88,11 +90,11 @@ def cmdError(name, cmdCode=0, exitNow=False): if enableMongo and not cluster.isMongodDbRunning(): errorExit("MongoDb doesn't seem to be running.") - walletMgr.killall() + walletMgr.killall(allInstances=killAll) walletMgr.cleanup() if localTest and not dontLaunch: - cluster.killall() + cluster.killall(allInstances=killAll) cluster.cleanup() Print("Stand up cluster") if cluster.launch(prodCount=prodCount, onlyBios=onlyBios, dontKill=dontKill) is False: @@ -129,7 +131,7 @@ def cmdError(name, cmdCode=0, exitNow=False): exchangeAccount.ownerPublicKey=PUB_KEY2 Print("Stand up walletd") - walletMgr.killall() + walletMgr.killall(allInstances=killAll) walletMgr.cleanup() if walletMgr.launch() is False: cmdError("%s" % (WalletdName)) @@ -192,7 +194,7 @@ def cmdError(name, cmdCode=0, exitNow=False): errorExit("Unexpected wallet list: %s" % (wallets)) Print("Getting wallet keys.") - actualKeys=walletMgr.getKeys() + actualKeys=walletMgr.getKeys(testWallet) expectedkeys=[] for account in accounts: expectedkeys.append(account.ownerPrivateKey) @@ -217,7 +219,7 @@ def cmdError(name, cmdCode=0, exitNow=False): errorExit("Failed to unlock wallet %s" % (testWallet.name)) Print("Getting wallet keys.") - actualKeys=walletMgr.getKeys() + actualKeys=walletMgr.getKeys(defproduceraWallet) expectedkeys=[defproduceraAccount.ownerPrivateKey] noMatch=list(set(expectedkeys) - set(actualKeys)) if len(noMatch) > 0: @@ -700,14 +702,14 @@ def cmdError(name, cmdCode=0, exitNow=False): if killEnuInstances: Print("Shut down the cluster.") - cluster.killall() + cluster.killall(allInstances=killAll) if testSuccessful and not keepLogs: Print("Cleanup cluster data.") cluster.cleanup() if killWallet: Print("Shut down the wallet.") - walletMgr.killall() + walletMgr.killall(allInstances=killAll) if testSuccessful and not keepLogs: Print("Cleanup wallet data.") walletMgr.cleanup() diff --git a/tests/restart-scenarios-test.py b/tests/restart-scenarios-test.py index 54fc8125f6f..f5f0520e4af 100755 --- a/tests/restart-scenarios-test.py +++ b/tests/restart-scenarios-test.py @@ -44,6 +44,7 @@ def errorExit(msg="", errorCode=1): action='store_true') parser.add_argument("--keep-logs", help="Don't delete var/lib/node_* folders upon test completion", action='store_true') +parser.add_argument("--kill-all", help="Kill all enunode and enuwallet instances", action='store_true') args = parser.parse_args() pnodes=args.p @@ -57,6 +58,7 @@ def errorExit(msg="", errorCode=1): killEnuInstances= not args.dont_kill dumpErrorDetails=args.dump_error_details keepLogs=args.keep_logs +killAll=args.kill_all seed=1 testUtils.Utils.Debug=debug @@ -71,7 +73,7 @@ def errorExit(msg="", errorCode=1): cluster.setChainStrategy(chainSyncStrategyStr) cluster.setWalletMgr(walletMgr) - cluster.killall() + cluster.killall(allInstances=killAll) cluster.cleanup() Print ("producing nodes: %d, topology: %s, delay between nodes launch(seconds): %d, chain sync strategy: %s" % ( @@ -87,7 +89,7 @@ def errorExit(msg="", errorCode=1): errorExit("Cluster never stabilized") Print("Stand up ENU wallet enuwallet") - walletMgr.killall() + walletMgr.killall(allInstances=killAll) walletMgr.cleanup() if walletMgr.launch() is False: errorExit("Failed to stand up enuwallet.") @@ -173,8 +175,8 @@ def errorExit(msg="", errorCode=1): if killEnuInstances: Print("Shut down the cluster%s" % (" and cleanup." if (testSuccessful and not keepLogs) else ".")) - cluster.killall() - walletMgr.killall() + cluster.killall(allInstances=killAll) + walletMgr.killall(allInstances=killAll) if testSuccessful and not keepLogs: Print("Cleanup cluster and wallet data.") cluster.cleanup() diff --git a/tests/testUtils.py b/tests/testUtils.py index 337efa9efd9..731076fb1ca 100755 --- a/tests/testUtils.py +++ b/tests/testUtils.py @@ -1272,17 +1272,17 @@ def getOpenWallets(self): return wallets - def getKeys(self): + def getKeys(self, wallet): keys=[] p = re.compile(r'\n\s+\"(\w+)\"\n', re.MULTILINE) - cmd="%s %s wallet keys" % (Utils.EnuClientPath, self.endpointArgs) + cmd="%s %s wallet private_keys --name %s --password %s " % (Utils.EnuClientPath, self.endpointArgs, wallet.name, wallet.password) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) retStr=subprocess.check_output(cmd.split()).decode("utf-8") #Utils.Print("retStr: %s" % (retStr)) m=p.findall(retStr) if m is None: - Utils.Print("ERROR: wallet keys parser failure") + Utils.Print("ERROR: wallet private_keys parser failure") return None keys=m @@ -1297,11 +1297,22 @@ def dumpErrorDetails(self): with open(WalletMgr.__walletLogFile, "r") as f: shutil.copyfileobj(f, sys.stdout) - @staticmethod - def killall(): - cmd="pkill -9 %s" % (Utils.EnuWalletName) - if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) - subprocess.call(cmd.split()) + # @staticmethod + # def killall(): + # cmd="pkill -9 %s" % (Utils.EnuWalletName) + # if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) + # subprocess.call(cmd.split()) + + def killall(self, allInstances=False): + """Kill enuwallet instances. allInstances will kill all enuwallet instances running on the system.""" + if self.__walletPid: + os.kill(self.__walletPid, signal.SIGKILL) + + if allInstances: + cmd="pkill -9 %s" % (Utils.EnuWalletName) + if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) + subprocess.call(cmd.split()) + @staticmethod def cleanup(): @@ -2210,17 +2221,19 @@ def dumpErrorDetails(self): fileName="var/lib/node_%02d/stderr.txt" % (i) Cluster.dumpErrorDetailImpl(fileName) - def killall(self, silent=True): - cmd="%s -k 15" % (Utils.EnuLauncherPath) + def killall(self, silent=True, allInstances=False): + """Kill cluster enunode instances. allInstances will kill all enunode instances running on the system.""" + cmd="%s -k 9" % (Utils.EnuLauncherPath) if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) if 0 != subprocess.call(cmd.split(), stdout=Utils.FNull): if not silent: Utils.Print("Launcher failed to shut down enu cluster.") - # ocassionally the launcher cannot kill the enu server - cmd="pkill -9 %s" % (Utils.EnuServerName) - if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) - if 0 != subprocess.call(cmd.split(), stdout=Utils.FNull): - if not silent: Utils.Print("Failed to shut down enu cluster.") + if allInstances: + # ocassionally the launcher cannot kill the enu server + cmd="pkill -9 %s" % (Utils.EnuServerName) + if Utils.Debug: Utils.Print("cmd: %s" % (cmd)) + if 0 != subprocess.call(cmd.split(), stdout=Utils.FNull): + if not silent: Utils.Print("Failed to shut down enu cluster.") # another explicit nodes shutdown for node in self.nodes: diff --git a/tests/wallet_tests.cpp b/tests/wallet_tests.cpp index a6b10cf3d7c..407d2317a7e 100644 --- a/tests/wallet_tests.cpp +++ b/tests/wallet_tests.cpp @@ -16,7 +16,6 @@ namespace enumivo { BOOST_AUTO_TEST_SUITE(wallet_tests) - /// Test creating the wallet BOOST_AUTO_TEST_CASE(wallet_test) { try { @@ -82,7 +81,7 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test) wallet_manager wm; BOOST_CHECK_EQUAL(0, wm.list_wallets().size()); - BOOST_CHECK_EQUAL(0, wm.list_keys().size()); + BOOST_CHECK_THROW(wm.get_public_keys(), wallet_not_available_exception); BOOST_CHECK_NO_THROW(wm.lock_all()); BOOST_CHECK_THROW(wm.lock("test"), fc::exception); @@ -94,7 +93,8 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test) BOOST_CHECK_EQUAL(0, pw.find("PW")); // starts with PW BOOST_CHECK_EQUAL(1, wm.list_wallets().size()); // enumivo key is imported automatically when a wallet is created - BOOST_CHECK_EQUAL(1, wm.list_keys().size()); + BOOST_CHECK_EQUAL(1, wm.get_public_keys().size()); + BOOST_CHECK_EQUAL(1, wm.list_keys("test", pw).size()); BOOST_CHECK(wm.list_wallets().at(0).find("*") != std::string::npos); wm.lock("test"); BOOST_CHECK(wm.list_wallets().at(0).find("*") == std::string::npos); @@ -102,8 +102,8 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test) BOOST_CHECK_THROW(wm.unlock("test", pw), chain::wallet_unlocked_exception); BOOST_CHECK(wm.list_wallets().at(0).find("*") != std::string::npos); wm.import_key("test", key1); - BOOST_CHECK_EQUAL(2, wm.list_keys().size()); - auto keys = wm.list_keys(); + BOOST_CHECK_EQUAL(2, wm.get_public_keys().size()); + auto keys = wm.list_keys("test", pw); auto pub_pri_pair = [](const char *key) -> auto { private_key_type prikey = private_key_type(std::string(key)); @@ -113,33 +113,40 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test) BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key1)) != keys.cend()); wm.import_key("test", key2); - keys = wm.list_keys(); + keys = wm.list_keys("test", pw); BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key1)) != keys.cend()); BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key2)) != keys.cend()); // key3 was automatically imported BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key3)) != keys.cend()); wm.lock("test"); - BOOST_CHECK_EQUAL(0, wm.list_keys().size()); + BOOST_CHECK_THROW(wm.list_keys("test", pw), wallet_locked_exception); + BOOST_CHECK_THROW(wm.get_public_keys(), wallet_locked_exception); wm.unlock("test", pw); - BOOST_CHECK_EQUAL(3, wm.list_keys().size()); + BOOST_CHECK_EQUAL(3, wm.get_public_keys().size()); + BOOST_CHECK_EQUAL(3, wm.list_keys("test", pw).size()); wm.lock_all(); - BOOST_CHECK_EQUAL(0, wm.list_keys().size()); + BOOST_CHECK_THROW(wm.get_public_keys(), wallet_locked_exception); BOOST_CHECK(wm.list_wallets().at(0).find("*") == std::string::npos); auto pw2 = wm.create("test2"); BOOST_CHECK_EQUAL(2, wm.list_wallets().size()); // enumivo key is imported automatically when a wallet is created - BOOST_CHECK_EQUAL(1, wm.list_keys().size()); + BOOST_CHECK_EQUAL(1, wm.get_public_keys().size()); BOOST_CHECK_THROW(wm.import_key("test2", key3), fc::exception); - keys = wm.list_keys(); + keys = wm.list_keys("test2", pw2); BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key1)) == keys.cend()); BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key2)) == keys.cend()); BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key3)) != keys.cend()); wm.unlock("test", pw); - keys = wm.list_keys(); + keys = wm.list_keys("test", pw); + auto keys2 = wm.list_keys("test2", pw2); + keys.insert(keys2.begin(), keys2.end()); BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key1)) != keys.cend()); BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key2)) != keys.cend()); BOOST_CHECK(std::find(keys.cbegin(), keys.cend(), pub_pri_pair(key3)) != keys.cend()); + BOOST_CHECK_EQUAL(3, keys.size()); + + BOOST_CHECK_THROW(wm.list_keys("test2", "PWnogood"), wallet_invalid_password_exception); private_key_type pkey1{std::string(key1)}; private_key_type pkey2{std::string(key2)}; @@ -158,9 +165,10 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test) BOOST_CHECK(find(pks.cbegin(), pks.cend(), pkey2.get_public_key()) != pks.cend()); BOOST_CHECK(find(pks.cbegin(), pks.cend(), pkey3.get_public_key()) != pks.cend()); - BOOST_CHECK_EQUAL(3, wm.list_keys().size()); + BOOST_CHECK_EQUAL(3, wm.get_public_keys().size()); wm.set_timeout(chrono::seconds(0)); - BOOST_CHECK_EQUAL(0, wm.list_keys().size()); + BOOST_CHECK_THROW(wm.get_public_keys(), wallet_locked_exception); + BOOST_CHECK_THROW(wm.list_keys("test", pw), wallet_locked_exception); wm.set_timeout(chrono::seconds(15)); @@ -168,7 +176,7 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test) const string test_key_create_types[] = {"K1", "R1", "k1", ""}; for(const string& key_type_to_create : test_key_create_types) { - wm.create("testgen"); + string pw = wm.create("testgen"); //check that the public key returned looks legit through a string conversion // (would throw otherwise) @@ -176,7 +184,7 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test) //now pluck out the private key from the wallet and see if the public key of said // private key matches what was returned earlier from the create_key() call - private_key_type create_key_priv(wm.list_keys().cbegin()->second); + private_key_type create_key_priv(wm.list_keys("testgen", pw).cbegin()->second); BOOST_CHECK_EQUAL((string)create_key_pub, (string)create_key_priv.get_public_key()); wm.lock("testgen"); @@ -196,7 +204,6 @@ BOOST_AUTO_TEST_CASE(wallet_manager_test) } FC_LOG_AND_RETHROW() } - BOOST_AUTO_TEST_SUITE_END() } // namespace enumivo diff --git a/unittests/enumivo.system_tests.cpp b/unittests/enumivo.system_tests.cpp index 7597b59ef4a..20c51b40a74 100644 --- a/unittests/enumivo.system_tests.cpp +++ b/unittests/enumivo.system_tests.cpp @@ -10,12 +10,6 @@ using namespace enumivo_system; -struct enumivo_parameters : enumivo::chain::chain_config { - uint64_t max_ram_size; -}; - -FC_REFLECT_DERIVED(enumivo_parameters, (enumivo::chain::chain_config), (max_ram_size)); - BOOST_AUTO_TEST_SUITE(enumivo_system_tests) BOOST_FIXTURE_TEST_CASE( buysell, enumivo_system_tester ) try { @@ -32,7 +26,7 @@ BOOST_FIXTURE_TEST_CASE( buysell, enumivo_system_tester ) try { const asset initial_ramfee_balance = get_balance(N(enumivo.rfee)); BOOST_REQUIRE_EQUAL( success(), buyram( "alice1111111", "alice1111111", core_from_string("200.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("800.0000"), get_balance( "alice1111111" ) ); - BOOST_REQUIRE_EQUAL( initial_ram_balance + core_from_string("199.0000"), get_balance(N(enumivo.ram)) ); + BOOST_REQUIRE_EQUAL( initial_ram_balance + core_from_string("199.0000"), get_balance(N(enumivo.ram)) ); BOOST_REQUIRE_EQUAL( initial_ramfee_balance + core_from_string("1.0000"), get_balance(N(enumivo.rfee)) ); total = get_total_stake( "alice1111111" ); @@ -123,6 +117,9 @@ BOOST_FIXTURE_TEST_CASE( buysell, enumivo_system_tester ) try { BOOST_FIXTURE_TEST_CASE( stake_unstake, enumivo_system_tester ) try { cross_15_percent_threshold(); + produce_blocks( 10 ); + produce_block( fc::hours(3*24) ); + BOOST_REQUIRE_EQUAL( core_from_string("0.0000"), get_balance( "alice1111111" ) ); transfer( "enumivo", "alice1111111", core_from_string("1000.0000"), "enumivo" ); @@ -133,18 +130,22 @@ BOOST_FIXTURE_TEST_CASE( stake_unstake, enumivo_system_tester ) try { BOOST_REQUIRE_EQUAL( core_from_string("210.0000"), total["net_weight"].as()); BOOST_REQUIRE_EQUAL( core_from_string("110.0000"), total["cpu_weight"].as()); + const auto init_enumivo_stk_balance = get_balance( N(enumivo.stk) ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( init_enumivo_stk_balance + core_from_string("300.0000"), get_balance( N(enumivo.stk) ) ); BOOST_REQUIRE_EQUAL( success(), unstake( "alice1111111", "alice1111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); produce_block( fc::hours(3*24-1) ); produce_blocks(1); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( init_enumivo_stk_balance + core_from_string("300.0000"), get_balance( N(enumivo.stk) ) ); //after 3 days funds should be released produce_block( fc::hours(1) ); produce_blocks(1); BOOST_REQUIRE_EQUAL( core_from_string("1000.0000"), get_balance( "alice1111111" ) ); + BOOST_REQUIRE_EQUAL( init_enumivo_stk_balance, get_balance( N(enumivo.stk) ) ); BOOST_REQUIRE_EQUAL( success(), stake( "alice1111111", "bob111111111", core_from_string("200.0000"), core_from_string("100.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance( "alice1111111" ) ); @@ -1151,7 +1152,7 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, enumivo_system_tester, * boost::unit_test: const uint64_t initial_claim_time = initial_global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t initial_pervote_bucket = initial_global_state["pervote_bucket"].as(); const int64_t initial_perblock_bucket = initial_global_state["perblock_bucket"].as(); - const int64_t initial_savings = initial_global_state["savings"].as(); + const int64_t initial_savings = get_balance(N(enumivo.save)).get_amount(); const uint32_t initial_tot_unpaid_blocks = initial_global_state["total_unpaid_blocks"].as(); prod = get_producer_info("defproducera"); @@ -1170,7 +1171,7 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, enumivo_system_tester, * boost::unit_test: const uint64_t claim_time = global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t pervote_bucket = global_state["pervote_bucket"].as(); const int64_t perblock_bucket = global_state["perblock_bucket"].as(); - const int64_t savings = global_state["savings"].as(); + const int64_t savings = get_balance(N(enumivo.save)).get_amount(); const uint32_t tot_unpaid_blocks = global_state["total_unpaid_blocks"].as(); @@ -1229,7 +1230,7 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, enumivo_system_tester, * boost::unit_test: const uint64_t initial_claim_time = initial_global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t initial_pervote_bucket = initial_global_state["pervote_bucket"].as(); const int64_t initial_perblock_bucket = initial_global_state["perblock_bucket"].as(); - const int64_t initial_savings = initial_global_state["savings"].as(); + const int64_t initial_savings = get_balance(N(enumivo.save)).get_amount(); const uint32_t initial_tot_unpaid_blocks = initial_global_state["total_unpaid_blocks"].as(); const double initial_tot_vote_weight = initial_global_state["total_producer_vote_weight"].as(); @@ -1253,7 +1254,7 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, enumivo_system_tester, * boost::unit_test: const uint64_t claim_time = global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t pervote_bucket = global_state["pervote_bucket"].as(); const int64_t perblock_bucket = global_state["perblock_bucket"].as(); - const int64_t savings = global_state["savings"].as(); + const int64_t savings = get_balance(N(enumivo.save)).get_amount(); const uint32_t tot_unpaid_blocks = global_state["total_unpaid_blocks"].as(); @@ -1295,7 +1296,7 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, enumivo_system_tester, * boost::unit_test: regproducer(N(defproducerb)); regproducer(N(defproducerc)); const asset initial_supply = get_token_supply(); - const int64_t initial_savings = get_global_state()["savings"].as(); + const int64_t initial_savings = get_balance(N(enumivo.save)).get_amount(); for (uint32_t i = 0; i < 7 * 52; ++i) { produce_block(fc::seconds(8 * 3600)); BOOST_REQUIRE_EQUAL(success(), push_action(N(defproducerc), N(claimrewards), mvo()("owner", "defproducerc"))); @@ -1305,7 +1306,7 @@ BOOST_FIXTURE_TEST_CASE(producer_pay, enumivo_system_tester, * boost::unit_test: BOOST_REQUIRE_EQUAL(success(), push_action(N(defproducera), N(claimrewards), mvo()("owner", "defproducera"))); } const asset supply = get_token_supply(); - const int64_t savings = get_global_state()["savings"].as(); + const int64_t savings = get_balance(N(enumivo.save)).get_amount(); // Amount issued per year is very close to the 5% inflation target. Small difference (500 tokens out of 50'000'000 issued) // is due to compounding every 8 hours in this test as opposed to theoretical continuous compounding BOOST_REQUIRE(500 * 10000 > int64_t(double(initial_supply.get_amount()) * double(0.05)) - (supply.get_amount() - initial_supply.get_amount())); @@ -1453,10 +1454,9 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, enumivo_system_tester, * boost::u const uint64_t initial_claim_time = initial_global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t initial_pervote_bucket = initial_global_state["pervote_bucket"].as(); const int64_t initial_perblock_bucket = initial_global_state["perblock_bucket"].as(); - const int64_t initial_savings = initial_global_state["savings"].as(); + const int64_t initial_savings = get_balance(N(enumivo.save)).get_amount(); const uint32_t initial_tot_unpaid_blocks = initial_global_state["total_unpaid_blocks"].as(); const asset initial_supply = get_token_supply(); - const asset initial_saving_balance = get_balance(N(enumivo.save)); const asset initial_bpay_balance = get_balance(N(enumivo.bpay)); const asset initial_vpay_balance = get_balance(N(enumivo.vpay)); const asset initial_balance = get_balance(prod_name); @@ -1468,10 +1468,9 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, enumivo_system_tester, * boost::u const uint64_t claim_time = global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t pervote_bucket = global_state["pervote_bucket"].as(); const int64_t perblock_bucket = global_state["perblock_bucket"].as(); - const int64_t savings = global_state["savings"].as(); + const int64_t savings = get_balance(N(enumivo.save)).get_amount(); const uint32_t tot_unpaid_blocks = global_state["total_unpaid_blocks"].as(); const asset supply = get_token_supply(); - const asset saving_balance = get_balance(N(enumivo.save)); const asset bpay_balance = get_balance(N(enumivo.bpay)); const asset vpay_balance = get_balance(N(enumivo.vpay)); const asset balance = get_balance(prod_name); @@ -1484,8 +1483,6 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, enumivo_system_tester, * boost::u BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth), supply.get_amount() - initial_supply.get_amount() ); BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth) - int64_t(expected_supply_growth)/5, savings - initial_savings ); - BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth) - int64_t(expected_supply_growth)/5, - saving_balance.get_amount() - initial_saving_balance.get_amount() ); const int64_t expected_perblock_bucket = int64_t( double(initial_supply.get_amount()) * double(usecs_between_fills) * (0.25 * cont_rate/ 5.) / usecs_per_year ); const int64_t expected_pervote_bucket = int64_t( double(initial_supply.get_amount()) * double(usecs_between_fills) * (0.75 * cont_rate/ 5.) / usecs_per_year ); @@ -1494,7 +1491,7 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, enumivo_system_tester, * boost::u const int64_t from_pervote_bucket = int64_t( vote_shares[prod_index] * expected_pervote_bucket); BOOST_REQUIRE( 1 >= abs(int32_t(initial_tot_unpaid_blocks - tot_unpaid_blocks) - int32_t(initial_unpaid_blocks - unpaid_blocks)) ); - + if (from_pervote_bucket >= 100 * 10000) { BOOST_REQUIRE( within_one( from_perblock_bucket + from_pervote_bucket, balance.get_amount() - initial_balance.get_amount() ) ); BOOST_REQUIRE( within_one( expected_pervote_bucket - from_pervote_bucket, pervote_bucket ) ); @@ -1504,7 +1501,7 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, enumivo_system_tester, * boost::u BOOST_REQUIRE( within_one( expected_pervote_bucket, vpay_balance.get_amount() ) ); BOOST_REQUIRE( within_one( perblock_bucket, bpay_balance.get_amount() ) ); } - + produce_blocks(5); BOOST_REQUIRE_EQUAL(wasm_assert_msg("already claimed rewards within past day"), @@ -1521,9 +1518,8 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, enumivo_system_tester, * boost::u push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); } - // wait for 23 hours which is not enough for producers to get deactivated - // payment calculations don't change. By now, pervote_bucket has grown enough - // that a producer's share is more than 100 tokens + // Wait for 23 hours. By now, pervote_bucket has grown enough + // that a producer's share is more than 100 tokens. produce_block(fc::seconds(23 * 3600)); { @@ -1534,10 +1530,9 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, enumivo_system_tester, * boost::u const uint64_t initial_claim_time = initial_global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t initial_pervote_bucket = initial_global_state["pervote_bucket"].as(); const int64_t initial_perblock_bucket = initial_global_state["perblock_bucket"].as(); - const int64_t initial_savings = initial_global_state["savings"].as(); + const int64_t initial_savings = get_balance(N(enumivo.save)).get_amount(); const uint32_t initial_tot_unpaid_blocks = initial_global_state["total_unpaid_blocks"].as(); const asset initial_supply = get_token_supply(); - const asset initial_saving_balance = get_balance(N(enumivo.save)); const asset initial_bpay_balance = get_balance(N(enumivo.bpay)); const asset initial_vpay_balance = get_balance(N(enumivo.vpay)); const asset initial_balance = get_balance(prod_name); @@ -1549,10 +1544,9 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, enumivo_system_tester, * boost::u const uint64_t claim_time = global_state["last_pervote_bucket_fill"].as_uint64(); const int64_t pervote_bucket = global_state["pervote_bucket"].as(); const int64_t perblock_bucket = global_state["perblock_bucket"].as(); - const int64_t savings = global_state["savings"].as(); + const int64_t savings = get_balance(N(enumivo.save)).get_amount(); const uint32_t tot_unpaid_blocks = global_state["total_unpaid_blocks"].as(); const asset supply = get_token_supply(); - const asset saving_balance = get_balance(N(enumivo.save)); const asset bpay_balance = get_balance(N(enumivo.bpay)); const asset vpay_balance = get_balance(N(enumivo.vpay)); const asset balance = get_balance(prod_name); @@ -1563,8 +1557,6 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, enumivo_system_tester, * boost::u const double expected_supply_growth = initial_supply.get_amount() * double(usecs_between_fills) * cont_rate / usecs_per_year; BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth), supply.get_amount() - initial_supply.get_amount() ); BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth) - int64_t(expected_supply_growth)/5, savings - initial_savings ); - BOOST_REQUIRE_EQUAL( int64_t(expected_supply_growth) - int64_t(expected_supply_growth)/5, - saving_balance.get_amount() - initial_saving_balance.get_amount() ); const int64_t expected_perblock_bucket = int64_t( double(initial_supply.get_amount()) * double(usecs_between_fills) * (0.25 * cont_rate/ 5.) / usecs_per_year ) + initial_perblock_bucket; @@ -1601,54 +1593,29 @@ BOOST_FIXTURE_TEST_CASE(multiple_producer_pay, enumivo_system_tester, * boost::u push_action(prod_name, N(claimrewards), mvo()("owner", prod_name))); } - // wait two more hours, now most producers haven't produced in a day and will - // be deactivated - BOOST_REQUIRE_EQUAL(success(), push_action(N(producvotera), N(voteproducer), mvo() - ("voter", "producvotera") - ("proxy", name(0).to_string()) - ("producers", vector(producer_names.begin(), producer_names.begin()+21)) - ) - ); + { + const uint32_t rmv_index = 5; + account_name prod_name = producer_names[rmv_index]; - produce_block(fc::hours(9)); - produce_blocks(8 * 21 * 12); + auto info = get_producer_info(prod_name); + BOOST_REQUIRE( info["is_active"].as() ); + BOOST_REQUIRE( fc::crypto::public_key() != fc::crypto::public_key(info["producer_key"].as_string()) ); - { - bool all_newly_elected_produced = true; - for (uint32_t i = 21; i < producer_names.size(); ++i) { - if (0 == get_producer_info(producer_names[i])["unpaid_blocks"].as()) { - all_newly_elected_produced = false; - } - } - BOOST_REQUIRE(all_newly_elected_produced); - } + BOOST_REQUIRE_EQUAL( error("missing authority of enumivo"), + push_action(prod_name, N(rmvproducer), mvo()("producer", prod_name))); + BOOST_REQUIRE_EQUAL( error("missing authority of enumivo"), + push_action(producer_names[rmv_index + 2], N(rmvproducer), mvo()("producer", prod_name) ) ); + BOOST_REQUIRE_EQUAL( success(), + push_action(config::system_account_name, N(rmvproducer), mvo()("producer", prod_name) ) ); - { - uint32_t survived_active_producers = 0; - uint32_t one_inactive_index = 0; - for (uint32_t i = 0; i < 21; ++i) { - if (fc::crypto::public_key() != fc::crypto::public_key(get_producer_info(producer_names[i])["producer_key"].as_string())) { - ++survived_active_producers; - } else { - one_inactive_index = i; - } - } + info = get_producer_info(prod_name); + BOOST_REQUIRE( !info["is_active"].as() ); + BOOST_REQUIRE( fc::crypto::public_key() == fc::crypto::public_key(info["producer_key"].as_string()) ); + BOOST_REQUIRE_EQUAL( wasm_assert_msg("producer does not have an active key"), + push_action(prod_name, N(claimrewards), mvo()("owner", prod_name) ) ); - BOOST_REQUIRE(3 >= survived_active_producers); - - auto inactive_prod_info = get_producer_info(producer_names[one_inactive_index]); - BOOST_REQUIRE_EQUAL(0, inactive_prod_info["time_became_active"].as()); - BOOST_REQUIRE_EQUAL(wasm_assert_msg("producer does not have an active key"), - push_action(producer_names[one_inactive_index], N(claimrewards), mvo()("owner", producer_names[one_inactive_index]))); - // re-register deactivated producer and let him produce blocks again - const uint32_t initial_unpaid_blocks = inactive_prod_info["unpaid_blocks"].as(); - regproducer(producer_names[one_inactive_index]); - produce_blocks(8 * 21 * 12); - auto reactivated_prod_info = get_producer_info(producer_names[one_inactive_index]); - const uint32_t unpaid_blocks = reactivated_prod_info["unpaid_blocks"].as(); - BOOST_REQUIRE(initial_unpaid_blocks + 12 <= unpaid_blocks); - BOOST_REQUIRE_EQUAL(success(), - push_action(producer_names[one_inactive_index], N(claimrewards), mvo()("owner", producer_names[one_inactive_index]))); + BOOST_REQUIRE_EQUAL( wasm_assert_msg("producer not found"), + push_action( config::system_account_name, N(rmvproducer), mvo()("producer", "nonexistingp") ) ); } } FC_LOG_AND_RETHROW() @@ -2519,7 +2486,7 @@ BOOST_FIXTURE_TEST_CASE( vote_producers_in_and_out, enumivo_system_tester ) try ); BOOST_REQUIRE_EQUAL(0, get_producer_info(producer_names[new_prod_index])["unpaid_blocks"].as()); produce_blocks(4 * 12 * 21); - BOOST_REQUIRE(0 < get_producer_info(producer_names[new_prod_index])["unpaid_blocks"]); + BOOST_REQUIRE(0 < get_producer_info(producer_names[new_prod_index])["unpaid_blocks"].as()); const uint32_t initial_unpaid_blocks = get_producer_info(producer_names[voted_out_index])["unpaid_blocks"].as(); produce_blocks(2 * 12 * 21); BOOST_REQUIRE_EQUAL(initial_unpaid_blocks, get_producer_info(producer_names[voted_out_index])["unpaid_blocks"].as()); @@ -2560,9 +2527,8 @@ BOOST_FIXTURE_TEST_CASE( setparams, enumivo_system_tester ) try { prod_perms.push_back( { name(x), config::active_name } ); } - enumivo_parameters params; - (enumivo::chain::chain_config&)params = control->get_global_properties().configuration; - params.max_ram_size = 65ll*1024 * 1024 * 1024; + enumivo::chain::chain_config params; + params = control->get_global_properties().configuration; //change some values params.max_block_net_usage += 10; params.max_transaction_lifetime += 1; @@ -2646,7 +2612,7 @@ BOOST_FIXTURE_TEST_CASE( setram_effect, enumivo_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), buyram( name_a, name_a, core_from_string("300.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance(name_a) ); const uint64_t bought_bytes_a = get_total_stake(name_a)["ram_bytes"].as_uint64() - init_bytes_a; - + // after buying and selling balance should be 700 + 300 * 0.995 * 0.995 = 997.0075 BOOST_REQUIRE_EQUAL( success(), sellram(name_a, bought_bytes_a ) ); BOOST_REQUIRE_EQUAL( core_from_string("997.0075"), get_balance(name_a) ); @@ -2661,13 +2627,15 @@ BOOST_FIXTURE_TEST_CASE( setram_effect, enumivo_system_tester ) try { BOOST_REQUIRE_EQUAL( success(), buyram( name_b, name_b, core_from_string("300.0000") ) ); BOOST_REQUIRE_EQUAL( core_from_string("700.0000"), get_balance(name_b) ); const uint64_t bought_bytes_b = get_total_stake(name_b)["ram_bytes"].as_uint64() - init_bytes_b; - - // increase max_ram_size, ram bought by name_b loses part of its value + + // increase max_ram_size, ram bought by name_b loses part of its value BOOST_REQUIRE_EQUAL( wasm_assert_msg("ram may only be increased"), push_action(config::system_account_name, N(setram), mvo()("max_ram_size", 64ll*1024 * 1024 * 1024)) ); - BOOST_REQUIRE_EQUAL( success(), + BOOST_REQUIRE_EQUAL( error("missing authority of enumivo"), + push_action(name_b, N(setram), mvo()("max_ram_size", 80ll*1024 * 1024 * 1024)) ); + BOOST_REQUIRE_EQUAL( success(), push_action(config::system_account_name, N(setram), mvo()("max_ram_size", 80ll*1024 * 1024 * 1024)) ); - + BOOST_REQUIRE_EQUAL( success(), sellram(name_b, bought_bytes_b ) ); BOOST_REQUIRE( core_from_string("900.0000") < get_balance(name_b) ); BOOST_REQUIRE( core_from_string("950.0000") > get_balance(name_b) );