blockbook/bchain/coins/ecash/ecashparser.go
Sai Raj 49ca2ba2cf Self restart on repeated error and package name
- Adding self restart when repeated error occurs with backend rpc connection

- renamed package name to reflect correctly
2024-07-01 22:20:48 -04:00

190 lines
4.8 KiB
Go

package ecash
import (
"fmt"
"github.com/pirk/ecashutil"
"github.com/martinboehm/btcutil"
"github.com/martinboehm/btcutil/chaincfg"
"github.com/martinboehm/btcutil/txscript"
"github.com/pirk/ecashaddr-converter/address"
"github.com/ranchimall/blockbook/bchain"
"github.com/ranchimall/blockbook/bchain/coins/btc"
)
// AddressFormat type is used to specify different formats of address
type AddressFormat = uint8
const (
// Legacy AddressFormat is the same as Bitcoin
Legacy AddressFormat = iota
// CashAddr AddressFormat is new eCash standard
CashAddr
)
const (
// MainNetPrefix is CashAddr prefix for mainnet
MainNetPrefix = "ecash:"
// TestNetPrefix is CashAddr prefix for testnet
TestNetPrefix = "ectest:"
// RegTestPrefix is CashAddr prefix for regtest
RegTestPrefix = "ecreg:"
)
var (
// MainNetParams are parser parameters for mainnet
MainNetParams chaincfg.Params
// TestNetParams are parser parameters for testnet
TestNetParams chaincfg.Params
// RegtestParams are parser parameters for regtest
RegtestParams chaincfg.Params
)
func init() {
MainNetParams = chaincfg.MainNetParams
MainNetParams.Net = ecashutil.MainnetMagic
TestNetParams = chaincfg.TestNet3Params
TestNetParams.Net = ecashutil.TestnetMagic
RegtestParams = chaincfg.RegressionNetParams
RegtestParams.Net = ecashutil.Regtestmagic
}
// ECashParser handle
type ECashParser struct {
*btc.BitcoinLikeParser
AddressFormat AddressFormat
}
// NewECashParser returns new ECashParser instance
func NewECashParser(params *chaincfg.Params, c *btc.Configuration) (*ECashParser, error) {
var format AddressFormat
switch c.AddressFormat {
case "":
fallthrough
case "cashaddr":
format = CashAddr
case "legacy":
format = Legacy
default:
return nil, fmt.Errorf("Unknown address format: %s", c.AddressFormat)
}
p := &ECashParser{
BitcoinLikeParser: btc.NewBitcoinLikeParser(params, c),
AddressFormat: format,
}
p.OutputScriptToAddressesFunc = p.outputScriptToAddresses
p.AmountDecimalPoint = 2
return p, nil
}
// GetChainParams contains network parameters for the main eCash network,
// the regression test eCash network, the test eCash network and
// the simulation test eCash network, in this order
func GetChainParams(chain string) *chaincfg.Params {
if !chaincfg.IsRegistered(&MainNetParams) {
err := chaincfg.Register(&MainNetParams)
if err == nil {
err = chaincfg.Register(&TestNetParams)
}
if err == nil {
err = chaincfg.Register(&RegtestParams)
}
if err != nil {
panic(err)
}
}
switch chain {
case "test":
return &TestNetParams
case "regtest":
return &RegtestParams
default:
return &MainNetParams
}
}
// GetAddrDescFromAddress returns internal address representation of given address
func (p *ECashParser) GetAddrDescFromAddress(address string) (bchain.AddressDescriptor, error) {
return p.addressToOutputScript(address)
}
// addressToOutputScript converts address to ScriptPubKey
func (p *ECashParser) addressToOutputScript(address string) ([]byte, error) {
if isCashAddr(address) {
da, err := ecashutil.DecodeAddress(address, p.Params)
if err != nil {
return nil, err
}
script, err := ecashutil.PayToAddrScript(da)
if err != nil {
return nil, err
}
return script, nil
}
da, err := btcutil.DecodeAddress(address, p.Params)
if err != nil {
return nil, err
}
script, err := txscript.PayToAddrScript(da)
if err != nil {
return nil, err
}
return script, nil
}
func isCashAddr(addr string) bool {
n := len(addr)
switch {
case n > len(MainNetPrefix) && addr[0:len(MainNetPrefix)] == MainNetPrefix:
return true
case n > len(TestNetPrefix) && addr[0:len(TestNetPrefix)] == TestNetPrefix:
return true
case n > len(RegTestPrefix) && addr[0:len(RegTestPrefix)] == RegTestPrefix:
return true
}
return false
}
// outputScriptToAddresses converts ScriptPubKey to bitcoin addresses
func (p *ECashParser) outputScriptToAddresses(script []byte) ([]string, bool, error) {
// convert possible P2PK script to P2PK, which ecashutil can process
var err error
script, err = txscript.ConvertP2PKtoP2PKH(p.Params.Base58CksumHasher, script)
if err != nil {
return nil, false, err
}
a, err := ecashutil.ExtractPkScriptAddrs(script, p.Params)
if err != nil {
// do not return unknown script type error as error
if err.Error() == "unknown script type" {
// try OP_RETURN script
or := p.TryParseOPReturn(script)
if or != "" {
return []string{or}, false, nil
}
return []string{}, false, nil
}
return nil, false, err
}
// EncodeAddress returns CashAddr address
addr := a.EncodeAddress()
if p.AddressFormat == Legacy {
da, err := address.NewFromString(addr)
if err != nil {
return nil, false, err
}
ca, err := da.Legacy()
if err != nil {
return nil, false, err
}
addr, err = ca.Encode()
if err != nil {
return nil, false, err
}
}
return []string{addr}, len(addr) > 0, nil
}