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 Constructor Function #595

Closed
wants to merge 10 commits into from
Closed

Add Constructor Function #595

wants to merge 10 commits into from

Conversation

dangell7
Copy link

There was no easy way to deploy a contract with a signed raw transaction.

How was it fixed?

By adding the deploy_data function. It can be used like so....

`

greeter_compiled_sol = compile_files(['contracts/Greeter.sol'])
greeter_contract_interface = greeter_compiled_sol['contracts/Greeter.sol:Greeter']
greeter_contract = w3.eth.contract(abi=greeter_contract_interface['abi'], bytecode=greeter_contract_interface['bin'])

contract_data = greeter_contract.deploy_data()

print(contract_data)

key = decrypt_account(w3.eth.coinbase, 'Coinbase-Master')

gas_price = w3.eth.gasPrice
gas_limit = 7000000

nonce = w3.eth.getTransactionCount(w3.eth.coinbase)

transaction = {
    'nonce': nonce,
    'gasPrice': gas_price,
    'gas': gas_limit,
    'to': '',
    'value': 1000,
    'data': contract_data,
    'chainId': None
}


signed = w3.eth.account.signTransaction(transaction, key)

raw_tx_hex = Web3.toHex(signed.rawTransaction)

print('Raw Tx Hex: %s' % raw_tx_hex)

tx_hash = w3.eth.sendRawTransaction(raw_tx_hex)

while w3.eth.getTransactionReceipt(tx_hash) == None:
    time.sleep(5)
    print('Waiting on Tranasaction')

tx_receipt = w3.eth.getTransactionReceipt(tx_hash)

contract_address = tx_receipt['contractAddress']

print('Greeter Contract Address: {}'.format(contract_address))

`

Cute Animal Picture

Cute animal picture

@pipermerriam
Copy link
Member

@harpangell7 this feature is captured here in #577 which defines an alternate API for this functionality which is more inline with the existing API for contract functions and events.

Please note that @zheli has claimed that issue, however, there is no open pull request at this time. I would encourage you to reach out to @zheli prior to investing time in converting this PR to match #577 (assuming you are interested in claiming the bounty).

@pipermerriam
Copy link
Member

Also, for contributions to be something we can merge, this would need to have tests and documentation written to cover the new functionality.

@dangell7
Copy link
Author

Honestly man, I'm not sure I feel comfortable asking for money lol. I just did it because I needed the functionality. I would hate to claim a bounty and not be able to produce. I will keep your tests and documentation in mind though. And I really do appreciate all the work that YOU do!! I'll just use the new API when its released, until then, I have my fork. lol

@pipermerriam
Copy link
Member

I only mention the bounty to be sure there's as little contention as possible. You are welcome to contribute the feature of your own altruistic/whatever motivation. Either way works.

@dangell7
Copy link
Author

dangell7 commented Jan 28, 2018

Well I needed to learn the tests anyways. So I added them and the documentation. But now my "check" with Travis it fails. :( Aslo, the tests dont assert the deploying to the chain, only that they can sign and return the correct signed transaction details. I couldn't find the tests on the sendRawTransaction().

@zheli
Copy link
Contributor

zheli commented Jan 28, 2018

@harpangell7 I have only done some research on current library interface and how it can be done, there is no serious code have been written yet. I would be happy to let you claim this issue (#577) if you want to.

@dangell7
Copy link
Author

Yeah I'd love to give it a try!! Give me 2 days, and if I cant figure it out, then I'll need some help.

@zheli
Copy link
Contributor

zheli commented Jan 28, 2018

@harpangell7 I don't know how to say this, but I actually made some progress on my pull request today... maybe we can work on it together and share the bounty? 😂

@dangell7
Copy link
Author

Thats fine, I'm working on the constructor api now. So if you want to tackle the fallback and we can meet in the middle?

@zheli
Copy link
Contributor

zheli commented Jan 28, 2018

@harpangell7 I think one of us should branch off from the other's branch to make it easier to track changes:) Maybe you can also tell me briefly how do you want the new constructor to work?

Right now I just need to ask @pipermerriam or @carver what do they mean by deprecating contract.constructor().deploy :)

@dangell7
Copy link
Author

@zheli go ahead and take this one. I was working on it but got busy and you claimed it first. But to answer your question I think they just mean deprecating contract.deloy() and making the contract.constructor().transact() the new deploy method. I'm curious to see how it turns out though!

@dangell7
Copy link
Author

@zheli I made a push to show you how I would do it.

@dangell7 dangell7 changed the title Add Deploy Data Function Add Constructor Function Jan 29, 2018
@zheli
Copy link
Contributor

zheli commented Jan 29, 2018

@harpangell7 thx man! Regarding to constructor(*,**), I am not sure if they mean to create a new constructor method in Contract class. As constructor is also a concept in object-oriented programming, in this case it could mean __init__(). At least that's how I understand it.

@dangell7
Copy link
Author

Oh interesting, I was thinking they meant the literal constructor, as contract(abi, bytecode) already init()'s the class, therefore, calling the constructor on the class made more sense to me. See the language is def lost. lol I also read the fallback as literally contract.fallback(*args, **kwargs).estimateGas(). This would eliminate the need to check for an actually function called fallback, because that function would be called using contract.functions.fallback(*args, **kwargs).estimateGas(). But its really up to them. lol

Copy link
Member

@pipermerriam pipermerriam left a comment

Choose a reason for hiding this comment

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

Lets see if I can answer all the questions.

We do actually mean a function named constructor so the literal API would be contract_instance.constructor(*args, **kwargs).transact({...})

I'm fine with you two working collaboratively on this. I'd prefer that the two of you determine how you want to split the bounty if you work on this collaboratively. I'd prefer to not be tasked with making that subjective decision.

@harpangell7 RE: the signing and sendRawTransaction testing.

I think your tests which assert things about the signed data are not really testing the correct thing, or at least, they are opaque in terms of what they are testing. Instead, an approach that I think will produce better tests would be:

  1. use c.constructor(...).buildTransaction() to build the txn dict.
  2. send normal deploy transaction with c.constructor(...).transact()
  3. compare built transaction with the transact() transaction and see that their data fields match.

'nonce': w3.eth.getTransactionCount(w3.eth.coinbase),
'chainId': None
}
>>> contract_data = token_contract.constructor(web3.eth.accounts[1], 12345).buildTransaction(transaction)
Copy link
Member

Choose a reason for hiding this comment

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

This code example seems wrong. The return value from token_contract.constructor(...).build_transaction(...) should be a transaction dictionary. Then, that returned dictionary should be what is passed into web3.eth.account.signTransaction.

Make sense?

Copy link
Author

Choose a reason for hiding this comment

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

Yes, that makes sense and I will add it now

#assert Web3.toHex(signed.hash) == tx_hash

#account = acct.privateKeyToAccount(private_key)
#assert account.signTransaction(txn) == signed
Copy link
Member

Choose a reason for hiding this comment

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

looks like this test has all of it's assertions commented out.

Copy link
Author

Choose a reason for hiding this comment

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

Will Finish

),
ids=['web3js_example', '31byte_r_and_s'],
)

Copy link
Member

Choose a reason for hiding this comment

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

odd extra whitespace.

Copy link
Author

Choose a reason for hiding this comment

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

Will fix

),
ids=['web3js_example', '31byte_r_and_s'],
)

Copy link
Member

Choose a reason for hiding this comment

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

odd extra whitespace.

Copy link
Author

Choose a reason for hiding this comment

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

Will Fix

ids=['web3js_example', '31byte_r_and_s'],
)


Copy link
Member

Choose a reason for hiding this comment

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

extra whitespace.

Copy link
Author

Choose a reason for hiding this comment

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

Will Fix

web3/contract.py Outdated
@@ -268,6 +287,52 @@ def deploy(cls, transaction=None, args=None, kwargs=None):
txn_hash = cls.web3.eth.sendTransaction(deploy_transaction)
return txn_hash

@classmethod
@deprecated_for("contract.<constructor>.buildTransaction")
def deploy_data(cls, transaction=None, args=None, kwargs=None):
Copy link
Member

Choose a reason for hiding this comment

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

Can we remove this method since it was never part of the original API.

Copy link
Author

