Skip to content
This repository has been archived by the owner on Aug 2, 2021. It is now read-only.

swap: chequebook persistence #1797

Merged
merged 42 commits into from
Sep 26, 2019
Merged

Conversation

Eknir
Copy link
Contributor

@Eknir Eknir commented Sep 23, 2019

Rework from #1790 , now with a shorter git-history
closes #1796
Closes the first bullet point of #1739

  • Implements chequebook persistence by saving to the swap datastore any chequebook it connects to.
  • Upon boot-up the node will see if there is already a chequebook used for the current Ethereum NetworkID. If this is the case, this one will be used, otherwise a new one will be deployed or the passed-in value will be used. If a value is passed-in and a chequebook is used previously, the node does not boot up and will display an error message.
  • Saves the Ethereum Network ID the first time a node boots up with swap-enabled. Subsequently, don't allow a different Ethereum network ID to be used anymore.
  • Small refactor around the deploy logic in swap

This PR is a feature which is important to help users in rebooting their swap-enabled swarm. Without the feature, users would have to manually collect from the logs the address of their previously deployed chequebook and provide this the next time via command line/config/env.

Test scenario's by hand:

  1. Node boots up and deploys chequebook:
    /home/rinke/go/src/github.com/ethersphere/swarm/build/bin/swarm --swap --swap-backend-url https://rinkeby.infura.io/v3/<infure_key> --bzznetworkid=5 --password ~/.ethereum/swarm/standardPassword.txt

  2. Node boots up and uses previously deployed chequebook (from test scenario 1):
    /home/rinke/go/src/github.com/ethersphere/swarm/build/bin/swarm --swap --swap-backend-url https://rinkeby.infura.io/v3/<infure_key> --bzznetworkid=5 --password ~/.ethereum/swarm/standardPassword.txt

  3. Node boots up and uses previously deployed chequebook (from scenario 1 and 2), with chequebookAddress passed-in
    /home/rinke/go/src/github.com/ethersphere/swarm/build/bin/swarm --swap --swap-backend-url https://rinkeby.infura.io/v3/<infure_key> --bzznetworkid=5 --password ~/.ethereum/swarm/standardPassword.txt --swap-chequebook <address_from_before>

  4. Node does not boot up, with chequebookAddress passed-in. Reason: other chequebook used before
    /home/rinke/go/src/github.com/ethersphere/swarm/build/bin/swarm --swap --swap-backend-url https://rinkeby.infura.io/v3/<infure_key> --bzznetworkid=5 --password ~/.ethereum/swarm/standardPassword.txt --swap-chequebook <different_address>

  5. Remove data file swap.db

  6. Node boots up, with chequebook address passed-in
    /home/rinke/go/src/github.com/ethersphere/swarm/build/bin/swarm --swap --swap-backend-url https://rinkeby.infura.io/v3/<infure_key> --bzznetworkid=5 --password ~/.ethereum/swarm/standardPassword.txt --swap-chequebook <address_from_before>

  7. Remove file swap.db

  8. Node does not boot up, with chequebookAddress passed-in. Reason: contract validation failed
    /home/rinke/go/src/github.com/ethersphere/swarm/build/bin/swarm --swap --swap-backend-url https://rinkeby.infura.io/v3/<infure_key> --bzznetworkid=5 --password ~/.ethereum/swarm/standardPassword.txt --swap-chequebook <different_address>

  9. Node does not boot up when attempting to connect with a different than Ethereum Network ID
    /home/rinke/go/src/github.com/ethersphere/swarm/build/bin/swarm --swap --swap-backend-url https://ropsen.infura.io/v3/<infure_key> --bzznetworkid=5 --password ~/.ethereum/swarm/standardPassword.txt --swap-chequebook <different_address>

Copy link
Contributor

@mortelli mortelli left a comment

Choose a reason for hiding this comment

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

