implement MessagePool.CheckMessages
Signed-off-by: Jakub Sztandera <kubuxu@protocol.ai>
This commit is contained in:
parent
ed61642b3a
commit
91e774063e
@ -252,6 +252,11 @@ type FullNode interface {
|
|||||||
// MpoolBatchPushMessage batch pushes a unsigned message to mempool.
|
// MpoolBatchPushMessage batch pushes a unsigned message to mempool.
|
||||||
MpoolBatchPushMessage(context.Context, []*types.Message, *MessageSendSpec) ([]*types.SignedMessage, error) //perm:sign
|
MpoolBatchPushMessage(context.Context, []*types.Message, *MessageSendSpec) ([]*types.SignedMessage, error) //perm:sign
|
||||||
|
|
||||||
|
// MpoolCheckMessages performs logical checks on a batch of messages
|
||||||
|
MpoolCheckMessages(context.Context, []*types.Message) ([][]MessageCheckStatus, error) //perm:read
|
||||||
|
// MpoolCheckPendingMessages performs logical checks for all pending messages from a given address
|
||||||
|
MpoolCheckPendingMessages(context.Context, address.Address) ([][]MessageCheckStatus, error) //perm:read
|
||||||
|
|
||||||
// MpoolGetNonce gets next nonce for the specified sender.
|
// MpoolGetNonce gets next nonce for the specified sender.
|
||||||
// Note that this method may not be atomic. Use MpoolPushMessage instead.
|
// Note that this method may not be atomic. Use MpoolPushMessage instead.
|
||||||
MpoolGetNonce(context.Context, address.Address) (uint64, error) //perm:read
|
MpoolGetNonce(context.Context, address.Address) (uint64, error) //perm:read
|
||||||
|
35
api/checkstatuscode_string.go
Normal file
35
api/checkstatuscode_string.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Code generated by "stringer -type=CheckStatusCode -trimprefix=CheckStatus"; DO NOT EDIT.
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import "strconv"
|
||||||
|
|
||||||
|
func _() {
|
||||||
|
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||||
|
// Re-run the stringer command to generate them again.
|
||||||
|
var x [1]struct{}
|
||||||
|
_ = x[CheckStatusMessageSerialize-1]
|
||||||
|
_ = x[CheckStatusMessageSize-2]
|
||||||
|
_ = x[CheckStatusMessageValidity-3]
|
||||||
|
_ = x[CheckStatusMessageMinGas-4]
|
||||||
|
_ = x[CheckStatusMessageMinBaseFee-5]
|
||||||
|
_ = x[CheckStatusMessageBaseFee-6]
|
||||||
|
_ = x[CheckStatusMessageBaseFeeLowerBound-7]
|
||||||
|
_ = x[CheckStatusMessageBaseFeeUpperBound-8]
|
||||||
|
_ = x[CheckStatusMessageGetStateNonce-9]
|
||||||
|
_ = x[CheckStatusMessageNonce-10]
|
||||||
|
_ = x[CheckStatusMessageGetStateBalance-11]
|
||||||
|
_ = x[CheckStatusMessageBalance-12]
|
||||||
|
}
|
||||||
|
|
||||||
|
const _CheckStatusCode_name = "MessageSerializeMessageSizeMessageValidityMessageMinGasMessageMinBaseFeeMessageBaseFeeMessageBaseFeeLowerBoundMessageBaseFeeUpperBoundMessageGetStateNonceMessageNonceMessageGetStateBalanceMessageBalance"
|
||||||
|
|
||||||
|
var _CheckStatusCode_index = [...]uint8{0, 16, 27, 42, 55, 72, 86, 110, 134, 154, 166, 188, 202}
|
||||||
|
|
||||||
|
func (i CheckStatusCode) String() string {
|
||||||
|
i -= 1
|
||||||
|
if i < 0 || i >= CheckStatusCode(len(_CheckStatusCode_index)-1) {
|
||||||
|
return "CheckStatusCode(" + strconv.FormatInt(int64(i+1), 10) + ")"
|
||||||
|
}
|
||||||
|
return _CheckStatusCode_name[_CheckStatusCode_index[i]:_CheckStatusCode_index[i+1]]
|
||||||
|
}
|
@ -261,6 +261,9 @@ func init() {
|
|||||||
},
|
},
|
||||||
"methods": []interface{}{}},
|
"methods": []interface{}{}},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
addExample(api.CheckStatusCode(0))
|
||||||
|
addExample(map[string]interface{}{"abc": 123})
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAPIType(name, pkg string) (i interface{}, t, permStruct, commonPermStruct reflect.Type) {
|
func GetAPIType(name, pkg string) (i interface{}, t, permStruct, commonPermStruct reflect.Type) {
|
||||||
|
@ -1068,6 +1068,36 @@ func (mr *MockFullNodeMockRecorder) MpoolBatchPushUntrusted(arg0, arg1 interface
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MpoolBatchPushUntrusted", reflect.TypeOf((*MockFullNode)(nil).MpoolBatchPushUntrusted), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MpoolBatchPushUntrusted", reflect.TypeOf((*MockFullNode)(nil).MpoolBatchPushUntrusted), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MpoolCheckMessages mocks base method
|
||||||
|
func (m *MockFullNode) MpoolCheckMessages(arg0 context.Context, arg1 []*types.Message) ([][]api.MessageCheckStatus, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "MpoolCheckMessages", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].([][]api.MessageCheckStatus)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// MpoolCheckMessages indicates an expected call of MpoolCheckMessages
|
||||||
|
func (mr *MockFullNodeMockRecorder) MpoolCheckMessages(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MpoolCheckMessages", reflect.TypeOf((*MockFullNode)(nil).MpoolCheckMessages), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MpoolCheckPendingMessages mocks base method
|
||||||
|
func (m *MockFullNode) MpoolCheckPendingMessages(arg0 context.Context, arg1 address.Address) ([][]api.MessageCheckStatus, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "MpoolCheckPendingMessages", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].([][]api.MessageCheckStatus)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// MpoolCheckPendingMessages indicates an expected call of MpoolCheckPendingMessages
|
||||||
|
func (mr *MockFullNodeMockRecorder) MpoolCheckPendingMessages(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MpoolCheckPendingMessages", reflect.TypeOf((*MockFullNode)(nil).MpoolCheckPendingMessages), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// MpoolClear mocks base method
|
// MpoolClear mocks base method
|
||||||
func (m *MockFullNode) MpoolClear(arg0 context.Context, arg1 bool) error {
|
func (m *MockFullNode) MpoolClear(arg0 context.Context, arg1 bool) error {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -235,6 +235,10 @@ type FullNodeStruct struct {
|
|||||||
|
|
||||||
MpoolBatchPushUntrusted func(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) `perm:"write"`
|
MpoolBatchPushUntrusted func(p0 context.Context, p1 []*types.SignedMessage) ([]cid.Cid, error) `perm:"write"`
|
||||||
|
|
||||||
|
MpoolCheckMessages func(p0 context.Context, p1 []*types.Message) ([][]MessageCheckStatus, error) `perm:"read"`
|
||||||
|
|
||||||
|
MpoolCheckPendingMessages func(p0 context.Context, p1 address.Address) ([][]MessageCheckStatus, error) `perm:"read"`
|
||||||
|
|
||||||
MpoolClear func(p0 context.Context, p1 bool) error `perm:"write"`
|
MpoolClear func(p0 context.Context, p1 bool) error `perm:"write"`
|
||||||
|
|
||||||
MpoolGetConfig func(p0 context.Context) (*types.MpoolConfig, error) `perm:"read"`
|
MpoolGetConfig func(p0 context.Context) (*types.MpoolConfig, error) `perm:"read"`
|
||||||
@ -1509,6 +1513,22 @@ func (s *FullNodeStub) MpoolBatchPushUntrusted(p0 context.Context, p1 []*types.S
|
|||||||
return *new([]cid.Cid), xerrors.New("method not supported")
|
return *new([]cid.Cid), xerrors.New("method not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) MpoolCheckMessages(p0 context.Context, p1 []*types.Message) ([][]MessageCheckStatus, error) {
|
||||||
|
return s.Internal.MpoolCheckMessages(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStub) MpoolCheckMessages(p0 context.Context, p1 []*types.Message) ([][]MessageCheckStatus, error) {
|
||||||
|
return *new([][]MessageCheckStatus), xerrors.New("method not supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStruct) MpoolCheckPendingMessages(p0 context.Context, p1 address.Address) ([][]MessageCheckStatus, error) {
|
||||||
|
return s.Internal.MpoolCheckPendingMessages(p0, p1)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *FullNodeStub) MpoolCheckPendingMessages(p0 context.Context, p1 address.Address) ([][]MessageCheckStatus, error) {
|
||||||
|
return *new([][]MessageCheckStatus), xerrors.New("method not supported")
|
||||||
|
}
|
||||||
|
|
||||||
func (s *FullNodeStruct) MpoolClear(p0 context.Context, p1 bool) error {
|
func (s *FullNodeStruct) MpoolClear(p0 context.Context, p1 bool) error {
|
||||||
return s.Internal.MpoolClear(p0, p1)
|
return s.Internal.MpoolClear(p0, p1)
|
||||||
}
|
}
|
||||||
|
32
api/types.go
32
api/types.go
@ -137,3 +137,35 @@ type NodeChainStatus struct {
|
|||||||
BlocksPerTipsetLast100 float64
|
BlocksPerTipsetLast100 float64
|
||||||
BlocksPerTipsetLastFinality float64
|
BlocksPerTipsetLastFinality float64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type CheckStatusCode int
|
||||||
|
|
||||||
|
//go:generate go run golang.org/x/tools/cmd/stringer -type=CheckStatusCode -trimprefix=CheckStatus
|
||||||
|
const (
|
||||||
|
_ CheckStatusCode = iota
|
||||||
|
// Message Checks
|
||||||
|
CheckStatusMessageSerialize
|
||||||
|
CheckStatusMessageSize
|
||||||
|
CheckStatusMessageValidity
|
||||||
|
CheckStatusMessageMinGas
|
||||||
|
CheckStatusMessageMinBaseFee
|
||||||
|
CheckStatusMessageBaseFee
|
||||||
|
CheckStatusMessageBaseFeeLowerBound
|
||||||
|
CheckStatusMessageBaseFeeUpperBound
|
||||||
|
CheckStatusMessageGetStateNonce
|
||||||
|
CheckStatusMessageNonce
|
||||||
|
CheckStatusMessageGetStateBalance
|
||||||
|
CheckStatusMessageBalance
|
||||||
|
)
|
||||||
|
|
||||||
|
type CheckStatus struct {
|
||||||
|
Code CheckStatusCode
|
||||||
|
OK bool
|
||||||
|
Err string
|
||||||
|
Hint map[string]interface{}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MessageCheckStatus struct {
|
||||||
|
Cid cid.Cid
|
||||||
|
CheckStatus
|
||||||
|
}
|
||||||
|
@ -6,4 +6,5 @@ import (
|
|||||||
_ "github.com/GeertJohan/go.rice/rice"
|
_ "github.com/GeertJohan/go.rice/rice"
|
||||||
_ "github.com/golang/mock/mockgen"
|
_ "github.com/golang/mock/mockgen"
|
||||||
_ "github.com/whyrusleeping/bencher"
|
_ "github.com/whyrusleeping/bencher"
|
||||||
|
_ "golang.org/x/tools/cmd/stringer"
|
||||||
)
|
)
|
||||||
|
374
chain/messagepool/check.go
Normal file
374
chain/messagepool/check.go
Normal file
@ -0,0 +1,374 @@
|
|||||||
|
package messagepool
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
stdbig "math/big"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"golang.org/x/xerrors"
|
||||||
|
|
||||||
|
"github.com/filecoin-project/go-address"
|
||||||
|
"github.com/filecoin-project/go-state-types/big"
|
||||||
|
"github.com/filecoin-project/lotus/api"
|
||||||
|
"github.com/filecoin-project/lotus/build"
|
||||||
|
"github.com/filecoin-project/lotus/chain/types"
|
||||||
|
"github.com/filecoin-project/lotus/chain/vm"
|
||||||
|
)
|
||||||
|
|
||||||
|
var baseFeeUpperBoundFactor = types.NewInt(10)
|
||||||
|
|
||||||
|
// CheckMessages performs a set of logic checks for a list of messages, prior to submitting it to the mpool
|
||||||
|
func (mp *MessagePool) CheckMessages(msgs []*types.Message) ([][]api.MessageCheckStatus, error) {
|
||||||
|
return mp.checkMessages(msgs, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckPendingMessages performs a set of logical sets for all messages pending from a given actor
|
||||||
|
func (mp *MessagePool) CheckPendingMessages(from address.Address) ([][]api.MessageCheckStatus, error) {
|
||||||
|
var msgs []*types.Message
|
||||||
|
mp.lk.Lock()
|
||||||
|
mset, ok := mp.pending[from]
|
||||||
|
if ok {
|
||||||
|
for _, sm := range mset.msgs {
|
||||||
|
msgs = append(msgs, &sm.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mp.lk.Unlock()
|
||||||
|
|
||||||
|
if len(msgs) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Slice(msgs, func(i, j int) bool {
|
||||||
|
return msgs[i].Nonce < msgs[j].Nonce
|
||||||
|
})
|
||||||
|
|
||||||
|
return mp.checkMessages(msgs, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *MessagePool) checkMessages(msgs []*types.Message, interned bool) (result [][]api.MessageCheckStatus, err error) {
|
||||||
|
mp.curTsLk.Lock()
|
||||||
|
curTs := mp.curTs
|
||||||
|
mp.curTsLk.Unlock()
|
||||||
|
|
||||||
|
epoch := curTs.Height()
|
||||||
|
|
||||||
|
var baseFee big.Int
|
||||||
|
if len(curTs.Blocks()) > 0 {
|
||||||
|
baseFee = curTs.Blocks()[0].ParentBaseFee
|
||||||
|
} else {
|
||||||
|
baseFee, err = mp.api.ChainComputeBaseFee(context.Background(), curTs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, xerrors.Errorf("error computing basefee: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
baseFeeLowerBound := getBaseFeeLowerBound(baseFee, baseFeeLowerBoundFactor)
|
||||||
|
baseFeeUpperBound := types.BigMul(baseFee, baseFeeUpperBoundFactor)
|
||||||
|
|
||||||
|
type actorState struct {
|
||||||
|
nextNonce uint64
|
||||||
|
requiredFunds *stdbig.Int
|
||||||
|
}
|
||||||
|
|
||||||
|
state := make(map[address.Address]*actorState)
|
||||||
|
balances := make(map[address.Address]big.Int)
|
||||||
|
|
||||||
|
result = make([][]api.MessageCheckStatus, len(msgs))
|
||||||
|
|
||||||
|
for i, m := range msgs {
|
||||||
|
// pre-check: actor nonce
|
||||||
|
check := api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageGetStateNonce,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
st, ok := state[m.From]
|
||||||
|
if !ok {
|
||||||
|
mp.lk.Lock()
|
||||||
|
mset, ok := mp.pending[m.From]
|
||||||
|
if ok && !interned {
|
||||||
|
st = &actorState{nextNonce: mset.nextNonce, requiredFunds: mset.requiredFunds}
|
||||||
|
for _, m := range mset.msgs {
|
||||||
|
st.requiredFunds = new(stdbig.Int).Add(st.requiredFunds, m.Message.Value.Int)
|
||||||
|
}
|
||||||
|
state[m.From] = st
|
||||||
|
mp.lk.Unlock()
|
||||||
|
|
||||||
|
check.OK = true
|
||||||
|
check.Hint = map[string]interface{}{
|
||||||
|
"nonce": st.nextNonce,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mp.lk.Unlock()
|
||||||
|
|
||||||
|
stateNonce, err := mp.getStateNonce(m.From, curTs)
|
||||||
|
if err != nil {
|
||||||
|
check.OK = false
|
||||||
|
check.Err = fmt.Sprintf("error retrieving state nonce: %s", err.Error())
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
check.Hint = map[string]interface{}{
|
||||||
|
"nonce": stateNonce,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
st = &actorState{nextNonce: stateNonce, requiredFunds: new(stdbig.Int)}
|
||||||
|
state[m.From] = st
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
if !check.OK {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// pre-check: actor balance
|
||||||
|
check = api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageGetStateBalance,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
balance, ok := balances[m.From]
|
||||||
|
if !ok {
|
||||||
|
balance, err = mp.getStateBalance(m.From, curTs)
|
||||||
|
if err != nil {
|
||||||
|
check.OK = false
|
||||||
|
check.Err = fmt.Sprintf("error retrieving state balance: %s", err)
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
check.Hint = map[string]interface{}{
|
||||||
|
"balance": balance,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
balances[m.From] = balance
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
check.Hint = map[string]interface{}{
|
||||||
|
"balance": balance,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
if !check.OK {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Serialization
|
||||||
|
check = api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageSerialize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes, err := m.Serialize()
|
||||||
|
if err != nil {
|
||||||
|
check.OK = false
|
||||||
|
check.Err = err.Error()
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
|
||||||
|
// 2. Message size
|
||||||
|
check = api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageSize,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(bytes) > 32*1024-128 { // 128 bytes to account for signature size
|
||||||
|
check.OK = false
|
||||||
|
check.Err = "message too big"
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
|
||||||
|
// 3. Syntactic validation
|
||||||
|
check = api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageValidity,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := m.ValidForBlockInclusion(0, build.NewestNetworkVersion); err != nil {
|
||||||
|
check.OK = false
|
||||||
|
check.Err = fmt.Sprintf("syntactically invalid message: %s", err.Error())
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
if !check.OK {
|
||||||
|
// skip remaining checks if it is a syntatically invalid message
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// gas checks
|
||||||
|
|
||||||
|
// 4. Min Gas
|
||||||
|
minGas := vm.PricelistByEpoch(epoch).OnChainMessage(m.ChainLength())
|
||||||
|
|
||||||
|
check = api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageMinGas,
|
||||||
|
Hint: map[string]interface{}{
|
||||||
|
"minGas": minGas,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.GasLimit < minGas.Total() {
|
||||||
|
check.OK = false
|
||||||
|
check.Err = "GasLimit less than epoch minimum gas"
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
|
||||||
|
// 5. Min Base Fee
|
||||||
|
check = api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageMinBaseFee,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.GasFeeCap.LessThan(minimumBaseFee) {
|
||||||
|
check.OK = false
|
||||||
|
check.Err = "GasFeeCap less than minimum base fee"
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
if !check.OK {
|
||||||
|
goto checkState
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6. Base Fee
|
||||||
|
check = api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageBaseFee,
|
||||||
|
Hint: map[string]interface{}{
|
||||||
|
"baseFee": baseFee,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.GasFeeCap.LessThan(baseFee) {
|
||||||
|
check.OK = false
|
||||||
|
check.Err = "GasFeeCap less than current base fee"
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
|
||||||
|
// 7. Base Fee lower bound
|
||||||
|
check = api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageBaseFeeLowerBound,
|
||||||
|
Hint: map[string]interface{}{
|
||||||
|
"baseFeeLowerBound": baseFeeLowerBound,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.GasFeeCap.LessThan(baseFeeLowerBound) {
|
||||||
|
check.OK = false
|
||||||
|
check.Err = "GasFeeCap less than base fee lower bound for inclusion in next 20 epochs"
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
if !check.OK {
|
||||||
|
goto checkState
|
||||||
|
}
|
||||||
|
|
||||||
|
// 8. Base Fee upper bound
|
||||||
|
check = api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageBaseFeeUpperBound,
|
||||||
|
Hint: map[string]interface{}{
|
||||||
|
"baseFeeUpperBound": baseFeeUpperBound,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if m.GasFeeCap.LessThan(baseFeeUpperBound) {
|
||||||
|
check.OK = false
|
||||||
|
check.Err = "GasFeeCap less than base fee upper bound for inclusion in next 20 epochs"
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
|
||||||
|
// stateful checks
|
||||||
|
checkState:
|
||||||
|
// 9. Message Nonce
|
||||||
|
check = api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageNonce,
|
||||||
|
Hint: map[string]interface{}{
|
||||||
|
"nextNonce": st.nextNonce,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if st.nextNonce != m.Nonce {
|
||||||
|
check.OK = false
|
||||||
|
check.Err = fmt.Sprintf("message nonce doesn't match next nonce (%d)", st.nextNonce)
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
st.nextNonce++
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
|
||||||
|
// check required funds -vs- balance
|
||||||
|
st.requiredFunds = new(stdbig.Int).Add(st.requiredFunds, m.RequiredFunds().Int)
|
||||||
|
st.requiredFunds.Add(st.requiredFunds, m.Value.Int)
|
||||||
|
|
||||||
|
// 10. Balance
|
||||||
|
check = api.MessageCheckStatus{
|
||||||
|
Cid: m.Cid(),
|
||||||
|
CheckStatus: api.CheckStatus{
|
||||||
|
Code: api.CheckStatusMessageBalance,
|
||||||
|
Hint: map[string]interface{}{
|
||||||
|
"requiredFunds": big.Int{Int: stdbig.NewInt(0).Set(st.requiredFunds)},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if balance.Int.Cmp(st.requiredFunds) < 0 {
|
||||||
|
check.OK = false
|
||||||
|
check.Err = "insufficient balance"
|
||||||
|
} else {
|
||||||
|
check.OK = true
|
||||||
|
}
|
||||||
|
|
||||||
|
result[i] = append(result[i], check)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, nil
|
||||||
|
}
|
@ -82,6 +82,8 @@
|
|||||||
* [MpoolBatchPush](#MpoolBatchPush)
|
* [MpoolBatchPush](#MpoolBatchPush)
|
||||||
* [MpoolBatchPushMessage](#MpoolBatchPushMessage)
|
* [MpoolBatchPushMessage](#MpoolBatchPushMessage)
|
||||||
* [MpoolBatchPushUntrusted](#MpoolBatchPushUntrusted)
|
* [MpoolBatchPushUntrusted](#MpoolBatchPushUntrusted)
|
||||||
|
* [MpoolCheckMessages](#MpoolCheckMessages)
|
||||||
|
* [MpoolCheckPendingMessages](#MpoolCheckPendingMessages)
|
||||||
* [MpoolClear](#MpoolClear)
|
* [MpoolClear](#MpoolClear)
|
||||||
* [MpoolGetConfig](#MpoolGetConfig)
|
* [MpoolGetConfig](#MpoolGetConfig)
|
||||||
* [MpoolGetNonce](#MpoolGetNonce)
|
* [MpoolGetNonce](#MpoolGetNonce)
|
||||||
@ -1994,6 +1996,36 @@ Inputs:
|
|||||||
|
|
||||||
Response: `null`
|
Response: `null`
|
||||||
|
|
||||||
|
### MpoolCheckMessages
|
||||||
|
MpoolCheckMessages performs logical checks on a batch of messages
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
null
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response: `null`
|
||||||
|
|
||||||
|
### MpoolCheckPendingMessages
|
||||||
|
MpoolCheckPendingMessages performs logical checks for all pending messages from a given address
|
||||||
|
|
||||||
|
|
||||||
|
Perms: read
|
||||||
|
|
||||||
|
Inputs:
|
||||||
|
```json
|
||||||
|
[
|
||||||
|
"f01234"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
|
Response: `null`
|
||||||
|
|
||||||
### MpoolClear
|
### MpoolClear
|
||||||
MpoolClear clears pending messages from the mpool
|
MpoolClear clears pending messages from the mpool
|
||||||
|
|
||||||
|
1
go.mod
1
go.mod
@ -150,6 +150,7 @@ require (
|
|||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68
|
||||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
|
golang.org/x/time v0.0.0-20191024005414-555d28b269f0
|
||||||
|
golang.org/x/tools v0.0.0-20201112185108-eeaa07dd7696
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
||||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f // indirect
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
||||||
|
@ -225,6 +225,14 @@ func (a *MpoolAPI) MpoolBatchPushMessage(ctx context.Context, msgs []*types.Mess
|
|||||||
return smsgs, nil
|
return smsgs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *MpoolAPI) MpoolCheckMessages(ctx context.Context, msgs []*types.Message) ([][]api.MessageCheckStatus, error) {
|
||||||
|
return a.Mpool.CheckMessages(msgs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *MpoolAPI) MpoolCheckPendingMessages(ctx context.Context, from address.Address) ([][]api.MessageCheckStatus, error) {
|
||||||
|
return a.Mpool.CheckPendingMessages(from)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *MpoolAPI) MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error) {
|
func (a *MpoolAPI) MpoolGetNonce(ctx context.Context, addr address.Address) (uint64, error) {
|
||||||
return a.Mpool.GetNonce(ctx, addr, types.EmptyTSK)
|
return a.Mpool.GetNonce(ctx, addr, types.EmptyTSK)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user