Deterministic hashes for ETH lockups

We're missing a nonce for truly unique hashes - for now, two
identical transfers will only be executed once.
This commit is contained in:
Leo 2020-08-17 19:29:25 +02:00
parent bc3714fc73
commit 7903402fa6
6 changed files with 65 additions and 36 deletions

View File

@ -141,6 +141,7 @@ func main() {
zap.String("source", hex.EncodeToString(k.SourceAddress[:])),
zap.String("target", hex.EncodeToString(k.TargetAddress[:])),
zap.String("amount", k.Amount.String()),
zap.String("hash", hex.EncodeToString(k.Hash())),
)
}
}

View File

@ -0,0 +1,5 @@
package common
type BridgeWatcher interface {
WatchLockups(events chan *ChainLock) error
}

View File

@ -0,0 +1,46 @@
package common
import (
"crypto/sha256"
"encoding/json"
"math/big"
"github.com/ethereum/go-ethereum/common"
"github.com/certusone/wormhole/bridge/pkg/vaa"
)
type ChainLock struct {
TxHash common.Hash
SourceAddress vaa.Address
TargetAddress vaa.Address
SourceChain vaa.ChainID
TargetChain vaa.ChainID
TokenChain vaa.ChainID
TokenAddress vaa.Address
Amount *big.Int
}
// Hash returns a deterministic hash of the given ChainLock, meant to be used
// as primary key for the distributed round of signing.
//
// TODO: the ETH contract is missing a nonce, so it's not yet deterministic
func (l *ChainLock) Hash() []byte {
// TODO: json.Marshal being deterministic is an implementation detail - what guarantees do we need?
// We do not necessarily need stable serialization across releases, but they do need to be unique.
b, err := json.Marshal(l)
if err != nil {
panic(err)
}
h := sha256.New()
h.Write(b)
return h.Sum(nil)
}

View File

@ -1,25 +0,0 @@
package common
import (
"github.com/certusone/wormhole/bridge/pkg/vaa"
"math/big"
)
type (
BridgeWatcher interface {
WatchLockups(events chan *ChainLock) error
}
ChainLock struct {
SourceAddress vaa.Address
TargetAddress vaa.Address
SourceChain vaa.ChainID
TargetChain vaa.ChainID
TokenChain vaa.ChainID
TokenAddress vaa.Address
Amount *big.Int
}
)

View File

@ -3,17 +3,19 @@ package ethereum
import (
"context"
"fmt"
"github.com/certusone/wormhole/bridge/pkg/common"
"github.com/certusone/wormhole/bridge/pkg/ethereum/abi"
"github.com/certusone/wormhole/bridge/pkg/supervisor"
"github.com/certusone/wormhole/bridge/pkg/vaa"
"sync"
"time"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
eth_common "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/ethclient"
"go.uber.org/zap"
"sync"
"time"
"github.com/certusone/wormhole/bridge/pkg/common"
"github.com/certusone/wormhole/bridge/pkg/ethereum/abi"
"github.com/certusone/wormhole/bridge/pkg/supervisor"
"github.com/certusone/wormhole/bridge/pkg/vaa"
)
type (
@ -30,8 +32,6 @@ type (
pendingLock struct {
lock *common.ChainLock
txHash eth_common.Hash
height uint64
}
)
@ -73,6 +73,7 @@ func (e *EthBridgeWatcher) Run(ctx context.Context) error {
return
case ev := <-sink:
lock := &common.ChainLock{
TxHash: ev.Raw.TxHash,
SourceAddress: ev.Sender,
TargetAddress: ev.Recipient,
SourceChain: vaa.ChainIDEthereum,
@ -87,7 +88,6 @@ func (e *EthBridgeWatcher) Run(ctx context.Context) error {
e.pendingLocksGuard.Lock()
e.pendingLocks[ev.Raw.TxHash] = &pendingLock{
lock: lock,
txHash: ev.Raw.TxHash,
height: ev.Raw.BlockNumber,
}
e.pendingLocksGuard.Unlock()
@ -121,7 +121,7 @@ func (e *EthBridgeWatcher) Run(ctx context.Context) error {
// Transaction was dropped and never picked up again
if pLock.height+4*e.minConfirmations <= blockNumberU {
logger.Debug("lockup timed out", zap.Stringer("tx", pLock.txHash),
logger.Debug("lockup timed out", zap.Stringer("tx", pLock.lock.TxHash),
zap.Stringer("number", ev.Number))
delete(e.pendingLocks, hash)
continue
@ -129,7 +129,7 @@ func (e *EthBridgeWatcher) Run(ctx context.Context) error {
// Transaction is now ready
if pLock.height+e.minConfirmations <= ev.Number.Uint64() {
logger.Debug("lockup confirmed", zap.Stringer("tx", pLock.txHash),
logger.Debug("lockup confirmed", zap.Stringer("tx", pLock.lock.TxHash),
zap.Stringer("number", ev.Number))
delete(e.pendingLocks, hash)
e.evChan <- pLock.lock

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache 2
// TODO(hendrik): reentrancy protection for all methods
// TODO(hendrik): switch-over feature
pragma solidity ^0.6.0;
pragma experimental ABIEncoderV2;
@ -197,6 +198,7 @@ contract Wormhole {
isWrappedAsset[asset] = true;
}
// TODO(hendrik): nonce
function lockAssets(
address asset,
uint256 amount,