first pass through the code for me. i've left some comments, but i would like to request a more in-depth explanation for this network ID business, if possible :)

i think i am missing some of the high level logic that i need to understand in order to review the code better.

what's the idea behind using and storing network IDs, specifically?

thanks

contracts/swap/swap.go Outdated Show resolved Hide resolved
swap/swap.go Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
swap/swap_test.go Outdated Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
@Eknir
Copy link
Contributor Author

Eknir commented Sep 23, 2019

first pass through the code for me. i've left some comments, but i would like to request a more in-depth explanation for this network ID business, if possible :)

i think i am missing some of the high level logic that i need to understand in order to review the code better.

what's the idea behind using and storing network IDs, specifically?

thanks

@mortelli , thanks for the code review. The networkID is needed in the statestore, because otherwise if a node saves a chequebook when connecting to (say) Rinkeby, the node will attempt to load this same chequebook when the node connects to (say) Mainnet. The contract is obviously not deployed on mainnet, so we have to add the networkID as a key in the database. If not, the node will error on ValidateCode (swap/swap.go:489:bindToContractAt)

1_used_chequebook will yield the used chequebook address on mainnet,
3_used_chequebook will yield the used chequebook on Ropsten, etc.

Based on review from @ralph-pichler, I added the same logic to the key for balances used cheques and sent cheques, such that these keys are also not reused on different Ethereum networks

@Eknir Eknir changed the title Incentive chequebook persistance1 Incentive chequebook persistance Sep 23, 2019
Copy link
Contributor

@holisticode holisticode left a comment

Choose a reason for hiding this comment

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

A couple of minor things to look at please.

I am a bit nervous with this adding of a network ID again, but I can't pinpoint it and can't name any real problem for now

swap/swap.go Outdated Show resolved Hide resolved
swap/swap_test.go Outdated Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
swap/swap_test.go Outdated Show resolved Hide resolved
…de it impossible to connect with one statestore to multiple Ethereum network IDs
@Eknir Eknir changed the title Incentive chequebook persistance swap: chequebook persistance Sep 25, 2019
Copy link
Member

@ralph-pichler ralph-pichler left a comment

Choose a reason for hiding this comment

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

I don't think your networkID logic works because you're using different userBefore keys.

My idea was:

  • there is one usedBeforeNetworkId key
  • on start check if it exists
    • if it exists compare it against the current one and abort if it doesn't match
    • if it doesn't exist save it as usedBeforeNetworkId and continue

The rest of the PR looks good to me.

swap/swap.go Outdated Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
Copy link
Contributor

@holisticode holisticode left a comment

Choose a reason for hiding this comment

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

Good work tackling this bit of complex matter.

There are a couple of issues though. The most important ones:

  • Moving it to StartChequebook now gives the problem of other go routines messing up the prompt. I don't think we should overlook that. The reason is that you do all this initialization from Swarm.Start(). As I have commented elsewhere, this should actually be the correct way to initialize services, but we don't use it like this. I would suggest to move everything back into New to avoid these issues.

  • It seems to me that it is not possible anymore to provide an initial amount via config flag, can you check?

I like the idea of removing the InitialDepositAmount altogether from the Params, as it really only is used once and it doesn't need to be stored really. However make sure that the param can be set in any case.

