btcjson+rpc: match bitcoind's RPC error codes for rejected transactions

This commit is contained in:
Wilmer Paulino 2019-05-11 17:48:24 -07:00
parent 96897255fd
commit d055892599
No known key found for this signature in database
GPG key ID: 6DF57B9F9514972F
2 changed files with 38 additions and 10 deletions

View file

@ -76,6 +76,9 @@ const (
ErrRPCInvalidTxVout RPCErrorCode = -5 ErrRPCInvalidTxVout RPCErrorCode = -5
ErrRPCRawTxString RPCErrorCode = -32602 ErrRPCRawTxString RPCErrorCode = -32602
ErrRPCDecodeHexString RPCErrorCode = -22 ErrRPCDecodeHexString RPCErrorCode = -22
ErrRPCTxError RPCErrorCode = -25
ErrRPCTxRejected RPCErrorCode = -26
ErrRPCTxAlreadyInChain RPCErrorCode = -27
) )
// Errors that are specific to btcd. // Errors that are specific to btcd.

View file

@ -3323,19 +3323,44 @@ func handleSendRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan st
if err != nil { if err != nil {
// When the error is a rule error, it means the transaction was // When the error is a rule error, it means the transaction was
// simply rejected as opposed to something actually going wrong, // simply rejected as opposed to something actually going wrong,
// so log it as such. Otherwise, something really did go wrong, // so log it as such. Otherwise, something really did go wrong,
// so log it as an actual error. In both cases, a JSON-RPC // so log it as an actual error and return.
// error is returned to the client with the deserialization ruleErr, ok := err.(mempool.RuleError)
// error code (to match bitcoind behavior). if !ok {
if _, ok := err.(mempool.RuleError); ok {
rpcsLog.Debugf("Rejected transaction %v: %v", tx.Hash(),
err)
} else {
rpcsLog.Errorf("Failed to process transaction %v: %v", rpcsLog.Errorf("Failed to process transaction %v: %v",
tx.Hash(), err) tx.Hash(), err)
return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCTxError,
Message: "TX rejected: " + err.Error(),
}
} }
rpcsLog.Debugf("Rejected transaction %v: %v", tx.Hash(), err)
// We'll then map the rule error to the appropriate RPC error,
// matching bitcoind's behavior.
code := btcjson.ErrRPCTxError
if txRuleErr, ok := ruleErr.Err.(mempool.TxRuleError); ok {
errDesc := txRuleErr.Description
switch {
case strings.Contains(
strings.ToLower(errDesc), "orphan transaction",
):
code = btcjson.ErrRPCTxError
case strings.Contains(
strings.ToLower(errDesc), "transaction already exists",
):
code = btcjson.ErrRPCTxAlreadyInChain
default:
code = btcjson.ErrRPCTxRejected
}
}
return nil, &btcjson.RPCError{ return nil, &btcjson.RPCError{
Code: btcjson.ErrRPCDeserialization, Code: code,
Message: "TX rejected: " + err.Error(), Message: "TX rejected: " + err.Error(),
} }
} }
@ -4281,7 +4306,7 @@ func newRPCServer(config *rpcserverConfig) (*rpcServer, error) {
gbtWorkState: newGbtWorkState(config.TimeSource), gbtWorkState: newGbtWorkState(config.TimeSource),
helpCacher: newHelpCacher(), helpCacher: newHelpCacher(),
requestProcessShutdown: make(chan struct{}), requestProcessShutdown: make(chan struct{}),
quit: make(chan int), quit: make(chan int),
} }
if cfg.RPCUser != "" && cfg.RPCPass != "" { if cfg.RPCUser != "" && cfg.RPCPass != "" {
login := cfg.RPCUser + ":" + cfg.RPCPass login := cfg.RPCUser + ":" + cfg.RPCPass