2021-05-04 01:37:17 +00:00
|
|
|
package remotedbserver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"context"
|
|
|
|
"fmt"
|
|
|
|
|
2021-05-20 18:25:53 +00:00
|
|
|
"github.com/ledgerwatch/erigon/common"
|
|
|
|
"github.com/ledgerwatch/erigon/core"
|
|
|
|
"github.com/ledgerwatch/erigon/core/types"
|
|
|
|
"github.com/ledgerwatch/erigon/event"
|
|
|
|
"github.com/ledgerwatch/erigon/gointerfaces"
|
|
|
|
proto_txpool "github.com/ledgerwatch/erigon/gointerfaces/txpool"
|
2021-05-22 10:00:13 +00:00
|
|
|
types2 "github.com/ledgerwatch/erigon/gointerfaces/types"
|
2021-05-20 18:25:53 +00:00
|
|
|
"github.com/ledgerwatch/erigon/log"
|
2021-06-11 08:34:47 +00:00
|
|
|
"github.com/ledgerwatch/erigon/rlp"
|
2021-05-22 10:00:13 +00:00
|
|
|
"google.golang.org/protobuf/types/known/emptypb"
|
2021-05-04 01:37:17 +00:00
|
|
|
)
|
|
|
|
|
2021-05-22 10:00:13 +00:00
|
|
|
// TxPoolAPIVersion
|
|
|
|
var TxPoolAPIVersion = &types2.VersionReply{Major: 1, Minor: 0, Patch: 0}
|
|
|
|
|
2021-05-04 01:37:17 +00:00
|
|
|
type txPool interface {
|
|
|
|
Get(hash common.Hash) types.Transaction
|
|
|
|
AddLocals(txs []types.Transaction) []error
|
2021-06-11 08:34:47 +00:00
|
|
|
Content() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
|
2021-05-04 01:37:17 +00:00
|
|
|
SubscribeNewTxsEvent(ch chan<- core.NewTxsEvent) event.Subscription
|
|
|
|
}
|
|
|
|
|
|
|
|
type TxPoolServer struct {
|
|
|
|
proto_txpool.UnimplementedTxpoolServer
|
|
|
|
ctx context.Context
|
|
|
|
txPool txPool
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewTxPoolServer(ctx context.Context, txPool txPool) *TxPoolServer {
|
|
|
|
return &TxPoolServer{ctx: ctx, txPool: txPool}
|
|
|
|
}
|
2021-05-17 12:15:19 +00:00
|
|
|
|
2021-05-22 10:00:13 +00:00
|
|
|
func (s *TxPoolServer) Version(context.Context, *emptypb.Empty) (*types2.VersionReply, error) {
|
|
|
|
return MiningAPIVersion, nil
|
|
|
|
}
|
2021-06-11 08:34:47 +00:00
|
|
|
func (s *TxPoolServer) All(context.Context, *proto_txpool.AllRequest) (*proto_txpool.AllReply, error) {
|
|
|
|
pending, queued := s.txPool.Content()
|
|
|
|
reply := &proto_txpool.AllReply{}
|
|
|
|
reply.Txs = make([]*proto_txpool.AllReply_Tx, 0, 16)
|
|
|
|
for addr, list := range pending {
|
|
|
|
addrBytes := addr.Bytes()
|
|
|
|
for i := range list {
|
|
|
|
b, err := rlp.EncodeToBytes(list[i])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
reply.Txs = append(reply.Txs, &proto_txpool.AllReply_Tx{
|
|
|
|
Sender: addrBytes,
|
|
|
|
Type: proto_txpool.AllReply_PENDING,
|
|
|
|
RlpTx: b,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for addr, list := range queued {
|
|
|
|
addrBytes := addr.Bytes()
|
|
|
|
for i := range list {
|
|
|
|
b, err := rlp.EncodeToBytes(list[i])
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
reply.Txs = append(reply.Txs, &proto_txpool.AllReply_Tx{
|
|
|
|
Sender: addrBytes,
|
|
|
|
Type: proto_txpool.AllReply_QUEUED,
|
|
|
|
RlpTx: b,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return reply, nil
|
|
|
|
}
|
2021-05-22 10:00:13 +00:00
|
|
|
|
2021-05-04 01:37:17 +00:00
|
|
|
func (s *TxPoolServer) FindUnknown(ctx context.Context, in *proto_txpool.TxHashes) (*proto_txpool.TxHashes, error) {
|
|
|
|
return nil, fmt.Errorf("unimplemented")
|
|
|
|
/*
|
|
|
|
var underpriced int
|
|
|
|
for i := range in.Hashes {
|
|
|
|
h := gointerfaces.ConvertH256ToHash(in.Hashes[i])
|
|
|
|
if s.txPool.Has(h) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
if s.underpriced.Contains(h) {
|
|
|
|
underpriced++
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
reply.Hashes = append(reply.Hashes, in.Hashes[i])
|
|
|
|
}
|
|
|
|
txAnnounceInMeter.Mark(int64(len(in.Hashes)))
|
|
|
|
txAnnounceKnownMeter.Mark(int64(len(in.Hashes) - len(reply.Hashes)))
|
|
|
|
txAnnounceUnderpricedMeter.Mark(int64(underpriced))
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *TxPoolServer) Add(ctx context.Context, in *proto_txpool.AddRequest) (*proto_txpool.AddReply, error) {
|
|
|
|
reply := &proto_txpool.AddReply{Imported: make([]proto_txpool.ImportResult, len(in.RlpTxs)), Errors: make([]string, len(in.RlpTxs))}
|
2021-05-04 05:51:28 +00:00
|
|
|
txs, err := types.UnmarshalTransactionsFromBinary(in.RlpTxs)
|
2021-05-04 01:37:17 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
errs := s.txPool.AddLocals(txs)
|
|
|
|
for i, err := range errs {
|
|
|
|
if err == nil {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
|
|
|
|
reply.Errors[i] = err.Error()
|
|
|
|
|
|
|
|
// Track a few interesting failure types
|
|
|
|
switch err {
|
|
|
|
case nil: // Noop, but need to handle to not count these
|
|
|
|
|
|
|
|
case core.ErrAlreadyKnown:
|
|
|
|
reply.Imported[i] = proto_txpool.ImportResult_ALREADY_EXISTS
|
|
|
|
case core.ErrUnderpriced, core.ErrReplaceUnderpriced:
|
|
|
|
reply.Imported[i] = proto_txpool.ImportResult_FEE_TOO_LOW
|
|
|
|
case core.ErrInvalidSender, core.ErrGasLimit, core.ErrNegativeValue, core.ErrOversizedData:
|
|
|
|
reply.Imported[i] = proto_txpool.ImportResult_INVALID
|
|
|
|
default:
|
|
|
|
reply.Imported[i] = proto_txpool.ImportResult_INTERNAL_ERROR
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return reply, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *TxPoolServer) OnAdd(req *proto_txpool.OnAddRequest, stream proto_txpool.Txpool_OnAddServer) error {
|
|
|
|
txsCh := make(chan core.NewTxsEvent, 1024)
|
|
|
|
defer close(txsCh)
|
|
|
|
sub := s.txPool.SubscribeNewTxsEvent(txsCh)
|
|
|
|
defer sub.Unsubscribe()
|
|
|
|
|
|
|
|
var buf bytes.Buffer
|
2021-05-04 11:31:07 +00:00
|
|
|
var rplTxs [][]byte
|
2021-05-04 16:12:59 +00:00
|
|
|
for txs := range txsCh {
|
|
|
|
rplTxs = rplTxs[:0]
|
|
|
|
for _, tx := range txs.Txs {
|
|
|
|
buf.Reset()
|
2021-05-04 21:58:13 +00:00
|
|
|
if err := tx.MarshalBinary(&buf); err != nil {
|
2021-05-04 16:12:59 +00:00
|
|
|
log.Warn("error while marshaling a pending transaction", "err", err)
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
rplTxs = append(rplTxs, common.CopyBytes(buf.Bytes()))
|
|
|
|
}
|
|
|
|
if err := stream.Send(&proto_txpool.OnAddReply{RplTxs: rplTxs}); err != nil {
|
2021-05-04 01:37:17 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (s *TxPoolServer) Transactions(ctx context.Context, in *proto_txpool.TransactionsRequest) (*proto_txpool.TransactionsReply, error) {
|
|
|
|
buf := bytes.NewBuffer(nil)
|
|
|
|
reply := &proto_txpool.TransactionsReply{RlpTxs: make([][]byte, len(in.Hashes))}
|
|
|
|
for i := range in.Hashes {
|
|
|
|
txn := s.txPool.Get(gointerfaces.ConvertH256ToHash(in.Hashes[i]))
|
|
|
|
if txn == nil {
|
|
|
|
reply.RlpTxs[i] = nil
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
buf.Reset()
|
2021-05-04 21:58:13 +00:00
|
|
|
if err := txn.MarshalBinary(buf); err != nil {
|
2021-05-04 01:37:17 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
reply.RlpTxs[i] = common.CopyBytes(buf.Bytes())
|
|
|
|
}
|
|
|
|
|
|
|
|
return reply, nil
|
|
|
|
}
|