// It assumes that there is an existing contract instance at the given address, or an error is returned
// This function is needed to communicate with remote Swap contracts (e.g. sending a cheque)
func InstanceAt(address common.Address, backend Backend) (Contract, error) {
simple, err := contract.NewSimpleSwap(address, backend)
Copy link
Contributor

Choose a reason for hiding this comment

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

Mind you he just moved what was existing, so it was like this before.

But I am ok changing these things too (this is why careful with moving things around without changing them, it becomes unclear IF something changed and by who)

swap/swap.go Outdated
@@ -143,28 +145,60 @@ func New(logpath string, dbPath string, prvkey *ecdsa.PrivateKey, backendURL str
// initialize the balances store
stateStore, err := state.NewDBStore(filepath.Join(dbPath, "swap.db"))
if err != nil {
return nil, fmt.Errorf("swap init error: %s", err)
return nil, fmt.Errorf("swap init error: error initializing statestore: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

Remember, only log//add an error if it has not been logged before (so useful to go and check), and/or if it actually adds to the available error message.

swap/swap.go Outdated
if err != nil {
return nil, fmt.Errorf("swap init error: error retrieving networkID from backendURL: %v", err)
}
var usedBeforeAtNetwork uint64
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree, these names are strange - what was used before?

I suggest something like firstConnectedBlockchain or something (Network is not descriptive enough and could be misleading, even if the call on the blockchain is called NetworkID() )

swap/swap.go Outdated Show resolved Hide resolved
swap/swap.go Outdated
}
// read from database
if err == nil {
usedBefore = true
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this safe enough? What if the state store went away?

That would be of course a user error. And in that case all balances and cheques would be gone anyway, which means that the node starts afresh.

I am just asking you to think of what this could mean for the complete initialization process here. I guess there is no problem whatsoever, please confirm.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If the user corrupts it's state store many things can go wrong. Let's say it would only delete the entry about the networkID. In this case, the user might connect on a different network, where he will (among other potential errors) not be able to cash the cheques which should be cashable according to the statestore.

swap/swap.go Outdated
@@ -491,8 +532,8 @@ func (s *Swap) deployLoop(opts *bind.TransactOpts, owner common.Address, default
time.Sleep(deployDelay)
}

if s.contract, tx, err = contract.Deploy(opts, s.backend, owner, defaultHarddepositTimeoutDuration); err != nil {
auditLog.Warn("can't send chequebook deploy tx", "try", try, "error", err)
if addr, tx, _, err = contract.Deploy(opts, s.backend, owner, defaultHarddepositTimeoutDuration); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

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

yes, this is production code, not test code, let's not ignore, and if it needs to be ignored, explain why

opts := bind.NewKeyedTransactor(swap.owner.privateKey)
opts.Value = big.NewInt(int64(swap.params.InitialDepositAmount))
opts.Context = ctx

swap.contract, _, err = cswap.Deploy(opts, swap.backend, swap.owner.address, defaultHarddepositTimeoutDuration)
address, _, _, err := cswap.Deploy(opts, swap.backend, swap.owner.address, defaultHarddepositTimeoutDuration)
Copy link
Contributor

Choose a reason for hiding this comment

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

Why is this change?

@@ -109,19 +108,6 @@ func TestNewSwarm(t *testing.T) {
}
},
},
{
Copy link
Contributor

Choose a reason for hiding this comment

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

Me too.

In fact on first glance (I only did a quick check) it seems as it is not possible to pass the initial amount via config variable anymore, and this tests would probably catch it!

swap/swap.go Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
Copy link
Contributor

@holisticode holisticode left a comment

Choose a reason for hiding this comment

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

Great job!

Copy link
Member

@ralph-pichler ralph-pichler left a comment

Choose a reason for hiding this comment

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

Nodes don't start anymore on empty datadirs, this needs to be fixed before merge.

As for the issue with StartChequebook I don't like it but if @holisticode and @mortelli think it's ok I'll accept that.

swap/swap.go Outdated Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
swap/swap.go Outdated Show resolved Hide resolved
Copy link
Member

@ralph-pichler ralph-pichler left a comment

Choose a reason for hiding this comment

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

LGTM

@ralph-pichler
Copy link
Member

One final request: Please change the title from persistance to persistence

@holisticode holisticode changed the title swap: chequebook persistance swap: chequebook persistence Sep 26, 2019
@holisticode holisticode merged commit 0362436 into master Sep 26, 2019
@mortelli mortelli deleted the incentive-chequebook_persistance1 branch November 14, 2019 18:54
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Saving cheques
4 participants