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:
parent
bc3714fc73
commit
7903402fa6
|
@ -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())),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package common
|
||||
|
||||
type BridgeWatcher interface {
|
||||
WatchLockups(events chan *ChainLock) error
|
||||
}
|
|
@ -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)
|
||||
}
|
|
@ -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
|
||||
}
|
||||
)
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue