Merge PR #2328: Support min fees-based anti spam strategy
This commit is contained in:
committed by
Christopher Goes
parent
c6a3928d37
commit
b74a6a9066
@@ -46,6 +46,12 @@ func (coin Coin) IsGTE(other Coin) bool {
|
||||
return coin.SameDenomAs(other) && (!coin.Amount.LT(other.Amount))
|
||||
}
|
||||
|
||||
// IsLT returns true if they are the same type and the receiver is
|
||||
// a smaller value
|
||||
func (coin Coin) IsLT(other Coin) bool {
|
||||
return !coin.IsGTE(other)
|
||||
}
|
||||
|
||||
// IsEqual returns true if the two sets of Coins have the same value
|
||||
func (coin Coin) IsEqual(other Coin) bool {
|
||||
return coin.SameDenomAs(other) && (coin.Amount.Equal(other.Amount))
|
||||
@@ -181,6 +187,12 @@ func (coins Coins) IsGTE(coinsB Coins) bool {
|
||||
return diff.IsNotNegative()
|
||||
}
|
||||
|
||||
// IsLT returns True iff every currency in coins, the currency is
|
||||
// present at a smaller amount in coins
|
||||
func (coins Coins) IsLT(coinsB Coins) bool {
|
||||
return !coins.IsGTE(coinsB)
|
||||
}
|
||||
|
||||
// IsZero returns true if there are no coins
|
||||
// or all coins are zero.
|
||||
func (coins Coins) IsZero() bool {
|
||||
|
||||
@@ -76,6 +76,24 @@ func TestIsGTECoin(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsLTCoin(t *testing.T) {
|
||||
cases := []struct {
|
||||
inputOne Coin
|
||||
inputTwo Coin
|
||||
expected bool
|
||||
}{
|
||||
{NewInt64Coin("A", 1), NewInt64Coin("A", 1), false},
|
||||
{NewInt64Coin("A", 2), NewInt64Coin("A", 1), false},
|
||||
{NewInt64Coin("A", -1), NewInt64Coin("A", 5), true},
|
||||
{NewInt64Coin("a", 0), NewInt64Coin("b", 1), true},
|
||||
}
|
||||
|
||||
for tcIndex, tc := range cases {
|
||||
res := tc.inputOne.IsLT(tc.inputTwo)
|
||||
require.Equal(t, tc.expected, res, "coin LT relation is incorrect, tc #%d", tcIndex)
|
||||
}
|
||||
}
|
||||
|
||||
func TestIsEqualCoin(t *testing.T) {
|
||||
cases := []struct {
|
||||
inputOne Coin
|
||||
@@ -227,6 +245,8 @@ func TestCoins(t *testing.T) {
|
||||
assert.True(t, good.IsPositive(), "Expected coins to be positive: %v", good)
|
||||
assert.False(t, null.IsPositive(), "Expected coins to not be positive: %v", null)
|
||||
assert.True(t, good.IsGTE(empty), "Expected %v to be >= %v", good, empty)
|
||||
assert.False(t, good.IsLT(empty), "Expected %v to be < %v", good, empty)
|
||||
assert.True(t, empty.IsLT(good), "Expected %v to be < %v", empty, good)
|
||||
assert.False(t, neg.IsPositive(), "Expected neg coins to not be positive: %v", neg)
|
||||
assert.Zero(t, len(sum), "Expected 0 coins")
|
||||
assert.False(t, badSort1.IsValid(), "Coins are not sorted")
|
||||
|
||||
+43
-33
@@ -1,3 +1,4 @@
|
||||
// nolint
|
||||
package types
|
||||
|
||||
import (
|
||||
@@ -41,10 +42,12 @@ func NewContext(ms MultiStore, header abci.Header, isCheckTx bool, logger log.Lo
|
||||
c = c.WithBlockHeader(header)
|
||||
c = c.WithBlockHeight(header.Height)
|
||||
c = c.WithChainID(header.ChainID)
|
||||
c = c.WithIsCheckTx(isCheckTx)
|
||||
c = c.WithTxBytes(nil)
|
||||
c = c.WithLogger(logger)
|
||||
c = c.WithSigningValidators(nil)
|
||||
c = c.WithGasMeter(NewInfiniteGasMeter())
|
||||
c = c.WithMinimumFees(Coins{})
|
||||
return c
|
||||
}
|
||||
|
||||
@@ -132,10 +135,12 @@ const (
|
||||
contextKeyBlockHeight
|
||||
contextKeyConsensusParams
|
||||
contextKeyChainID
|
||||
contextKeyIsCheckTx
|
||||
contextKeyTxBytes
|
||||
contextKeyLogger
|
||||
contextKeySigningValidators
|
||||
contextKeyGasMeter
|
||||
contextKeyMinimumFees
|
||||
)
|
||||
|
||||
// NOTE: Do not expose MultiStore.
|
||||
@@ -145,41 +150,41 @@ func (c Context) multiStore() MultiStore {
|
||||
return c.Value(contextKeyMultiStore).(MultiStore)
|
||||
}
|
||||
|
||||
// nolint
|
||||
func (c Context) BlockHeader() abci.Header {
|
||||
return c.Value(contextKeyBlockHeader).(abci.Header)
|
||||
}
|
||||
func (c Context) BlockHeight() int64 {
|
||||
return c.Value(contextKeyBlockHeight).(int64)
|
||||
}
|
||||
func (c Context) BlockHeader() abci.Header { return c.Value(contextKeyBlockHeader).(abci.Header) }
|
||||
|
||||
func (c Context) BlockHeight() int64 { return c.Value(contextKeyBlockHeight).(int64) }
|
||||
|
||||
func (c Context) ConsensusParams() abci.ConsensusParams {
|
||||
return c.Value(contextKeyConsensusParams).(abci.ConsensusParams)
|
||||
}
|
||||
func (c Context) ChainID() string {
|
||||
return c.Value(contextKeyChainID).(string)
|
||||
}
|
||||
func (c Context) TxBytes() []byte {
|
||||
return c.Value(contextKeyTxBytes).([]byte)
|
||||
}
|
||||
func (c Context) Logger() log.Logger {
|
||||
return c.Value(contextKeyLogger).(log.Logger)
|
||||
}
|
||||
|
||||
func (c Context) ChainID() string { return c.Value(contextKeyChainID).(string) }
|
||||
|
||||
func (c Context) TxBytes() []byte { return c.Value(contextKeyTxBytes).([]byte) }
|
||||
|
||||
func (c Context) Logger() log.Logger { return c.Value(contextKeyLogger).(log.Logger) }
|
||||
|
||||
func (c Context) SigningValidators() []abci.SigningValidator {
|
||||
return c.Value(contextKeySigningValidators).([]abci.SigningValidator)
|
||||
}
|
||||
func (c Context) GasMeter() GasMeter {
|
||||
return c.Value(contextKeyGasMeter).(GasMeter)
|
||||
}
|
||||
func (c Context) WithMultiStore(ms MultiStore) Context {
|
||||
return c.withValue(contextKeyMultiStore, ms)
|
||||
}
|
||||
|
||||
func (c Context) GasMeter() GasMeter { return c.Value(contextKeyGasMeter).(GasMeter) }
|
||||
|
||||
func (c Context) IsCheckTx() bool { return c.Value(contextKeyIsCheckTx).(bool) }
|
||||
|
||||
func (c Context) MinimumFees() Coins { return c.Value(contextKeyMinimumFees).(Coins) }
|
||||
|
||||
func (c Context) WithMultiStore(ms MultiStore) Context { return c.withValue(contextKeyMultiStore, ms) }
|
||||
|
||||
func (c Context) WithBlockHeader(header abci.Header) Context {
|
||||
var _ proto.Message = &header // for cloning.
|
||||
return c.withValue(contextKeyBlockHeader, header)
|
||||
}
|
||||
|
||||
func (c Context) WithBlockHeight(height int64) Context {
|
||||
return c.withValue(contextKeyBlockHeight, height)
|
||||
}
|
||||
|
||||
func (c Context) WithConsensusParams(params *abci.ConsensusParams) Context {
|
||||
if params == nil {
|
||||
return c
|
||||
@@ -187,20 +192,25 @@ func (c Context) WithConsensusParams(params *abci.ConsensusParams) Context {
|
||||
return c.withValue(contextKeyConsensusParams, params).
|
||||
WithGasMeter(NewGasMeter(params.TxSize.MaxGas))
|
||||
}
|
||||
func (c Context) WithChainID(chainID string) Context {
|
||||
return c.withValue(contextKeyChainID, chainID)
|
||||
}
|
||||
func (c Context) WithTxBytes(txBytes []byte) Context {
|
||||
return c.withValue(contextKeyTxBytes, txBytes)
|
||||
}
|
||||
func (c Context) WithLogger(logger log.Logger) Context {
|
||||
return c.withValue(contextKeyLogger, logger)
|
||||
}
|
||||
|
||||
func (c Context) WithChainID(chainID string) Context { return c.withValue(contextKeyChainID, chainID) }
|
||||
|
||||
func (c Context) WithTxBytes(txBytes []byte) Context { return c.withValue(contextKeyTxBytes, txBytes) }
|
||||
|
||||
func (c Context) WithLogger(logger log.Logger) Context { return c.withValue(contextKeyLogger, logger) }
|
||||
|
||||
func (c Context) WithSigningValidators(SigningValidators []abci.SigningValidator) Context {
|
||||
return c.withValue(contextKeySigningValidators, SigningValidators)
|
||||
}
|
||||
func (c Context) WithGasMeter(meter GasMeter) Context {
|
||||
return c.withValue(contextKeyGasMeter, meter)
|
||||
|
||||
func (c Context) WithGasMeter(meter GasMeter) Context { return c.withValue(contextKeyGasMeter, meter) }
|
||||
|
||||
func (c Context) WithIsCheckTx(isCheckTx bool) Context {
|
||||
return c.withValue(contextKeyIsCheckTx, isCheckTx)
|
||||
}
|
||||
|
||||
func (c Context) WithMinimumFees(minFees Coins) Context {
|
||||
return c.withValue(contextKeyMinimumFees, minFees)
|
||||
}
|
||||
|
||||
// Cache the multistore and return a new cached context. The cached context is
|
||||
|
||||
@@ -162,20 +162,23 @@ func TestContextWithCustom(t *testing.T) {
|
||||
logger := NewMockLogger()
|
||||
signvals := []abci.SigningValidator{{}}
|
||||
meter := types.NewGasMeter(10000)
|
||||
minFees := types.Coins{types.NewInt64Coin("feeCoin", 1)}
|
||||
|
||||
ctx = types.NewContext(nil, header, ischeck, logger).
|
||||
WithBlockHeight(height).
|
||||
WithChainID(chainid).
|
||||
WithTxBytes(txbytes).
|
||||
WithSigningValidators(signvals).
|
||||
WithGasMeter(meter)
|
||||
WithGasMeter(meter).
|
||||
WithMinimumFees(minFees)
|
||||
|
||||
require.Equal(t, header, ctx.BlockHeader())
|
||||
require.Equal(t, height, ctx.BlockHeight())
|
||||
require.Equal(t, chainid, ctx.ChainID())
|
||||
require.Equal(t, ischeck, ctx.IsCheckTx())
|
||||
require.Equal(t, txbytes, ctx.TxBytes())
|
||||
require.Equal(t, logger, ctx.Logger())
|
||||
require.Equal(t, signvals, ctx.SigningValidators())
|
||||
require.Equal(t, meter, ctx.GasMeter())
|
||||
|
||||
require.Equal(t, minFees, types.Coins{types.NewInt64Coin("feeCoin", 1)})
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ const (
|
||||
CodeInvalidCoins CodeType = 11
|
||||
CodeOutOfGas CodeType = 12
|
||||
CodeMemoTooLarge CodeType = 13
|
||||
CodeInsufficientFee CodeType = 14
|
||||
|
||||
// CodespaceRoot is a codespace for error codes in this file only.
|
||||
// Notice that 0 is an "unset" codespace, which can be overridden with
|
||||
@@ -101,6 +102,8 @@ func CodeToDefaultMsg(code CodeType) string {
|
||||
return "out of gas"
|
||||
case CodeMemoTooLarge:
|
||||
return "memo too large"
|
||||
case CodeInsufficientFee:
|
||||
return "insufficient fee"
|
||||
default:
|
||||
return unknownCodeMsg(code)
|
||||
}
|
||||
@@ -150,6 +153,9 @@ func ErrOutOfGas(msg string) Error {
|
||||
func ErrMemoTooLarge(msg string) Error {
|
||||
return newErrorWithRootCodespace(CodeMemoTooLarge, msg)
|
||||
}
|
||||
func ErrInsufficientFee(msg string) Error {
|
||||
return newErrorWithRootCodespace(CodeInsufficientFee, msg)
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// Error & sdkError
|
||||
|
||||
Reference in New Issue
Block a user