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 off-chain signature generation and on-chain verification #7

Merged
merged 3 commits into from
Jan 26, 2018

Conversation

JasoonS
Copy link
Contributor

@JasoonS JasoonS commented Jan 15, 2018

Fixes #6

Copy link
Owner

@andytudhope andytudhope left a comment

Choose a reason for hiding this comment

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

Sorry for the delay - was in the air.
This is really great work, thank you! Have left some comments (mostly just questions from someone still on the learning curve ;) ).
One thing I am still struggling a little with:

Running tests the first time failed at the last one:

Contract: NonFungibleToken issuing signature validation when the attacker tries to use a signature generated by a party other than the `collectableCouponIssuer` reverts:
     AssertionError: Expected "revert", got AssertionError: assert.fail() instead

and then worked perfectly when I tried to run it again a few seconds later. Probably just some local weirdness, but any idea what might have caused that? So strange...

Anyway, like I say, great work! Now to think about next steps... How to submit the signed transaction to the network (happy with just using infura rather than requiring running a full geth node so that we can keep the backend super light and not require a more expensive VM) and show the user the artwork associated with that token on their phone in an awesome and artistic kind of way...

@@ -11,6 +11,8 @@
"babel-loader": "6.2.7",
"babel-preset-react-app": "^2.0.1",
"case-sensitive-paths-webpack-plugin": "1.1.4",
"chai-as-promised": "^7.1.1",
"chai-bignumber": "^2.0.2",
"chalk": "1.1.3",
"connect-history-api-fallback": "1.3.0",
"cross-spawn": "4.0.2",
Copy link
Owner

Choose a reason for hiding this comment

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

Please add
"ethereumjs-abi": "^0.6.5",
to the package.json - your choice as to whether in dependencies or devDependencies. Would be inclined to go with the second if I were to have my way seeing as it is only required in the test suite.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ah, ok, I'll completely remove that, it isn't necessary in any of the tests yet, if it becomes necessary then I'll add it again.

Copy link
Owner

Choose a reason for hiding this comment

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

perfect

}

function getAddress(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public pure returns(address) {
bytes memory prefix = "\x19Ethereum Signed Message:\n32";
Copy link
Owner

Choose a reason for hiding this comment

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

Would you mind leaving a few comments in this file? In particular, could you explain the need to have prefix in memory rather than storage as well as the form of the prefix you have gone with here? What exactly is going on 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.

Very good point! Haha, this should be done off chain! :)

Copy link
Owner

Choose a reason for hiding this comment

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

👍 cool, was thinking that there was something else weird and new I'd need to learn about :/n32 and stuff 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hmm, very wierd the hash I'm getting by computing this off chain is different, I'll get it right though, I hope 😅

newOwner.should.be.equal(recipientAddress)

const {hash, v, r, s} = signatureObject
await assertRevert(token.claimCollectableWithCoupon(_firstTokenId, hash, v, r, s, {from: recipientAddress}))
Copy link
Owner

@andytudhope andytudhope Jan 15, 2018

Choose a reason for hiding this comment

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

This test would make more sense to me if it were {from: attackerAddress}. As it currently stands, my understanding is that this reverts because it calls NonFungibleCollectable at L40 and reverts due to NonFungibleToken at L235 (i.e. you have transferred the token to the recipientAddress and having the recipient try to claim a token they own already reverts...) BTW changing to attackerAddress also reverts as expected.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ok, sure, I can change that :)

@JasoonS
Copy link
Contributor Author

JasoonS commented Jan 16, 2018

No problem! :)

Yes, I actually don't know why it does that (the revert vs assert error), it must be some confusion in ganache, because I've also noticed it as a transient issue, maybe I'll just change the 'assertRevert' code to accept assert errors also (basically we just want to know that the smart contract isn't processing it).

I'm not sure what you mean by 'How to submit the signed transaction to the network', we'll use the provider in Status won't we? This is the transaction that the user will execute on their device (the signature is just the proof that the server gives its approval). We will though need to make sure the server isn't compromised, but that is a given.

@andytudhope
Copy link
Owner

andytudhope commented Jan 16, 2018

This is the transaction that the user will execute on their device

This is why you should not review code at midnight 😅 Absolutely right, my bad.
Sounds good on tightening up the tests too, thank you.

…aning more explicit - remove unused variable
@JasoonS
Copy link
Contributor Author

JasoonS commented Jan 16, 2018

Should have fixed up the lose ends above

Copy link
Owner

@andytudhope andytudhope left a comment

Choose a reason for hiding this comment

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

Even better, thank you! One minor comment in the tests still, but then we should be good here.

const {hash, v, r, s} = signatureObject
await assertRevert(token.claimCollectableWithCoupon(_secondTokenId, hash, v, r, s, {from: recipientAddress}))
const {prefixedHash, v, r, s} = signatureObject
await assertRevert(token.claimCollectableWithCoupon(_secondTokenId, prefixedHash, v, r, s, {from: recipientAddress}))
const newOwner = await token.ownerOf(_firstTokenId)
Copy link
Owner

Choose a reason for hiding this comment

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

I think this should be const newOwner = await token.ownerOf(_secondTokenId) in order to agree with trying to claim the token that has not been assigned by a valid coupon. Changing it still gets the expected revert().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, agreed, but since we are using the signature for the 1st token, it makes sense to test both tokens actually

@JasoonS
Copy link
Contributor Author

JasoonS commented Jan 17, 2018

Btw, I'll keep working on this for the next while at this sort of pace, and I'll try give you accurate predictions when I'll get done, just so you can stay on top of progress :)

@andytudhope andytudhope merged commit b58f422 into andytudhope:master Jan 26, 2018
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.

2 participants