-
Notifications
You must be signed in to change notification settings - Fork 92
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
eth/dex/client: Add initiateBatch function #1251
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good stuff. A couple Solidity questions, mainly wondering if the solc optimization would just end up with the same code anyway.
require(initiations[i].refundTimestamp > 0); | ||
require(swaps[initiations[i].secretHash].state == State.Empty); | ||
initVal = initVal + initiations[i].value; | ||
swaps[initiations[i].secretHash].initBlockNumber = block.number; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unless it changes the actual execution and therefore gas spent, can we make initiations[i].secretHash
a local variable?
Actually, and I'm just trying to learn some Solidity, but I see some examples where you bind to the entry in the map and assign like:
var swap = swaps[secretHash];
swap.initBlockNumer = block.number;
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've updated it. It saves some gas and looks nicer.
In solidity, reference variables are either in the storage, memory, or calldata. Storage is the memory that gets persisted in the global ethereum state. In my change I've created a local reference to a location in storage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks reasonable to me. I can't think of any loopholes created by this.
It changes the amount of gas needed for funding initiations, or the swap size, by making it variable, but we can deal with that.
swaps[initiations[i].secretHash].state = State.Filled; | ||
} | ||
|
||
require(initVal == msg.value); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this function will succeed with a zero length initiations
array, which may be fine but not sure.
Also, there is no upward limit on the number of initiations
. I wonder if that is ok?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think both are fine. If someone calls with a zero length array, they just waste some gas and change nothing. No reason to waste other people's gas with an extra check.
For the upward limit, I think anything is fine as long as the user has enough gas to pay for it. Maybe there are some limits on the amount of data that's allowed to be passed into a transaction..I'll look into it.
I've taken out the
I think for the swap size we can just use the amount of gas needed for a single swap, and then the user will just save some money if multiple swaps are submitted simultaneously. In the interest of simplicity, maybe we could remove the non-batch initiate function. The gas difference is negligible. |
@@ -118,13 +117,14 @@ contract ETHSwap { | |||
senderIsOrigin() | |||
isNotInitiated(secretHash) | |||
{ | |||
swaps[secretHash].initBlockNumber = block.number; | |||
swaps[secretHash].refundBlockTimestamp = refundTimestamp; | |||
swaps[secretHash].secretHash = secretHash; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wanted to test how much gas was saved by removing secretHash, and it gives the same estimate...
I'm running both the abigen and genruntime.sh commands, and can see the changes reflected in both BinRuntimeV0.go and contract.go. I've restarted the harness.
What am I missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You need to update the line in harness.sh
which specifies the bytecode.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing secretHash was the bulk of the savings.. the other changes saved only a little bit. The SSTORE op code which sets a value in storage from 0 to non zero costs 20k gas, and we're no longer doing one of those.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for clarifying. Seems like we have the same contract hex string in a few places. Maybe we can address that at some point.
I was curious about the secretHash savings because mappings don't save the key anywhere. Even though there's no ranging on contracts with Solidity because of this, I have to think that inspecting the mapping in the state with... I don't know... geth and EVM magic, there would surely be a way to debug and analyze the contents of the mapping, at least for a full node. Even though from the contract's point of view this does not matter because you must have the hash to retrieve a value type, I wonder if we'd regret not having the hash recorded anywhere for incomplete swaps.
Not a strong argument for storing it though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like it would be pretty hard to get those:
https://stackoverflow.com/a/65530927
We could emit an event every time someone initiates a swap, and then a full node could check them. This would much cheaper. Can you think of any use case for this?
Also if there's ETH left unclaimed in the contract after a year maybe we could have some kind of game, and the winner could take it haha.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like you don't need an archival node to check current state, just https://github.com/ethereum/go-ethereum/blob/0a3993c558616868e35f9730e92c704ac16ee437/core/state/statedb.go#L634
An event log does sound nice, but I think you could also look for all txns that call the initiate method(s) and check the call data too, right? EDIT: oh that would be an archival thing too, which presumably you could do with etherscan somehow
Anyway, I'm just chatting. We can do without this field.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah etherscan def runs an archival node. Maybe we can query etherscan if we're trying to do something with the secret hashes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM and works alright.
But the existing TestInitiateGas
returns a ridiculously low gas estimate for me until I run TestInitiateBatchGas
and retry TestInitiateGas
. My harness is running geth 1.10.10.
t.Fatalf("unexpected error for test %v: %v", test.name, err) | ||
} | ||
|
||
// It appears the receipt is only accessable after the tx is mined. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
accessible
This PR adds a batch initiation function to the ETH swap contract. This function saves a bit of gas when initiating multiple swaps simultaneously, and also allows ETH to conform to the current wallet interface which requires swaps to be submitted together.
Here are some logs from the rpc test:
We save ~20k gas for each additional swap that is batched.