Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial version of genesis deployment tool #458

Merged
merged 12 commits into from
Jan 8, 2019

Conversation

hobofan
Copy link
Contributor

@hobofan hobofan commented Nov 14, 2018

Adds the first version of the genesis deployment script(s).

This allows us to generate the accounts section for a parity chainspec, taking as input the bytecode of the compiled contracts and their constructor arguments (+ ABI). This greatly simplifies the bootstrapping of a new Auxiliary chain.

Also adds eslint for JS style conformance as per #404.

TODO:

  • Find a way to be able to invoke script directly instead of via truffle exec (truffle exec has a poluted STDOUT output)
  • A bit simpler interface for adding Truffle contracts
  • Add script to merge the output of one of these deployment scripts into a chainspec
  • Allow for specifying a address for a contract instance instead of incrementing from a fixed address.
  • More robust way of incrementing addresses (that works for more than 255 addresses)
  • Better documentation of the ContractRegistry functions

@pgev : I gave you access to my fork


takeNextAddress() {
const addressHex = web3.utils.bytesToHex(this.nextAvailableAddress);
this.nextAvailableAddress[this.nextAvailableAddress.length - 1] += 1;
Copy link
Contributor

Choose a reason for hiding this comment

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

Wouldn't it be easier to have a BN or similar and actually increase that? If I understand this approach correctly it is bound to 10 addresses, which may or may not be sufficient in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's bound to 255 (as it increments the last byte, not string character), but yeah, probably possible to use BN instead. I'll look into that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Doesn't it increment the last hex character (4 bits => max 16)? And does it know to go from 9 to a? JavaScript magic? 🤔

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this.nextAvailableAddress is a byte array, so no magic there 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But that code is gone now anyway 😄

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, somehow I thought it was a hex string 😳

@hobofan hobofan force-pushed the feature/genesis-deployment branch 3 times, most recently from e7b6a83 to f2e3d15 Compare November 19, 2018 07:33
@hobofan hobofan changed the title [WIP] Add initial version of genesis deployment tool Add initial version of genesis deployment tool Nov 19, 2018
@hobofan
Copy link
Contributor Author

hobofan commented Nov 19, 2018

From my side this would be mergeable in the current state. Should be in a usable state for @pgev's work on the ValidatorSet. Next step would be applying this to the deployment sequence for auxiliary, now that #448 is merged.

@hobofan hobofan changed the title Add initial version of genesis deployment tool [WIP] Add initial version of genesis deployment tool Nov 22, 2018
@hobofan
Copy link
Contributor Author

hobofan commented Nov 22, 2018

WIP again following some feedback from @pgev

@hobofan hobofan force-pushed the feature/genesis-deployment branch 2 times, most recently from 727bd12 to 63a40ec Compare December 11, 2018 14:18
@hobofan hobofan changed the title [WIP] Add initial version of genesis deployment tool Add initial version of genesis deployment tool Dec 11, 2018
@hobofan
Copy link
Contributor Author

hobofan commented Dec 11, 2018

Back to review.

@pgev I added the state machine we talked about. Also added some tests for core parts of the functionality and a referencing system for contract addresses in constructor arguments (so we can also order those correctly).

@hobofan hobofan mentioned this pull request Dec 15, 2018
@hobofan hobofan force-pushed the feature/genesis-deployment branch 2 times, most recently from 34e2fd9 to f9f045d Compare December 18, 2018 14:20
Copy link
Contributor

@schemar schemar left a comment

Choose a reason for hiding this comment

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

Thanks @hobofan 🙌
It is generally clear and understandable.
It is good that there are tests 👍 What is the rough coverage?

It would definitely make sense to have a short readme or comment somewhere that explains in which context and/or how to use these things.

Some functions are very long and should be split. For example Contract::instantiate().
I would prefer one class per file. Not sure if we have a rule for that. @pgev ?

See further comments in-line.

.eslintrc Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
tools/deploy_token_genesis.js Outdated Show resolved Hide resolved
const registry = new ContractRegistry();
registry.addContract(EIP20Token);

console.log(JSON.stringify(registry.toParityGenesisAccounts(), null, 4));
Copy link
Contributor

Choose a reason for hiding this comment

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

What is this for? How is this used?

tools/deployment_tools.js Outdated Show resolved Hide resolved
tools/deployment_tools.js Outdated Show resolved Hide resolved
tools/merge_chainspec_accounts.js Show resolved Hide resolved
chainspec.accounts[address] = obj;
});

console.log(JSON.stringify(chainspec, null, 4));
Copy link
Contributor

Choose a reason for hiding this comment

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

What is the purpose of this?

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know enough about JS, but are you using a logging mechanism to give feedback to the user on stdout? Can I change the behavior of console.log() to log somewhere else? E.g. a file? In that case I would prefer explicitly writing to stdout and not a log.

tools/test/deployment_tools.test.js Outdated Show resolved Hide resolved
tools/test/deployment_tools.test.js Outdated Show resolved Hide resolved
@hobofan hobofan force-pushed the feature/genesis-deployment branch 4 times, most recently from 45677fc to d2d75a9 Compare December 19, 2018 16:22
@hobofan
Copy link
Contributor Author

hobofan commented Dec 19, 2018

@schemar I've incorporated your feedback! I've added a README to the tools directory, which also gives a high-level introduction.

As for the test coverage, it is mostly focused on ensuring the "happy path" flow for both Genesis and Live deployment works as expected, and that the ordering and reference mechanisms work.

tools/README.md Show resolved Hide resolved
package.json Outdated Show resolved Hide resolved
Copy link
Contributor

@schemar schemar left a comment

Choose a reason for hiding this comment

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

Phew nice 🐎💨