Choose a reason for hiding this comment

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

Yes

web3/contract.py Outdated
@@ -1039,6 +1195,93 @@ def call_contract_function(abi,
return normalized_data


# Transact Constructor
# TODO
Copy link
Member

Choose a reason for hiding this comment

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

leftover comment?

Copy link
Author

Choose a reason for hiding this comment

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

Sorry, I leave my functions as TODO's until finished.

@dangell7
Copy link
Author

Gotcha, yeah the tests were definitely not perfected but I have a good place to start now.

@dangell7
Copy link
Author

@pipermerriam I'm running into some trouble with the tests now. When I call contract.constructor().buildTransaction() the result transaction doesn't include the "to" or the "nonce" fields. If I then try to pass this into the signTransaction I get the "TypeError: Not all fields initialized". So then if I try to enter the 'to' field, I have it giving me the 'ValueError: Cannot specify to for contract deployment' which makes sense. And If I try to pass the nonce, I receive a "Only the keys 'data/from/gas/gas_price/to/value' are allowed. Got extra keys: 'nonce'" error. I have made tests to assert that I get an error when trying to pass this information as there shouldn't be a deploy to address and the nonce I'm still trying to figure out. (I think it might just be a test thing, I'm checking in production). The nonce is a new error I haven't seen and I'm not sure how to handle it. Furthermore, the transaction v, s r from the transact() and the v, s, r from the buildTransaction() are different. I can confirm that the data is the same. I will continue testing until its production ready, I just wanted to update you.

@pipermerriam
Copy link
Member

cc @carver ^ might be something we need to address with how sign transaction validates contract deployment transactions.

Regarding signing the transactions. As for tests, I don't think you should need to sign the transaction as you should be able to simply submit it over web3.eth.sendTransaction without signing it. Maybe I'm missing something.

@carver
Copy link
Collaborator

carver commented Jan 29, 2018

it will automatically pre populate the "to" as ""

Cool that's roughly the approach I was going to suggest @harpangell7 . My instinct is that to should be None, and if that doesn't work in signTransaction then I'd like to update that function.

@dangell7
Copy link
Author

@pipermerriam @carver So buildTransaction() adds the default chainId and this is giving me a "eth_tester.exceptions.ValidationError: Only the keys 'data/from/gas/gas_price/nonce/to/value' are allowed. Got extra keys: 'chainId'". when I try to run web3.eth.sendTransaction. I've confirmed that this is only a testing error, as I can use buildTransaction({'chainId': 1}) just fine in my program.

@dangell7
Copy link
Author

@carver So I was incorrect in stating that it will auto 'to' to "". The reason it was doing that was because I hacked in built_transaction['to'] = '' just before returning to the user. Will there ever be an instance when they can deploy to a specific address? Not to sound stupid, but I want to make sure. With the current hack though, when you sign the transaction, it changes the "" to None.

@carver
Copy link
Collaborator

carver commented Jan 29, 2018

buildTransaction() adds the default chainId and this is giving me a "eth_tester.exceptions.ValidationError: Only the keys 'data/from/gas/gas_price/nonce/to/value' are allowed. Got extra keys: 'chainId'"

Can you open an issue on eth-tester about this (and link back here)?

Will there ever be an instance when they can deploy to a specific address?

Nope, the defined way to deploy a contract is to leave the to field empty. So building a transaction from a constructor must set to to empty.

@dangell7
Copy link
Author

@carver Purrfect!

@dangell7
Copy link
Author

@carver I’m just waiting on the eth-tester issue before I submit again...

@nueverest
Copy link

Would love to see this working.

@carver
Copy link
Collaborator

carver commented Mar 2, 2018

@nueverest Please subscribe to #666 which will be updated when the problem is fixed (even if this particular PR doesn't get merged)

@zheli zheli mentioned this pull request Mar 12, 2018
@carver
Copy link
Collaborator

carver commented Apr 3, 2018

Resolved in #693

@carver carver closed this Apr 3, 2018
*self.args,
**self.kwargs)

built_transaction['to'] = ''
Copy link
Author

Choose a reason for hiding this comment

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

Here was my suggestion to fix that bug. #739

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.

None yet

5 participants