Skip to content

Versioning of contracts and upgradability test#1470

Merged
cygnusv merged 14 commits intonucypher:masterfrom
vzotova:upgradability-test
Dec 26, 2019
Merged

Versioning of contracts and upgradability test#1470
cygnusv merged 14 commits intonucypher:masterfrom
vzotova:upgradability-test

Conversation

@vzotova
Copy link
Member

@vzotova vzotova commented Nov 22, 2019

Closes #1464
Closes #1465

  • Version for upgradeable contracts inside contract doc (@dev), for example |v1.2.3|
  • Multi-source solidity compilation
  • Extracting version inside SolidityCompiler
  • Storing version in contract registry
  • Using version while deployment
  • Test for upgrading possibility between current commit and master

Version format is |vi.j.k|, where i - fork (I hope will be always 1), j - upgradeable signature/state changes, k - small changes inside existent function

@vzotova vzotova added Enhancement New or improved features ETH Contracts Test 🔍 Tests only labels Nov 22, 2019
@vzotova vzotova self-assigned this Nov 22, 2019
@codecov
Copy link

codecov bot commented Nov 22, 2019

Codecov Report

Merging #1470 into master will decrease coverage by 0.08%.
The diff coverage is 91.86%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master    #1470      +/-   ##
==========================================
- Coverage   84.31%   84.22%   -0.09%     
==========================================
  Files          72       72              
  Lines       11225    11303      +78     
==========================================
+ Hits         9464     9520      +56     
- Misses       1761     1783      +22
Impacted Files Coverage Δ
nucypher/blockchain/eth/agents.py 91.15% <ø> (ø) ⬆️
nucypher/blockchain/eth/actors.py 86.95% <100%> (ø) ⬆️
nucypher/utilities/sandbox/blockchain.py 79.22% <100%> (ø) ⬆️
nucypher/blockchain/eth/deployers.py 89.35% <100%> (+0.86%) ⬆️
nucypher/cli/deploy.py 83.41% <100%> (+0.15%) ⬆️
nucypher/cli/painting.py 80.11% <100%> (ø) ⬆️
nucypher/blockchain/eth/interfaces.py 72.12% <82.75%> (+0.99%) ⬆️
nucypher/blockchain/eth/registry.py 83.38% <92.85%> (-0.01%) ⬇️
nucypher/blockchain/eth/sol/compile.py 84.94% <93.33%> (+4.94%) ⬆️
nucypher/characters/lawful.py 87.47% <0%> (-2.21%) ⬇️
... and 4 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 61f749e...5680bd2. Read the comment docs.

@vzotova vzotova force-pushed the upgradability-test branch 4 times, most recently from 468fdc1 to 5035026 Compare November 29, 2019 11:34
@vzotova vzotova force-pushed the upgradability-test branch 2 times, most recently from c545440 to 8458dfc Compare December 3, 2019 17:08
@vzotova vzotova changed the title [WIP] Versioning of contracts and upgradability test Versioning of contracts and upgradability test Dec 3, 2019
@vzotova vzotova marked this pull request as ready for review December 3, 2019 17:16
raw_interfaces = self._compile(root_source_dir, other_source_dirs)
for name, data in raw_interfaces.items():
# Extract contract version from docs
version_search = re.search(r'\"details\":\".*?\|(v\d+\.\d+\.\d+)\|.*?\"', data['devdoc'])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you expand this regex into the verbose format?

Example:

p = re.compile(r"""

(\+\d{1,2})?               # Optional Country Code +1 or perhaps +22
(-|\()?                    # Optional hyphen or open parenths for the area code.
(\d{10}                    # Try and match ten digits exactly
|                          # Else
(\d{3}                     # Match three digits
[\-|\)]{0,2})              # Hypen or close parenths zero through 2 times (to account for -))  
{2}                        # Repeat to match the next three digits
\d{4})                     # The remaining four digits
$                          # Ensure nothing else follows 


""", re.VERBOSE)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

* @param _index Index of the sub stake
* @param _periods Amount of periods for extending sub stake
**/
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hahah 😂

@vzotova vzotova force-pushed the upgradability-test branch from 8458dfc to 851de8f Compare December 5, 2019 10:15
vzotova added a commit to vzotova/nucypher that referenced this pull request Dec 5, 2019
vzotova added a commit to vzotova/nucypher that referenced this pull request Dec 6, 2019
@vzotova vzotova force-pushed the upgradability-test branch from 3c12856 to 5680bd2 Compare December 6, 2019 19:14
for name, data in raw_interfaces.items():
# Extract contract version from docs
version_search = re.search(r'\"details\":\".*?\|(v\d+\.\d+\.\d+)\|.*?\"', data['devdoc'])
version_search = re.search(r"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Badass

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🆒

@vzotova vzotova mentioned this pull request Dec 7, 2019
@@ -0,0 +1,144 @@
"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚀 - This is a relief, good work. I think this test can be emphasized in our CI workflow by running it in its own job.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

with pytest.raises(BaseContractDeployer.ContractDeploymentError):
assert policy_manager_deployer.contract_address is constants.CONTRACT_NOT_DEPLOYED
assert not policy_manager_deployer.is_deployed
assert not policy_manager_deployer.is_deployed()
Copy link
Member

@KPrasch KPrasch Dec 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is PolicyManagerDeployer.is_deployed no longer a @property method?

Copy link
Member Author

@vzotova vzotova Dec 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added version as parameter to this method, None by default means any version of contract

@cygnusv cygnusv added this to the Testnet v2 milestone Dec 11, 2019
@click.option('--retarget', '-d', help="Retarget a contract's proxy.", is_flag=True)
@click.option('--target-address', help="Recipient's checksum address for token or ownership transference.",
type=EIP55_CHECKSUM_ADDRESS)
@click.option('--ignore-deployed', help="Ignore already deployed contracts if exist.", is_flag=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

return of "bare" mode? I like your name better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's related to "bare" but much simpler, turns off 'is_deployed' check to redeploy same contract multiple times (first of all for test)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for my own understanding: is this flag essentially a force type option to deploy the contract even if previously deployed?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct, one remark - force for the same contract with the same version

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this have a use beyond tests?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see at least one use: redeploying same contract but with different constructor parameters, for example, disable/enable test mode of StakingEscrow (for worklock)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But are we going to do that on a real deployment? because as far as I understand, the test mode is only for tests. Or are you planning on trying that on testnet?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

test mode for testnet, to change worklock

])
interfaces = solidity_compiler.compile()

# Remove AST because id in tree node depends on compilation scope
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Woah - can you expand a bit on this?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Each element in AST has ID field. This value depends on scope of compiled files (all contracts). First source for SolidityCompiler includes only main contracts, second - also tests. Merging two results lead that main contracts has AST from first compilation, test contracts from the second. Interface has contracts with the same AST as in second compilation for all contracts. We don't use AST yet and main part for comparing is bytecode, so I remove it

vzotova added a commit to vzotova/nucypher that referenced this pull request Dec 12, 2019
@vzotova vzotova mentioned this pull request Dec 18, 2019
Copy link
Member

@derekpierre derekpierre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎸 - Very organized and clean! Added some comments, but I'm unsure I'm knowledgeable enough about this part of the codebase to add a meaningful approval - best for me to leave it to the dev pros 😄

@click.option('--retarget', '-d', help="Retarget a contract's proxy.", is_flag=True)
@click.option('--target-address', help="Recipient's checksum address for token or ownership transference.",
type=EIP55_CHECKSUM_ADDRESS)
@click.option('--ignore-deployed', help="Ignore already deployed contracts if exist.", is_flag=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just for my own understanding: is this flag essentially a force type option to deploy the contract even if previously deployed?

vzotova added a commit to vzotova/nucypher that referenced this pull request Dec 18, 2019
Co-Authored-By: Derek Pierre <derek.pierre@gmail.com>
requested_version == 'earliest' and \
(major < current_version_parsed[0] or
major == current_version_parsed[0] and minor < current_version_parsed[1] or
major == current_version_parsed[0] and minor == current_version_parsed[1] and patch < current_version_parsed[2]):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wow, a 9-line condition. This is though!
I think this part needs some touches to improve readability. As far as I can tell, you're trying to check lexicographical ordering between tuples, which Python implements already. So, e.g., lines 667 to 669 can be changed to (major, minor, patch) > current_version_parsed; similarly, lines 671 to 673 can be changed to (major, minor, patch) < current_version_parsed

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cygnusv That's pretty cool - didn't know you could do that.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, really cool suggestion.
✔️

@click.option('--retarget', '-d', help="Retarget a contract's proxy.", is_flag=True)
@click.option('--target-address', help="Recipient's checksum address for token or ownership transference.",
type=EIP55_CHECKSUM_ADDRESS)
@click.option('--ignore-deployed', help="Ignore already deployed contracts if exist.", is_flag=True)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this have a use beyond tests?

vzotova added a commit to vzotova/nucypher that referenced this pull request Dec 20, 2019
vzotova added a commit to vzotova/nucypher that referenced this pull request Dec 20, 2019
Co-Authored-By: Derek Pierre <derek.pierre@gmail.com>
Co-Authored-By: David Núñez <david@nucypher.com>
Copy link
Member

@cygnusv cygnusv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome work, @vzotova ! As usual :)
My only strong comment is regarding the CircleCI configuration, where I really think it should be restored to its original state.

- run:
name: Ethereum Contract Upgradeability Test
command: |
pytest $(circleci tests glob "tests/blockchain/eth/contracts/test_contracts_upgradeability.py" | circleci tests split --split-by=timings)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After checking the performance of the CI build, I think having a separate job for this test is unnecessary. It blocks a CI box for some time, while if it were included in the contracts job, it will probably be executed without any overhead due to current parallelism.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The main reason for extracting was readability of test results, like in 1459, where only one contract test failed, I like how it looks

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, I understand, but we have a limited number of CI boxes and using one of them for a single test that runs for 21 seconds doesn't seem a good idea to me.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

makes sense, I'll change it back

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✔️

for name, data in raw_interfaces.items():
# Extract contract version from docs
version_search = re.search(r'\"details\":\".*?\|(v\d+\.\d+\.\d+)\|.*?\"', data['devdoc'])
version_search = re.search(r"""
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🆒

/**
* @notice Contract for calculate issued tokens
**/
* @dev |v1.1.2|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about considering v.1.1.1 for all contracts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just tried to remember how many changes we did before, but really it doesn't matter because of testnet redeploy and new versions v2.1.1

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@property
def is_deployed(self) -> bool:
return bool(self._contract is not CONTRACT_NOT_DEPLOYED)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes! I had a very similar change in a WIP PR. This property was just checking if the contract was deployed with that very same instance of the deployer, which of course is not very useful in use cases like upgrades or rollbacks. Glad this is changed :)

@cygnusv cygnusv merged commit 11e7fc6 into nucypher:master Dec 26, 2019
@vzotova vzotova deleted the upgradability-test branch April 28, 2020 13:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement New or improved features Test 🔍 Tests only

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Test for contracts upgradability between master and PRs Versioning of contracts

5 participants