Just some minor things left 👍

package.json Outdated
@@ -6,8 +6,13 @@
"abi-decoder": "1.2.0",
"assert": "1.4.1",
"bn.js": "4.11.8",
"chai": "4.2.0",
"eslint": "5.9.0",
Copy link
Contributor

Choose a reason for hiding this comment

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

Not using 5.10 for a reason?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nope! Updating!

}

/**
* Helper for loading a contract saved in a format followin the truffle-contract-schema.
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
* Helper for loading a contract saved in a format followin the truffle-contract-schema.
* Helper for loading a contract saved in a format following the truffle-contract-schema.

*
* @param {string} contractName Name of the contract to load.
* @param {Array<*>} constructorArgs Arguments for the contract constructor.
* @param {object} options
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you expect more options in the future?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Maybe.

Copy link
Contributor

Choose a reason for hiding this comment

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

Then it could as well be a rootDir argument 🤷‍♂️

/**
* Returns the contract's address as detemined by the provided AddressGenerator.
*
* @param {Object|string} addressGeneratorOrAddress The AddressGenerator used for
Copy link
Contributor

Choose a reason for hiding this comment

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

I mean. I think I can accept this. But it kind of freaks me out.

Copy link
Contributor

Choose a reason for hiding this comment

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

Someone else should probably comment on this @benjaminbollen @pgev @deepesh-kn

Copy link
Contributor

Choose a reason for hiding this comment

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

I too prefer separate functions like setAddress and generateAddress

* @returns {Contract|null} The referenced contract.
*/
_getReferenceContract(constructorArg) {
if (!((typeof constructorArg === 'object') && (constructorArg !== null)) || constructorArg.__type !== TYPE_CONTRACT_REFERENCE) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Maybe something like the below. I am sure this can inspire you to do something readable 😄

if(!isReference(constructorArg)) {
    return null;
}


function isReference(constructorArg) {
    if (!isInstance(constructorArg) {
        return false;
    }

    return constructorArg.__type === TYPE_CONTRACT_REFERENCE
}

function isInstance(constructorArg) {
    return typeof constructorArg === 'object' && constructorArg !== null;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

👍

tools/deployment_tool/contract.js Show resolved Hide resolved
tools/deployment_tool/contract_registry.js Show resolved Hide resolved
@hobofan hobofan force-pushed the feature/genesis-deployment branch 2 times, most recently from c25ec99 to 352ca0f Compare December 19, 2018 17:59
@hobofan
Copy link
Contributor Author

hobofan commented Dec 19, 2018

🔁 :)

Copy link
Contributor

@schemar schemar left a comment

Choose a reason for hiding this comment

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

LGTM, but someone else should definitely have a look.

Summoning @benjaminbollen @pgev @deepesh-kn

*
* @param {string} contractName Name of the contract to load.
* @param {Array<*>} constructorArgs Arguments for the contract constructor.
* @param {object} options
Copy link
Contributor

Choose a reason for hiding this comment

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

Then it could as well be a rootDir argument 🤷‍♂️

/**
* Returns the contract's address as detemined by the provided AddressGenerator.
*
* @param {Object|string} addressGeneratorOrAddress The AddressGenerator used for
Copy link
Contributor

Choose a reason for hiding this comment

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

Someone else should probably comment on this @benjaminbollen @pgev @deepesh-kn

chainspec.accounts[address] = obj;
});

console.log(JSON.stringify(chainspec, null, 4));
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't know enough about JS, but are you using a logging mechanism to give feedback to the user on stdout? Can I change the behavior of console.log() to log somewhere else? E.g. a file? In that case I would prefer explicitly writing to stdout and not a log.

Copy link
Contributor

@deepesh-kn deepesh-kn left a comment

Choose a reason for hiding this comment

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

I liked the code.
It is clean, readable and documented.
💯:raised_hands: blue-> :large_blue_circle:
I have very minor inline comments.

tools/deployment_tool/contract.js Outdated Show resolved Hide resolved
tools/deployment_tool/contract.js Outdated Show resolved Hide resolved
/**
* Returns the contract's address as detemined by the provided AddressGenerator.
*
* @param {Object|string} addressGeneratorOrAddress The AddressGenerator used for
Copy link
Contributor

Choose a reason for hiding this comment

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

I too prefer separate functions like setAddress and generateAddress

tools/deployment_tool/test/deployment_tools.test.js Outdated Show resolved Hide resolved
@hobofan
Copy link
Contributor Author

hobofan commented Jan 7, 2019

@deepesh-kn @schemar

I addressed the feedback in the latest commit. setAddress has been split up into setAddress and setGeneratedAddress.

- Get rid of the "instances" concept
- Order contracts before deployment
- Introduce a Contract class instead of using plain objects
- Split out address generation into IncrementingAddressGenerator
- Add documentation in JSDoc format
- Add eslint
- Use fixed dependency versions
- Switch from Jest to Mocha + Chai to be closer to Truffle test setup
- Remove unused tools/deploy_token_genesis.js
- Split off Contract#_ensureStateOneOf from Contract#_ensureState
- Refactor deployment_tool into multiple files
- Add `npm run test:deployment_tool` and hook into travis
- Add README to tools directory, explaining the usage of the deployment tool lib
- Added messages to asserts in tests
- Split up Contract#setAddress into Contract#setAddress and Contract#setGeneratedAddress
- Don't use console.log to write to STDOUT in merge_chainspec_accounts.js
Copy link
Contributor

@deepesh-kn deepesh-kn left a comment

Choose a reason for hiding this comment

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

LGTM 🚀

@deepesh-kn deepesh-kn merged commit 54d6269 into OpenST:develop Jan 8, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants