Commit e1c83203 authored by Heimdall's avatar Heimdall

Resolve "Don't sign old transactions"

parent 4cefbdee
......@@ -7,6 +7,7 @@ import (
"sync"
"time"
"github.com/blang/semver"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/pkg/errors"
"github.com/prometheus/client_golang/prometheus"
......@@ -18,11 +19,12 @@ import (
"gitlab.com/thorchain/thornode/bifrost/config"
"gitlab.com/thorchain/thornode/bifrost/metrics"
"gitlab.com/thorchain/thornode/bifrost/pkg/chainclients"
pubkeymanager "gitlab.com/thorchain/thornode/bifrost/pubkeymanager"
"gitlab.com/thorchain/thornode/bifrost/pubkeymanager"
"gitlab.com/thorchain/thornode/bifrost/thorclient"
"gitlab.com/thorchain/thornode/bifrost/thorclient/types"
"gitlab.com/thorchain/thornode/bifrost/tss"
"gitlab.com/thorchain/thornode/common"
"gitlab.com/thorchain/thornode/constants"
"gitlab.com/thorchain/thornode/x/thorchain"
ttypes "gitlab.com/thorchain/thornode/x/thorchain/types"
)
......@@ -300,6 +302,17 @@ func (s *Signer) sendKeygenToThorchain(height int64, poolPk common.PubKey, blame
func (s *Signer) signAndBroadcast(item TxOutStoreItem) error {
height := item.Height
tx := item.TxOutItem
blockHeight, err := s.thorchainBridge.GetBlockHeight()
if err != nil {
s.logger.Error().Err(err).Msgf("fail to get block height")
return err
}
// TODO hardcode it as 0.1.0 for now, will need to get it appropriately later
cv := constants.GetConstantValues(semver.MustParse("0.1.0"))
if blockHeight-height > cv.GetInt64Value(constants.SigningTransactionPeriod) {
s.logger.Error().Msgf("tx was created at block height(%d), now it is (%d), it is older than (%d) blocks , skip it ", height, blockHeight, cv.GetInt64Value(constants.SigningTransactionPeriod))
return nil
}
chain, err := s.getChain(tx.Chain)
if err != nil {
s.logger.Error().Err(err).Msgf("not supported %s", tx.Chain.String())
......
......@@ -770,10 +770,6 @@ github.com/zondax/hid v0.9.0/go.mod h1:l5wttcP0jwtdLjqjMMWFVEE7d1zO0jvSPA9OPZxWp
github.com/zondax/ledger-go v0.9.0/go.mod h1:b2vIcu3u9gJoIx4kTWuXOgzGV7FPWeUktqRqVf6feG0=
github.com/zondax/ledger-go v0.11.0 h1:EEqUh6eaZucWAaGo87G7sJiqRNJpzBZr+I9PpGgjjPg=
github.com/zondax/ledger-go v0.11.0/go.mod h1:NI6JDs8VWwgh+9Bf1vPZMm9Xufp2Q7Iwm2IzxJWzmus=
gitlab.com/thorchain/tss/go-tss v0.0.0-20200311063750-ecbf4b87e492 h1:fEpRLHPsS/yyplhSMQsN1NNRQ949izo8dJxDAN4D2IY=
gitlab.com/thorchain/tss/go-tss v0.0.0-20200311063750-ecbf4b87e492/go.mod h1:ezIsYgnT42fXgani/rJvF7yNSbI1yr6RsZD06aC6yJg=
gitlab.com/thorchain/tss/go-tss v0.0.0-20200312094649-aef9dc0dbd42 h1:Lhocay+Q3xKM27xg6wDpjgPAkC6pRNXx13VfwGTRUXo=
gitlab.com/thorchain/tss/go-tss v0.0.0-20200312094649-aef9dc0dbd42/go.mod h1:ezIsYgnT42fXgani/rJvF7yNSbI1yr6RsZD06aC6yJg=
gitlab.com/thorchain/tss/go-tss v0.0.0-20200320003459-54d30a7e8a20 h1:AWFD7DINvj1UuPG8ls4aA8j1wKeUXC4h2eaJG0W/phc=
gitlab.com/thorchain/tss/go-tss v0.0.0-20200320003459-54d30a7e8a20/go.mod h1:ezIsYgnT42fXgani/rJvF7yNSbI1yr6RsZD06aC6yJg=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
......
......@@ -173,10 +173,7 @@ func (h ObservedTxInHandler) handleV1(ctx sdk.Context, version semver.Version, m
vault.InboundTxCount += 1
memo, _ := ParseMemo(tx.Tx.Memo) // ignore err
if vault.IsYggdrasil() && memo.IsType(txYggdrasilFund) {
vault.PendingTxCount -= 1
if vault.PendingTxCount < 0 {
vault.PendingTxCount = 0
}
vault.RemovePendingTxBlockHeights(memo.GetBlockHeight())
}
if err := h.keeper.SetVault(ctx, vault); err != nil {
ctx.Logger().Error("fail to save vault", "error", err)
......
......@@ -145,10 +145,8 @@ func (h ObservedTxOutHandler) handleV1(ctx sdk.Context, msg MsgObservedTxOut) sd
vault.OutboundTxCount += 1
memo, _ := ParseMemo(tx.Tx.Memo) // ignore err
if vault.IsAsgard() && memo.IsType(txMigrate) {
vault.PendingTxCount -= 1
if vault.PendingTxCount < 0 {
vault.PendingTxCount = 0
}
// only remove the block height that had been specified in the memo
vault.RemovePendingTxBlockHeights(memo.GetBlockHeight())
}
if err := h.keeper.SetVault(ctx, vault); err != nil {
ctx.Logger().Error("fail to save vault", "error", err)
......
......@@ -6,6 +6,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/pkg/errors"
"gitlab.com/thorchain/thornode/common"
"gitlab.com/thorchain/thornode/constants"
)
......
......@@ -8,9 +8,10 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
. "gopkg.in/check.v1"
tssCommon "gitlab.com/thorchain/tss/go-tss/common"
"gitlab.com/thorchain/thornode/common"
"gitlab.com/thorchain/thornode/constants"
tssCommon "gitlab.com/thorchain/tss/go-tss/common"
)
func TestPackage(t *testing.T) { TestingT(t) }
......@@ -200,7 +201,7 @@ func (s *ThorchainSuite) TestChurn(c *C) {
ctx = ctx.WithBlockHeight(vault.StatusSince + (migrateInterval * 7))
vault, err = keeper.GetVault(ctx, vault.PubKey)
c.Assert(err, IsNil)
vault.PendingTxCount = 0 // reset pending tx count
vault.PendingTxBlockHeights = nil
c.Assert(keeper.SetVault(ctx, vault), IsNil)
vaultMgr.EndBlock(ctx, ver, consts) // should attempt to send 100% of the coin values
items, err = txOutStore.GetOutboundItems(ctx)
......@@ -310,9 +311,9 @@ func (s *ThorchainSuite) TestRagnarok(c *C) {
}
c.Assert(keeper.SetVault(ctx, asgard), IsNil)
//////////////////////////////////////////////////////////
//////////////// Start Ragnarok Protocol /////////////////
//////////////////////////////////////////////////////////
// ////////////////////////////////////////////////////////
// ////////////// Start Ragnarok Protocol /////////////////
// ////////////////////////////////////////////////////////
vd := VaultData{
BondRewardRune: sdk.NewUint(1000_000 * common.One),
TotalBondUnits: sdk.NewUint(3 * 1014), // block height * node count
......
......@@ -8,6 +8,7 @@ import (
"github.com/pkg/errors"
"gitlab.com/thorchain/thornode/common"
"gitlab.com/thorchain/thornode/constants"
)
// VaultType there are two different types of Vault in thorchain
......@@ -32,16 +33,16 @@ const (
// Vault usually represent the pool we are using
type Vault struct {
BlockHeight int64 `json:"block_height"`
PubKey common.PubKey `json:"pub_key"`
Coins common.Coins `json:"coins"`
Type VaultType `json:"type"`
Status VaultStatus `json:"status"`
StatusSince int64 `json:"status_since"`
Membership common.PubKeys `json:"membership"`
InboundTxCount int64 `json:"inbound_tx_count"`
OutboundTxCount int64 `json:"outbound_tx_count"`
PendingTxCount int64 `json:"pending_tx_count"`
BlockHeight int64 `json:"block_height"`
PubKey common.PubKey `json:"pub_key"`
Coins common.Coins `json:"coins"`
Type VaultType `json:"type"`
Status VaultStatus `json:"status"`
StatusSince int64 `json:"status_since"`
Membership common.PubKeys `json:"membership"`
InboundTxCount int64 `json:"inbound_tx_count"`
OutboundTxCount int64 `json:"outbound_tx_count"`
PendingTxBlockHeights []int64 `json:"-"`
}
type Vaults []Vault
......@@ -182,6 +183,45 @@ func (v *Vault) SubFunds(coins common.Coins) {
}
}
// AppendPendingTxBlockHeights will add current block height into the list , also remove the block height that is too old
func (v *Vault) AppendPendingTxBlockHeights(blockHeight int64, constAccessor constants.ConstantValues) {
heights := []int64{
blockHeight,
}
for _, item := range v.PendingTxBlockHeights {
if (blockHeight - item) <= constAccessor.GetInt64Value(constants.SigningTransactionPeriod) {
heights = append(heights, item)
}
}
v.PendingTxBlockHeights = heights
}
// RemovePendingTxBlockHeights remove the given block height from internal pending tx block height
func (v *Vault) RemovePendingTxBlockHeights(blockHeight int64) {
idxToRemove := -1
for idx, item := range v.PendingTxBlockHeights {
if item == blockHeight {
idxToRemove = idx
break
}
}
if idxToRemove != -1 {
v.PendingTxBlockHeights = append(v.PendingTxBlockHeights[:idxToRemove], v.PendingTxBlockHeights[idxToRemove+1:]...)
}
}
// LenPendingTxBlockHeights count how many outstanding block heights in the vault
// if the a block height is older than SigningTransactionPeriod , it will ignore
func (v *Vault) LenPendingTxBlockHeights(currentBlockHeight int64, constAccessor constants.ConstantValues) int {
total := 0
for _, item := range v.PendingTxBlockHeights {
if (currentBlockHeight - item) <= constAccessor.GetInt64Value(constants.SigningTransactionPeriod) {
total++
}
}
return total
}
// SortBy order coins by the given asset
func (vs Vaults) SortBy(sortBy common.Asset) Vaults {
// use the vault pool with the highest quantity of our coin
......
package types
import (
"github.com/blang/semver"
sdk "github.com/cosmos/cosmos-sdk/types"
. "gopkg.in/check.v1"
"gitlab.com/thorchain/thornode/common"
"gitlab.com/thorchain/thornode/constants"
)
type VaultSuite struct{}
......@@ -69,3 +71,23 @@ func (s *VaultSuite) TestGetTssSigners(c *C) {
c.Assert(keys[0].Equals(nodeAccounts[0].PubKeySet.Secp256k1), Equals, true)
c.Assert(keys[1].Equals(nodeAccounts[1].PubKeySet.Secp256k1), Equals, true)
}
func (s *VaultSuite) TestPendingTxBlockHeights(c *C) {
vault := NewVault(12, ActiveVault, AsgardVault, GetRandomPubKey())
version := semver.MustParse("0.1.0")
constAccessor := constants.GetConstantValues(version)
vault.AppendPendingTxBlockHeights(1, constAccessor)
c.Assert(vault.LenPendingTxBlockHeights(2, constAccessor), Equals, 1)
c.Assert(vault.LenPendingTxBlockHeights(102, constAccessor), Equals, 0)
for i := 0; i < 100; i++ {
vault.AppendPendingTxBlockHeights(int64(i), constAccessor)
}
c.Assert(vault.LenPendingTxBlockHeights(100, constAccessor), Equals, 101)
vault.AppendPendingTxBlockHeights(1000, constAccessor)
c.Assert(vault.LenPendingTxBlockHeights(1001, constAccessor), Equals, 1)
vault.RemovePendingTxBlockHeights(1000)
c.Assert(vault.LenPendingTxBlockHeights(1002, constAccessor), Equals, 0)
vault.RemovePendingTxBlockHeights(1001)
c.Assert(vault.LenPendingTxBlockHeights(1002, constAccessor), Equals, 0)
}
......@@ -103,8 +103,7 @@ func (vm *VaultMgr) EndBlock(ctx sdk.Context, version semver.Version, constAcces
// move partial funds every 30 minutes
if (ctx.BlockHeight()-vault.StatusSince)%migrateInterval == 0 {
if vault.PendingTxCount > 0 {
if vault.LenPendingTxBlockHeights(ctx.BlockHeight(), constAccessor) > 0 {
ctx.Logger().Info("Skipping the migration of funds while transactions are still pending")
continue
}
......@@ -171,7 +170,7 @@ func (vm *VaultMgr) EndBlock(ctx sdk.Context, version semver.Version, constAcces
return err
}
if ok {
vault.PendingTxCount += 1
vault.AppendPendingTxBlockHeights(ctx.BlockHeight(), constAccessor)
if err := vm.k.SetVault(ctx, vault); err != nil {
return fmt.Errorf("fail to save vault: %w", err)
}
......
......@@ -10,6 +10,7 @@ import (
"gitlab.com/thorchain/thornode/constants"
)
// Fund is a method to fund yggdrasil pool
func Fund(ctx sdk.Context, keeper Keeper, txOutStore TxOutStore, constAccessor constants.ConstantValues) error {
// Check if we have triggered the ragnarok protocol
ragnarokHeight, err := keeper.GetRagnarokBlockHeight(ctx)
......@@ -76,8 +77,9 @@ func Fund(ctx sdk.Context, keeper Keeper, txOutStore TxOutStore, constAccessor c
if !ygg.IsYggdrasil() {
return nil
}
if ygg.PendingTxCount > 0 {
return fmt.Errorf("cannot send more yggdrasil funds while transactions are pending (%s: %d)", ygg.PubKey, ygg.PendingTxCount)
pendingTxCount := ygg.LenPendingTxBlockHeights(ctx.BlockHeight(), constAccessor)
if pendingTxCount > 0 {
return fmt.Errorf("cannot send more yggdrasil funds while transactions are pending (%s: %d)", ygg.PubKey, pendingTxCount)
}
// calculate the total value of funds of this yggdrasil vault
......@@ -130,8 +132,9 @@ func Fund(ctx sdk.Context, keeper Keeper, txOutStore TxOutStore, constAccessor c
if err != nil {
return err
}
ygg.PendingTxCount += int64(count)
for i := 0; i < count; i++ {
ygg.AppendPendingTxBlockHeights(ctx.BlockHeight(), constAccessor)
}
if err := keeper.SetVault(ctx, ygg); err != nil {
return fmt.Errorf("fail to create yggdrasil pool: %w", err)
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment