@@ -327,6 +327,15 @@ func rpcDecodeHexError(gotHex string) *btcjson.RPCError {
327327 gotHex ))
328328}
329329
330+ // rpcInvalidAddressOrKey is a convenience function for returning a nicely
331+ // formatted RPC error which indicates the address or key is invalid.
332+ func rpcInvalidAddressOrKeyError (addr string , msg string ) * btcjson.RPCError {
333+ return & btcjson.RPCError {
334+ Code : btcjson .ErrRPCInvalidAddressOrKey ,
335+ Message : msg ,
336+ }
337+ }
338+
330339// rpcNoTxInfoError is a convenience function for returning a nicely formatted
331340// RPC error which indicates there is no information available for the provided
332341// transaction hash.
@@ -568,59 +577,92 @@ func handleCreateRawTransaction(s *rpcServer, cmd interface{}, closeChan <-chan
568577 // Add all transaction outputs to the transaction after performing
569578 // some validity checks.
570579 params := s .cfg .ChainParams
571- for encodedAddr , amount := range c .Amounts {
572- // Ensure amount is in the valid range for monetary amounts.
573- if amount <= 0 || amount * btcutil .SatoshiPerBitcoin > btcutil .MaxSatoshi {
580+
581+ // Ensure amount is in the valid range for monetary amounts.
582+ // Decode the provided address.
583+ // Ensure the address is one of the supported types and that
584+ // the network encoded with the address matches the network the
585+ // server is currently on.
586+ // Create a new script which pays to the provided address.
587+ // Convert the amount to satoshi.
588+ handleAmountFn := func (amount float64 , encodedAddr string ) (* wire.TxOut ,
589+ error ) {
590+
591+ if amount <= 0 ||
592+ amount * btcutil .SatoshiPerBitcoin > btcutil .MaxSatoshi {
574593 return nil , & btcjson.RPCError {
575594 Code : btcjson .ErrRPCType ,
576- Message : "Invalid amount" ,
595+ Message : "invalid amount" ,
577596 }
578597 }
579598
580- // Decode the provided address.
581599 addr , err := btcutil .DecodeAddress (encodedAddr , params )
582600 if err != nil {
583- return nil , & btcjson.RPCError {
584- Code : btcjson .ErrRPCInvalidAddressOrKey ,
585- Message : "Invalid address or key: " + err .Error (),
586- }
601+ return nil , rpcInvalidAddressOrKeyError (encodedAddr ,
602+ "invalid address or key" )
587603 }
588604
589- // Ensure the address is one of the supported types and that
590- // the network encoded with the address matches the network the
591- // server is currently on.
592605 switch addr .(type ) {
593606 case * btcutil.AddressPubKeyHash :
594607 case * btcutil.AddressScriptHash :
595608 default :
596- return nil , & btcjson.RPCError {
597- Code : btcjson .ErrRPCInvalidAddressOrKey ,
598- Message : "Invalid address or key: " + addr .String (),
599- }
609+ return nil , rpcInvalidAddressOrKeyError (addr .String (),
610+ "invalid address or key" )
600611 }
601612 if ! addr .IsForNet (params ) {
602- return nil , & btcjson.RPCError {
603- Code : btcjson .ErrRPCInvalidAddressOrKey ,
604- Message : "Invalid address: " + encodedAddr +
605- " is for the wrong network" ,
606- }
613+ return nil , rpcInvalidAddressOrKeyError (addr .String (),
614+ "wrong network" )
607615 }
608616
609- // Create a new script which pays to the provided address.
610617 pkScript , err := txscript .PayToAddrScript (addr )
611618 if err != nil {
612- context := "Failed to generate pay-to-address script"
619+ context := "failed to generate pay-to-address script"
613620 return nil , internalRPCError (err .Error (), context )
614621 }
615622
616- // Convert the amount to satoshi.
617623 satoshi , err := btcutil .NewAmount (amount )
618624 if err != nil {
619- context := "Failed to convert amount"
625+ context := "failed to convert amount"
620626 return nil , internalRPCError (err .Error (), context )
621627 }
622628
623- txOut := wire .NewTxOut (int64 (satoshi ), pkScript )
629+ return wire .NewTxOut (int64 (satoshi ), pkScript ), nil
630+ }
631+
632+ handleDataFn := func (key string , value string ) (* wire.TxOut , error ) {
633+ if key != "data" {
634+ context := "output key must be an address or \" data\" "
635+ return nil , & btcjson.RPCError {
636+ Code : btcjson .ErrRPCInvalidParameter ,
637+ Message : context ,
638+ }
639+ }
640+ var data []byte
641+ data , err := hex .DecodeString (value )
642+ if err != nil {
643+ return nil , rpcDecodeHexError (value )
644+ }
645+ return wire .NewTxOut (0 , data ), nil
646+ }
647+
648+ for key , value := range c .Outputs {
649+ var err error
650+ var txOut * wire.TxOut
651+ switch value := value .(type ) {
652+ case float64 :
653+ txOut , err = handleAmountFn (value , key )
654+ case string :
655+ txOut , err = handleDataFn (key , value )
656+ default :
657+ context := "output value must be a string or float"
658+ return nil , & btcjson.RPCError {
659+ Code : btcjson .ErrRPCType ,
660+ Message : context ,
661+ }
662+ }
663+ if err != nil {
664+ return nil , err
665+ }
624666 mtx .AddTxOut (txOut )
625667 }
626668
0 commit comments