mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22:23 +00:00
Merge baecd7d377 into eaff89291c
This commit is contained in:
commit
511f221cb2
12 changed files with 149 additions and 1 deletions
|
|
@ -57,6 +57,16 @@ func WriteTxLookupEntries(db DatabaseWriter, block *types.Block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func WriteTxLookupEntry(db DatabaseWriter, entry *TxLookupEntry, txHash common.Hash) {
|
||||||
|
data, err := rlp.EncodeToBytes(entry)
|
||||||
|
if err != nil {
|
||||||
|
log.Crit("Failed to encode transaction lookup entry", "err", err)
|
||||||
|
}
|
||||||
|
if err := db.Put(txLookupKey(txHash), data); err != nil {
|
||||||
|
log.Crit("Failed to store transaction lookup entry", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DeleteTxLookupEntry removes all transaction data associated with a hash.
|
// DeleteTxLookupEntry removes all transaction data associated with a hash.
|
||||||
func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) {
|
func DeleteTxLookupEntry(db DatabaseDeleter, hash common.Hash) {
|
||||||
db.Delete(txLookupKey(hash))
|
db.Delete(txLookupKey(hash))
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package eth
|
package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"context"
|
"context"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
||||||
|
|
@ -227,3 +228,7 @@ func (b *EthAPIBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
|
||||||
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
|
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *EthAPIBackend) TxStatusByHash(ctx context.Context, hash common.Hash) (core.TxStatus, error) {
|
||||||
|
return core.TxStatusUnknown, errors.New("Not Support")
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1090,6 +1090,11 @@ func (s *PublicTransactionPoolAPI) GetTransactionReceipt(ctx context.Context, ha
|
||||||
return fields, nil
|
return fields, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTransactionStatus returns current status of the transaction given hash
|
||||||
|
func (s *PublicTransactionPoolAPI) GetTransactionStatus(ctx context.Context, hash common.Hash) (core.TxStatus, error) {
|
||||||
|
return s.b.TxStatusByHash(ctx, hash)
|
||||||
|
}
|
||||||
|
|
||||||
// sign is a helper function that signs a transaction with the private key of the given address.
|
// sign is a helper function that signs a transaction with the private key of the given address.
|
||||||
func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
func (s *PublicTransactionPoolAPI) sign(addr common.Address, tx *types.Transaction) (*types.Transaction, error) {
|
||||||
// Look up the wallet containing the requested signer
|
// Look up the wallet containing the requested signer
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,7 @@ type Backend interface {
|
||||||
Stats() (pending int, queued int)
|
Stats() (pending int, queued int)
|
||||||
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
|
TxPoolContent() (map[common.Address]types.Transactions, map[common.Address]types.Transactions)
|
||||||
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
|
SubscribeNewTxsEvent(chan<- core.NewTxsEvent) event.Subscription
|
||||||
|
TxStatusByHash(ctx context.Context, hash common.Hash) (core.TxStatus, error)
|
||||||
|
|
||||||
ChainConfig() *params.ChainConfig
|
ChainConfig() *params.ChainConfig
|
||||||
CurrentBlock() *types.Block
|
CurrentBlock() *types.Block
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
|
|
@ -5358,6 +5358,12 @@ var methods = function () {
|
||||||
outputFormatter: utils.toDecimal
|
outputFormatter: utils.toDecimal
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var getTransactionStatus = new Method({
|
||||||
|
name: 'getTransactionStatus',
|
||||||
|
call: 'eth_getTransactionStatus',
|
||||||
|
params: 1
|
||||||
|
});
|
||||||
|
|
||||||
var sendRawTransaction = new Method({
|
var sendRawTransaction = new Method({
|
||||||
name: 'sendRawTransaction',
|
name: 'sendRawTransaction',
|
||||||
call: 'eth_sendRawTransaction',
|
call: 'eth_sendRawTransaction',
|
||||||
|
|
@ -5444,6 +5450,7 @@ var methods = function () {
|
||||||
getTransactionFromBlock,
|
getTransactionFromBlock,
|
||||||
getTransactionReceipt,
|
getTransactionReceipt,
|
||||||
getTransactionCount,
|
getTransactionCount,
|
||||||
|
getTransactionStatus,
|
||||||
call,
|
call,
|
||||||
estimateGas,
|
estimateGas,
|
||||||
sendRawTransaction,
|
sendRawTransaction,
|
||||||
|
|
|
||||||
|
|
@ -197,3 +197,7 @@ func (b *LesApiBackend) ServiceFilter(ctx context.Context, session *bloombits.Ma
|
||||||
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
|
go session.Multiplex(bloomRetrievalBatch, bloomRetrievalWait, b.eth.bloomRequests)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (b *LesApiBackend) TxStatusByHash(ctx context.Context, hash common.Hash) (core.TxStatus, error) {
|
||||||
|
return light.GetTxStatus(ctx, b.eth.odr, hash)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1109,6 +1109,12 @@ func (pm *ProtocolManager) handleMsg(p *peer) error {
|
||||||
|
|
||||||
p.fcServer.GotReply(resp.ReqID, resp.BV)
|
p.fcServer.GotReply(resp.ReqID, resp.BV)
|
||||||
|
|
||||||
|
deliverMsg = &Msg{
|
||||||
|
MsgType: MsgTxStatus,
|
||||||
|
ReqID: resp.ReqID,
|
||||||
|
Obj: resp.Status,
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
p.Log().Trace("Received unknown message", "code", msg.Code)
|
p.Log().Trace("Received unknown message", "code", msg.Code)
|
||||||
return errResp(ErrInvalidMsgCode, "%v", msg.Code)
|
return errResp(ErrInvalidMsgCode, "%v", msg.Code)
|
||||||
|
|
|
||||||
|
|
@ -77,6 +77,7 @@ const (
|
||||||
MsgProofsV2
|
MsgProofsV2
|
||||||
MsgHeaderProofs
|
MsgHeaderProofs
|
||||||
MsgHelperTrieProofs
|
MsgHelperTrieProofs
|
||||||
|
MsgTxStatus
|
||||||
)
|
)
|
||||||
|
|
||||||
// Msg encodes a LES message that delivers reply data for a request
|
// Msg encodes a LES message that delivers reply data for a request
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,8 @@ func LesRequest(req light.OdrRequest) LesOdrRequest {
|
||||||
return (*ChtRequest)(r)
|
return (*ChtRequest)(r)
|
||||||
case *light.BloomRequest:
|
case *light.BloomRequest:
|
||||||
return (*BloomRequest)(r)
|
return (*BloomRequest)(r)
|
||||||
|
case *light.TxStatusRequest:
|
||||||
|
return (*TxStatusRequest)(r)
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -564,3 +566,60 @@ func (db *readTraceDB) Has(key []byte) (bool, error) {
|
||||||
_, err := db.Get(key)
|
_, err := db.Get(key)
|
||||||
return err == nil, nil
|
return err == nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TxStatusRequest light.TxStatusRequest
|
||||||
|
|
||||||
|
// GetCost returns the cost of the given ODR request according to the serving
|
||||||
|
// peer's cost table (implementation of LesOdrRequest)
|
||||||
|
func (r *TxStatusRequest) GetCost(peer *peer) uint64 {
|
||||||
|
return peer.GetRequestCost(GetTxStatusMsg, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CanSend tells if a certain peer is suitable for serving the given request
|
||||||
|
func (r *TxStatusRequest) CanSend(peer *peer) bool {
|
||||||
|
peer.lock.RLock()
|
||||||
|
defer peer.lock.RUnlock()
|
||||||
|
|
||||||
|
if peer.version < lpv2 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request sends an ODR request to the LES network (implementation of LesOdrRequest)
|
||||||
|
func (r *TxStatusRequest) Request(reqID uint64, peer *peer) error {
|
||||||
|
peer.Log().Debug("Requesting transaction status corresponding block", "TxHash", r.TxHash)
|
||||||
|
return peer.RequestTxStatus(reqID, r.GetCost(peer), []common.Hash{r.TxHash})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid processes an ODR request reply message from the LES network
|
||||||
|
// returns true and stores results in memory if the message was a valid reply
|
||||||
|
// to the request (implementation of LesOdrRequest)
|
||||||
|
func (r *TxStatusRequest) Validate(db ethdb.Database, msg *Msg) error {
|
||||||
|
log.Debug("Validating transaction status corresponding block", "TxHash", r.TxHash)
|
||||||
|
|
||||||
|
// Ensure we have a correct message with a single block receipt
|
||||||
|
if msg.MsgType != MsgTxStatus {
|
||||||
|
return errInvalidMessageType
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(msg.Obj.([]txStatus)) != 1 {
|
||||||
|
return errInvalidEntryCount
|
||||||
|
}
|
||||||
|
|
||||||
|
//We retrieve transaction status, block hash and block index from a full node by a given transaction hash
|
||||||
|
//These information retrieve from full node is lacking of relevant data to verify
|
||||||
|
//My current solution is (Code at odr_util.go):
|
||||||
|
//Only start verification after it's been "included", to proof a transaction is valid:
|
||||||
|
//Retrieve BlockHash/BlockIndex -> Retrieve and verify BlockBody -> Verify given transaction hash whether included
|
||||||
|
|
||||||
|
//Need support verify through pending transactions
|
||||||
|
//Share your ideas!
|
||||||
|
|
||||||
|
status := msg.Obj.([]txStatus)[0]
|
||||||
|
|
||||||
|
r.TxStatus = status.Status
|
||||||
|
r.TxEntry = status.Lookup
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
11
light/odr.go
11
light/odr.go
|
|
@ -170,3 +170,14 @@ func (req *BloomRequest) StoreResult(db ethdb.Database) {
|
||||||
rawdb.WriteBloomBits(db, req.BitIdx, sectionIdx, sectionHead, req.BloomBits[i])
|
rawdb.WriteBloomBits(db, req.BitIdx, sectionIdx, sectionHead, req.BloomBits[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type TxStatusRequest struct {
|
||||||
|
OdrRequest
|
||||||
|
TxHash common.Hash
|
||||||
|
TxStatus core.TxStatus
|
||||||
|
TxEntry *rawdb.TxLookupEntry
|
||||||
|
}
|
||||||
|
|
||||||
|
func (req *TxStatusRequest) StoreResult(db ethdb.Database) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -230,3 +230,42 @@ func GetBloomBits(ctx context.Context, odr OdrBackend, bitIdx uint, sectionIdxLi
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//GetTxStatus requests full nodes to retrieve the status of transaction corresponding to the hash.
|
||||||
|
//Message of the LES/2 protocol version (LPV2)
|
||||||
|
func GetTxStatus(ctx context.Context, odr OdrBackend, txHash common.Hash) (core.TxStatus, error) {
|
||||||
|
|
||||||
|
// Return "Included" status if query success from database
|
||||||
|
bHash, bIndex, _ := rawdb.ReadTxLookupEntry(odr.Database(), txHash)
|
||||||
|
if bHash != (common.Hash{}) {
|
||||||
|
return core.TxStatusIncluded, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send on-demand request message
|
||||||
|
r := &TxStatusRequest{TxHash: txHash}
|
||||||
|
if err := odr.Retrieve(ctx, r); err != nil {
|
||||||
|
return core.TxStatusUnknown, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if r.TxStatus != core.TxStatusIncluded {
|
||||||
|
return r.TxStatus, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Another on-demand request message for retrieve block body, verify block body internally
|
||||||
|
bHash, bIndex, _ = r.TxEntry.BlockHash, r.TxEntry.BlockIndex, r.TxEntry.Index
|
||||||
|
bBody, err := GetBody(ctx, odr, bHash, bIndex)
|
||||||
|
if err != nil {
|
||||||
|
return r.TxStatus, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find matched transaction by given hash, verifying transaction by given hash whether exist
|
||||||
|
for _, tx := range bBody.Transactions {
|
||||||
|
if tx.Hash() == r.TxHash {
|
||||||
|
// Write into database if hash matched, link given hash to verified block hash and index
|
||||||
|
rawdb.WriteTxLookupEntry(odr.Database(), r.TxEntry, r.TxHash)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return r.TxStatus, nil
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue