Skip to content

Commit

Permalink
Merge branch 'release/0.4.5' into fix/handle-dispatcher-errors
Browse files Browse the repository at this point in the history
  • Loading branch information
jazg committed Jul 16, 2021
2 parents cf11c7b + 75dfcbe commit bd0fbd0
Show file tree
Hide file tree
Showing 7 changed files with 115 additions and 59 deletions.
7 changes: 7 additions & 0 deletions cmd/lightnode/lightnode.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ func main() {

options.Whitelist = conf.Whitelist

// Replace Darknode whitelist with a custom one if it is set.
if os.Getenv("WHITELIST") != "" {
options = options.WithWhitelist(
parseWhitelist("WHITELIST"),
)
}

for chain, chainOpt := range options.Chains {
chainOpt.Confirmations = conf.Confirmations[chain]
if conf.MaxConfirmations[chain] != 0 {
Expand Down
114 changes: 74 additions & 40 deletions compat/v0/compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ package v0

import (
"context"
"crypto/ecdsa"
"encoding/base64"
"encoding/hex"
"fmt"
"math/big"
"strings"

"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/ethereum/go-ethereum/accounts/abi/bind"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
Expand Down Expand Up @@ -456,35 +456,55 @@ func V1TxParamsFromTx(ctx context.Context, params ParamsSubmitTx, bindings *bind
return jsonrpc.ParamsSubmitTx{}, err
}

var txHash B32

submitVersion := tx.Version0
// Convert the v0 tx to v1 transaction
if IsShiftIn(params.Tx.To) {
v1Tx, err = V1TxFromV0Mint(ctx, params.Tx, bindings)
v1Tx, txHash, err = V1TxFromV0Mint(ctx, params.Tx, bindings, pubkey)
if err != nil {
return jsonrpc.ParamsSubmitTx{}, err
}
} else {
v1Tx, err = V1TxFromV0Burn(ctx, params.Tx, bindings, network)
}
if err != nil {
return jsonrpc.ParamsSubmitTx{}, err
if err != nil {
return jsonrpc.ParamsSubmitTx{}, err
}

submitVersion = tx.Version1

// Calculate tx hash for v0 tx
txHash, err = V0TxHashFromTx(params.Tx)
if err != nil {
return jsonrpc.ParamsSubmitTx{}, err
}
}

// Calculate tx hash for v0 tx
txHash, err := V0TxHashFromTx(params.Tx)
copy(params.Tx.Hash[:], txHash[:])

// calculate the new tx format hash
h, err := tx.NewTxHash(submitVersion, v1Tx.Selector, v1Tx.Input)
if err != nil {
return jsonrpc.ParamsSubmitTx{}, err
}
copy(params.Tx.Hash[:], txHash[:])

// Store the v0/v1 mapping in the CompatStore
// We change the version version0 to indicate this tx is converted from a
// v0 transaction, so that when resolver tries to resolve this tx, it knows
// to return an v0 format response to the user.
v1Params := jsonrpc.ParamsSubmitTx{
Tx: v1Tx,
Tx: tx.Tx{
Version: tx.Version0,
Hash: h,
Input: v1Tx.Input,
Selector: v1Tx.Selector,
},
}
if err := store.PersistTxMappings(params.Tx, v1Tx); err != nil {

// Store the v0/v1 mapping in the CompatStore
if err := store.PersistTxMappings(params.Tx, v1Params.Tx); err != nil {
return jsonrpc.ParamsSubmitTx{}, err
}

// We change the version version0 to indicate this tx is converted from a
// v0 transaction, so that when resolver tries to resolve this tx, it knows
// to return an v0 format response to the user.
v1Params.Tx.Version = tx.Version0
return v1Params, nil
}

Expand Down Expand Up @@ -553,15 +573,22 @@ func NetParams(chain multichain.Chain, net multichain.Network) *chaincfg.Params
}
}

func V1TxFromV0Mint(ctx context.Context, v0tx Tx, bindings *binding.Binding) (tx.Tx, error) {
selector := tx.Selector(fmt.Sprintf("%s/fromEthereum", v0tx.To[0:3]))
func V1TxFromV0Mint(ctx context.Context, v0tx Tx, bindings *binding.Binding, pubkey *id.PubKey) (tx.Tx, B32, error) {
selector := tx.Selector(fmt.Sprintf("%s/toEthereum", v0tx.To[0:3]))
utxo := v0tx.In.Get("utxo").Value.(ExtBtcCompatUTXO)
vout := utxo.VOut.Int.Uint64()
txidB, err := chainhash.NewHashFromStr(hex.EncodeToString(utxo.TxHash[:]))
txidB, err := utxo.TxHash.MarshalBinary()
if err != nil {
return tx.Tx{}, err
return tx.Tx{}, B32{}, err
}

txl := len(txidB)
for i := 0; i < txl/2; i++ {
txidB[i], txidB[txl-1-i] = txidB[txl-1-i], txidB[i]
}
txid := txidB.CloneBytes()

txid := pack.NewBytes(txidB)

txindex := pack.NewU32(uint32(vout))

client := bindings.UTXOClient(selector.Asset().OriginChain())
Expand All @@ -570,23 +597,37 @@ func V1TxFromV0Mint(ctx context.Context, v0tx Tx, bindings *binding.Binding) (tx
Index: pack.NewU32(uint32(vout)),
})
if err != nil {
return tx.Tx{}, err
return tx.Tx{}, B32{}, err
}
amount := output.Value

token := v0tx.In.Get("token").Value.(ExtEthCompatAddress)
payload := pack.NewBytes(v0tx.In.Get("p").Value.(ExtEthCompatPayload).Value[:])
phash := engine.Phash(payload)
to := pack.String(v0tx.In.Get("to").Value.(ExtEthCompatAddress).String())
nonceBytes, err := v0tx.In.Get("n").Value.(B32).MarshalBinary()
if err != nil {
return tx.Tx{}, err
return tx.Tx{}, B32{}, err
}
var c [32]byte
copy(c[:], nonceBytes)
copy(c[:32], nonceBytes)
nonce := pack.NewBytes32(c)
nhash := engine.Nhash(nonce, txid, txindex)
// We need the v0 nhash to get the v0 ghash (to get the correct gateway)
nhash, err := engine.V0Nhash(nonce, txidB, txindex)
if err != nil {
return tx.Tx{}, B32{}, err
}

minter := common.HexToAddress(string(to))
ghash := engine.Ghash(selector, phash, minter[:], nonce)

// We need to use the v0 ghash to get the correct gateway produced by renjsv1
ghash, err := engine.V0Ghash(token[:], phash, minter[:], nonce)
if err != nil {
return tx.Tx{}, B32{}, err
}

// We need to provide the gpubkey for mints
pubkbytes := crypto.CompressPubkey((*ecdsa.PublicKey)(pubkey))
input, err := pack.Encode(engine.LockMintBurnReleaseInput{
Txid: txid,
Txindex: txindex,
Expand All @@ -597,12 +638,17 @@ func V1TxFromV0Mint(ctx context.Context, v0tx Tx, bindings *binding.Binding) (tx
Nonce: nonce,
Nhash: nhash,
Ghash: ghash,
Gpubkey: pack.NewBytes(pubkbytes),
})

if err != nil {
return tx.Tx{}, err
return tx.Tx{}, B32{}, err
}

return tx.NewTx(selector, pack.Typed(input.(pack.Struct)))
v0hash := MintTxHash(selector, ghash, txid, pack.U32(vout))
v1Tx, err := tx.NewTx(selector, pack.Typed(input.(pack.Struct)))

return v1Tx, v0hash, err
}

func V1TxFromV0Burn(ctx context.Context, v0tx Tx, bindings *binding.Binding, network multichain.Network) (tx.Tx, error) {
Expand Down Expand Up @@ -688,19 +734,7 @@ func V1TxFromV0Burn(ctx context.Context, v0tx Tx, bindings *binding.Binding, net
func V0TxHashFromTx(tx Tx) (B32, error) {
var hash B32
if IsShiftIn(tx.To) {
payload := pack.NewBytes(tx.In.Get("p").Value.(ExtEthCompatPayload).Value[:])
phash := engine.Phash(payload)
tokenAddr := tx.In.Get("token").Value.(ExtEthCompatAddress)
to := tx.In.Get("to").Value.(ExtEthCompatAddress)
n := tx.In.Get("n").Value.(B32)
var nonce pack.Bytes32
copy(nonce[:], n[:])
ghash, err := engine.V0Ghash(tokenAddr[:], phash, to[:], nonce)
if err != nil {
return B32{}, err
}
utxo := tx.In.Get("utxo").Value.(ExtBtcCompatUTXO)
copy(hash[:], crypto.Keccak256([]byte(fmt.Sprintf("txHash_%s_%s_%s_%d", tx.To, ghash, utxo.TxHash, utxo.VOut.Int.Int64()))))
panic("cannot handle shift-ins")
} else {
ref := tx.In.Get("ref").Value.(U64)
copy(hash[:], crypto.Keccak256([]byte(fmt.Sprintf("txHash_%s_%d", tx.To, ref.Int.Int64()))))
Expand Down
31 changes: 19 additions & 12 deletions compat/v0/compat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (
"github.com/renproject/darknode/binding"
"github.com/renproject/darknode/tx"
"github.com/renproject/id"
"github.com/renproject/lightnode/compat/v0"
v0 "github.com/renproject/lightnode/compat/v0"
"github.com/renproject/lightnode/db"
"github.com/renproject/lightnode/resolver"
"github.com/renproject/lightnode/testutils"
Expand Down Expand Up @@ -121,7 +121,7 @@ var _ = Describe("Compat V0", func() {
Expect(shardsResponse.Shards[0].Gateways[0].PubKey).Should(Equal("Akwn5WEMcB2Ff_E0ZOoVks9uZRvG_eFD99AysymOc5fm"))
})

It("should convert a v0 BTC Burn ParamsSubmitTx into an empty v1 ParamsSubmitTx", func() {
It("should convert a v0 BTC Burn ParamsSubmitTx into an v1 ParamsSubmitTx", func() {
params := testutils.MockBurnParamSubmitTxV0BTC()
store, _, bindings, pubkey := init(params, false)
ctx, cancel := context.WithCancel(context.Background())
Expand Down Expand Up @@ -162,14 +162,18 @@ var _ = Describe("Compat V0", func() {
Expect(err).ShouldNot(HaveOccurred())
Expect(len(keys)).Should(Equal(1))

Expect(v1.Tx.Selector).Should(Equal(tx.Selector("BTC/toEthereum")))

// Check that redis mapped the hashes correctly
hash := v1.Tx.Hash.String()
storedHash, err := client.Get(keys[0]).Result()
Expect(err).ShouldNot(HaveOccurred())
Expect(storedHash).Should(Equal(hash))

// v0 hash should have a mapping in the store
v0Hash, err := v0.V0TxHashFromTx(params.Tx)
ghash := v1.Tx.Input.Get("ghash").(pack.Bytes32)
txid := v1.Tx.Input.Get("txid").(pack.Bytes)
txindex := v1.Tx.Input.Get("txindex").(pack.U32)
v0Hash := v0.MintTxHash(v1.Tx.Selector, ghash, txid, txindex)
Expect(err).ShouldNot(HaveOccurred())

// btc txhash mapping
Expand All @@ -178,7 +182,7 @@ var _ = Describe("Compat V0", func() {
Expect(keys).Should(ContainElement(v0Hash.String()))

// v1 hash should be correct
v1Hash, err := tx.NewTxHash(tx.Version1, v1.Tx.Selector, v1.Tx.Input)
v1Hash, err := tx.NewTxHash(tx.Version0, v1.Tx.Selector, v1.Tx.Input)
Expect(err).ShouldNot(HaveOccurred())
Expect(hash).To(Equal(v1Hash.String()))
})
Expand All @@ -204,8 +208,10 @@ var _ = Describe("Compat V0", func() {
Expect(err).ShouldNot(HaveOccurred())
Expect(storedHash).Should(Equal(hash))

// v0 hash should have a mapping in the store
v0Hash, err := v0.V0TxHashFromTx(params.Tx)
ghash := v1.Tx.Input.Get("ghash").(pack.Bytes32)
txid := v1.Tx.Input.Get("txid").(pack.Bytes)
txindex := v1.Tx.Input.Get("txindex").(pack.U32)
v0Hash := v0.MintTxHash(v1.Tx.Selector, ghash, txid, txindex)
Expect(err).ShouldNot(HaveOccurred())

// btc txhash mapping
Expand All @@ -214,7 +220,7 @@ var _ = Describe("Compat V0", func() {
Expect(keys).Should(ContainElement(v0Hash.String()))

// v1 hash should be correct
v1Hash, err := tx.NewTxHash(tx.Version1, v1.Tx.Selector, v1.Tx.Input)
v1Hash, err := tx.NewTxHash(tx.Version0, v1.Tx.Selector, v1.Tx.Input)
Expect(err).ShouldNot(HaveOccurred())
Expect(hash).To(Equal(v1Hash.String()))
})
Expand All @@ -240,17 +246,18 @@ var _ = Describe("Compat V0", func() {
Expect(err).ShouldNot(HaveOccurred())
Expect(hash).Should(Equal(storedHash))

// v0 hash should have a mapping in the store
v0Hash, err := v0.V0TxHashFromTx(params.Tx)
Expect(err).ShouldNot(HaveOccurred())
ghash := v1.Tx.Input.Get("ghash").(pack.Bytes32)
txid := v1.Tx.Input.Get("txid").(pack.Bytes)
txindex := v1.Tx.Input.Get("txindex").(pack.U32)
v0Hash := v0.MintTxHash(v1.Tx.Selector, ghash, txid, txindex)

// btc txhash mapping
keys, err = client.Keys("*").Result()
Expect(err).ShouldNot(HaveOccurred())
Expect(keys).Should(ContainElement(v0Hash.String()))

// v1 hash should be correct
v1Hash, err := tx.NewTxHash(tx.Version1, v1.Tx.Selector, v1.Tx.Input)
v1Hash, err := tx.NewTxHash(tx.Version0, v1.Tx.Selector, v1.Tx.Input)
Expect(err).ShouldNot(HaveOccurred())
Expect(hash).To(Equal(v1Hash.String()))
})
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ require (
github.com/renproject/phi v0.1.0
github.com/renproject/surge v1.2.6
github.com/sirupsen/logrus v1.7.0
github.com/xlab/c-for-go v0.0.0-20201223145653-3ba5db515dcb // indirect
go.uber.org/zap v1.16.0
golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2
golang.org/x/time v0.0.0-20201208040808-7e3f01d25324
Expand Down
8 changes: 5 additions & 3 deletions resolver/resolver.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ func (resolver *Resolver) QueryBlocks(ctx context.Context, id interface{}, param
func (resolver *Resolver) SubmitTx(ctx context.Context, id interface{}, params *jsonrpc.ParamsSubmitTx, req *http.Request) jsonrpc.Response {
// Check if the tx is a v1 tx or v0 tx.
txVersion := params.Tx.Version
if params.Tx.Version == tx.Version0{
// We need to always make sure the tx to submit is a v1 tx as

if params.Tx.Version == tx.Version0 && params.Tx.Selector.IsBurn() {
// When burning, we need to always make sure the tx to submit is a v1 tx as
// darknode won't accept v0 tx.
params.Tx.Version = tx.Version1
}
Expand All @@ -89,10 +90,11 @@ func (resolver *Resolver) SubmitTx(ctx context.Context, id interface{}, params *
if response.Error != nil {
return response
}

v0tx, err := v0.TxFromV1Tx(params.Tx, false, resolver.bindings)
if err != nil {
resolver.logger.Errorf("[responder] cannot convert v1 tx to v0, %v", err)
jsonErr := jsonrpc.NewError(jsonrpc.ErrorCodeInternal, "fail to convert v1 tx to v0", nil)
jsonErr := jsonrpc.NewError(jsonrpc.ErrorCodeInternal, "failed to convert v1 tx to v0", nil)
return jsonrpc.NewResponse(id, nil, &jsonErr)
}

Expand Down
9 changes: 7 additions & 2 deletions resolver/resolver_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,8 +182,13 @@ var _ = Describe("Resolver", func() {
paramsJSON, err := json.Marshal(params)
Expect(err).ShouldNot(HaveOccurred())

v0Hash, err := v0.V0TxHashFromTx(params.Tx)
// It's a bit of a pain to make this robustly calculatable, so lets use the mock
// v0 tx's v0 hash directly
v0HashString := "fEwRnmZAjz6uzPZFGwYSa4OK8xtHVl2nsncCHvV0aKE="
v0HashBytes, err := base64.StdEncoding.DecodeString(v0HashString)
Expect(err).ShouldNot(HaveOccurred())
v0Hash := [32]byte{}
copy(v0Hash[:], v0HashBytes[:])

req, resp := validator.ValidateRequest(innerCtx, &http.Request{}, jsonrpc.Request{
Version: "2.0",
Expand All @@ -197,7 +202,7 @@ var _ = Describe("Resolver", func() {
resp = resolver.SubmitTx(ctx, nil, (req).(*jsonrpc.ParamsSubmitTx), nil)
Expect(resp.Error).Should(BeNil())

hashS, err := client.Get(v0Hash.String()).Result()
hashS, err := client.Get(v0HashString).Result()
Expect(err).ShouldNot(HaveOccurred())
Expect(hashS).ShouldNot(Equal(nil))

Expand Down
4 changes: 2 additions & 2 deletions resolver/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import (
"github.com/renproject/darknode/jsonrpc"
"github.com/renproject/darknode/tx"
"github.com/renproject/id"
"github.com/renproject/lightnode/compat/v0"
"github.com/renproject/lightnode/compat/v1"
v0 "github.com/renproject/lightnode/compat/v0"
v1 "github.com/renproject/lightnode/compat/v1"
"github.com/renproject/multichain"
"github.com/renproject/pack"
"github.com/sirupsen/logrus"
Expand Down

0 comments on commit bd0fbd0

Please sign in to comment.