Intro
An oracle is a dapp that can provide information to other dapps, code external to the blockchain(s), and people.
With a hard-fork imminent for Ethereum, there needs to be a way to reliably determine which tine (chain) one is on.
There are not many solutions I’ve seen so far - actually, just this one by Timon Rapp. Although, to be honest, I wasn’t looking that much, and this seemed a good exercise anyway.
How this oracle should work
It has to answer one question:
Is this the “classic” or the “hard-fork” chain?
That is reasonably simple. However, complications:
- it can’t answer “both”, at any time;
- it shouldn’t have a default answer;
- it could answer “none”, but only before the fork;
- the code must be identical, no matter the answer;
- the address must be identical;
- it would be very nice if the answer was available ASAP, preferably same block as the fork, please.
Critique
Barring the discovery of some yet-unknown vunerability in TheDAO
that would allow draining the DarkDAO off-shoot pre-fork, Timon’s solution
kind-of-fits the requirements above. 1
, 2
and 3
are guaranteed
and can be verified pre-fork.
Caveats:
- it uses the constructor to determine the answer, and therefore must be deployed after the fork. Its address is not known pre-fork, so code relying on the answer can’t be deployed before that.
- It must be simultaneously deployed on both chains, and that requires “transaction hygiene” to ensure that the oracle address is the same on both chains.
- On the up-side, it can be deployed by anyone. On the down-side, that could mean repetition of effort.
Pretty solid. Since we already have that, I wanted to try something else.
Code
It’s available on GitHub, and is already deployed on the pre-fork blockchain (see etherscan.io and live.ether.camp).
TheDAOHardForkOracle.sol
:
Does it fit the requirements?
Well, not exactly. Putting a fork oracle onto the chain pre-fork means another possible answer is introduced - “pre-fork”. The answer is no longer binary. One must work around that either by returning a numeric/symbolic answer, or by answering two questions.
This dapp does the latter by having flags ran
and forked
(notforked
is redundant, but can be conveniently used, too). They are public
,
meaning the Solidity compiler automatically produces accessors (value
return functions) for them.
By default, bool
variables are false
. The fallback function is
prohibited to run prior the fork (tested that). Prior
to the fork, ran()
is guaranteed to return false
, but so are the
other two - fitting complication 2
above.
1
and 3
are moot, and using forked()
without ran()
means
trouble pre-fork and some time after, until it is general knowledge
that the dapp works as intended.
4
and 5
are guaranteed and can be verified pre-fork.
6
has the same gothcha as Timon’s solution. Two clients have to be
automated to send a transaction on respective tines of the fork.
Why two conditions?
This hard fork will make certain alterations to the state of the EVM. Namely, moving ether from some accounts to another.
(More on this in my post on Reddit some time ago - it’s dated and doesn’t reflect the current spec exactly, but is non-technical enough).
One condition checks if the refund dapp has indeed been refunded. The other checks if the known split dapp still has its share. A successful hard-fork, I would argue, involves the former being met, but not the latter; and a successful continuation of the pre-fork state - the other way around.
That, and I was trying to work around complication 2
above. Different
than my previous attempt at writing Solidity, it’s
all on GitHub.
It does introduce an attack vector, though: anyone can drop 10
million ether into WithdrawDAO
’s account, pre-fork (yeah, right) or
post-fork on the “classic” chain. Then this dapp couldn’t reliably
determine which chain it’s on (on one of the fork’s tines), rendering
it useless (on both tines).
As with Timon’s dapp, “some yet-unknown vunerability in TheDAO that would allow draining the DarkDAO off-shoot pre-fork” would result in the same failure.
Conclusion
So, there you go. Do you need to run some dapp on block #190005, but
deploy it before the fork? Now you can. Make sure to check ran()
,
though, or send a transaction first if you’re dire.
Any attached ether will be locked forever. This is intentional, since some (dated?) clients don’t allow sending 0 ether.
Liked this?
The dapp and article took ~ 8 hours to write and check, since I’m new and slow.
If you’d like to donate, check my drop page.