// GetLiveTicketsForAddress gets all currently active tickets for a given // address. func (tmdb *TicketDB) GetLiveTicketsForAddress( address dcrutil.Address) ([]chainhash.Hash, error) { tmdb.mtx.Lock() defer tmdb.mtx.Unlock() var ltfa []chainhash.Hash for i := 0; i < BucketsSize; i++ { for _, ticket := range tmdb.maps.ticketMap[i] { // Load the ticket from the database and find the address that it's // going to. txReply, err := tmdb.database.FetchTxBySha(&ticket.SStxHash) if err != nil { return nil, err } _, addr, _, err := txscript.ExtractPkScriptAddrs(txReply[0].Tx.TxOut[0].Version, txReply[0].Tx.TxOut[0].PkScript, tmdb.chainParams) if err != nil { return nil, err } // Compare the HASH160 result and see if it's equal. if bytes.Equal(addr[0].ScriptAddress(), address.ScriptAddress()) { ltfa = append(ltfa, ticket.SStxHash) } } } return ltfa, nil }
// PayToSSRtx creates a new script to pay a transaction output to a // public key hash, but tags the output with OP_SSRTX. For use in constructing // valid SSRtx. func PayToSSRtx(addr dcrutil.Address) ([]byte, error) { if addr == nil { return nil, ErrUnsupportedAddress } // Only pay to pubkey hash and pay to script hash are // supported. scriptType := PubKeyHashTy switch addr := addr.(type) { case *dcrutil.AddressPubKeyHash: if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { return nil, ErrUnsupportedAddress } break case *dcrutil.AddressScriptHash: scriptType = ScriptHashTy break default: return nil, ErrUnsupportedAddress } hash := addr.ScriptAddress() if scriptType == PubKeyHashTy { return NewScriptBuilder().AddOp(OP_SSRTX).AddOp(OP_DUP). AddOp(OP_HASH160).AddData(hash).AddOp(OP_EQUALVERIFY). AddOp(OP_CHECKSIG).Script() } return NewScriptBuilder().AddOp(OP_SSRTX).AddOp(OP_HASH160). AddData(hash).AddOp(OP_EQUAL).Script() }
// dumpSStxHashes dumps the hashes of all owned SStxs for some address. func (s *StakeStore) dumpSStxHashesForAddress(ns walletdb.ReadBucket, addr dcrutil.Address) ([]chainhash.Hash, error) { // Extract the HASH160 script hash; if it's not 20 bytes // long, return an error. hash160 := addr.ScriptAddress() if len(hash160) != 20 { str := "stake store is closed" return nil, stakeStoreError(ErrInput, str, nil) } _, addrIsP2SH := addr.(*dcrutil.AddressScriptHash) allTickets := s.dumpSStxHashes() var ticketsForAddr []chainhash.Hash // Access the database and store the result locally. for _, h := range allTickets { thisHash160, p2sh, err := fetchSStxRecordSStxTicketHash160(ns, &h) if err != nil { str := "failure getting ticket 0th out script hashes from db" return nil, stakeStoreError(ErrDatabase, str, err) } if addrIsP2SH != p2sh { continue } if bytes.Equal(hash160, thisHash160) { ticketsForAddr = append(ticketsForAddr, h) } } return ticketsForAddr, nil }
// dumpSStxHashes dumps the hashes of all owned SStxs for some address. func (s *StakeStore) dumpSStxHashesForAddress(addr dcrutil.Address) ([]chainhash.Hash, error) { // Extract the HASH160 script hash; if it's not 20 bytes // long, return an error. scriptHash := addr.ScriptAddress() if len(scriptHash) != 20 { str := "stake store is closed" return nil, stakeStoreError(ErrInput, str, nil) } var err error allTickets := s.dumpSStxHashes() var ticketsForAddr []chainhash.Hash // Access the database and store the result locally. err = s.namespace.View(func(tx walletdb.Tx) error { var err error var thisScrHash []byte for _, h := range allTickets { thisScrHash, err = fetchSStxRecordSStxTicketScriptHash(tx, &h) if err != nil { return err } if bytes.Equal(scriptHash, thisScrHash) { ticketsForAddr = append(ticketsForAddr, h) } } return nil }) if err != nil { str := "failure getting ticket 0th out script hashes from db" return nil, stakeStoreError(ErrDatabase, str, err) } return ticketsForAddr, nil }
// stakePoolUserInfo returns the stake pool user information for a given stake // pool user, keyed to their P2SH voting address. func (s *StakeStore) stakePoolUserInfo(ns walletdb.ReadBucket, user dcrutil.Address) (*StakePoolUser, error) { _, isScriptHash := user.(*dcrutil.AddressScriptHash) _, isP2PKH := user.(*dcrutil.AddressPubKeyHash) if !(isScriptHash || isP2PKH) { str := fmt.Sprintf("user %v is invalid", user.EncodeAddress()) return nil, stakeStoreError(ErrBadPoolUserAddr, str, nil) } scriptHashB := user.ScriptAddress() scriptHash := new([20]byte) copy(scriptHash[:], scriptHashB) stakePoolUser := new(StakePoolUser) // Catch missing user errors below and blank out the stake // pool user information for the section if the user has // no entries. missingValidTickets, missingInvalidTickets := false, false userTickets, fetchErrVal := fetchStakePoolUserTickets(ns, *scriptHash) if fetchErrVal != nil { stakeMgrErr, is := fetchErrVal.(StakeStoreError) if is { missingValidTickets = stakeMgrErr.ErrorCode == ErrPoolUserTicketsNotFound } else { return nil, fetchErrVal } } if missingValidTickets { userTickets = make([]*PoolTicket, 0) } invalTickets, fetchErrInval := fetchStakePoolUserInvalTickets(ns, *scriptHash) if fetchErrInval != nil { stakeMgrErr, is := fetchErrInval.(StakeStoreError) if is { missingInvalidTickets = stakeMgrErr.ErrorCode == ErrPoolUserInvalTcktsNotFound } else { return nil, fetchErrInval } } if missingInvalidTickets { invalTickets = make([]*chainhash.Hash, 0) } stakePoolUser.Tickets = userTickets stakePoolUser.InvalidTickets = invalTickets return stakePoolUser, nil }
// updateStakePoolUserInvalTickets updates the list of invalid stake pool // tickets for a given user. If the ticket does not currently exist in the // database, it adds it. func (s *StakeStore) updateStakePoolUserInvalTickets(ns walletdb.ReadWriteBucket, user dcrutil.Address, ticket *chainhash.Hash) error { _, isScriptHash := user.(*dcrutil.AddressScriptHash) _, isP2PKH := user.(*dcrutil.AddressPubKeyHash) if !(isScriptHash || isP2PKH) { str := fmt.Sprintf("user %v is invalid", user.EncodeAddress()) return stakeStoreError(ErrBadPoolUserAddr, str, nil) } scriptHashB := user.ScriptAddress() scriptHash := new([20]byte) copy(scriptHash[:], scriptHashB) return updateStakePoolInvalUserTickets(ns, *scriptHash, ticket) }
// GenerateSStxAddrPush generates an OP_RETURN push for SSGen payment addresses in // an SStx. func GenerateSStxAddrPush(addr dcrutil.Address, amount dcrutil.Amount, limits uint16) ([]byte, error) { if addr == nil { return nil, ErrUnsupportedAddress } // Only pay to pubkey hash and pay to script hash are // supported. scriptType := PubKeyHashTy switch addr := addr.(type) { case *dcrutil.AddressPubKeyHash: if addr.DSA(addr.Net()) != chainec.ECTypeSecp256k1 { return nil, ErrUnsupportedAddress } break case *dcrutil.AddressScriptHash: scriptType = ScriptHashTy break default: return nil, ErrUnsupportedAddress } // Prefix dataPushes := []byte{ 0x6a, // OP_RETURN 0x1e, // OP_DATA_30 } hash := addr.ScriptAddress() amountBuffer := make([]byte, 8) binary.LittleEndian.PutUint64(amountBuffer, uint64(amount)) // Set the bit flag indicating pay to script hash. if scriptType == ScriptHashTy { amountBuffer[7] |= 1 << 7 } limitsBuffer := make([]byte, 2) binary.LittleEndian.PutUint16(limitsBuffer, limits) // Concatenate the prefix, pubkeyhash, and amount. addrOut := append(dataPushes, hash...) addrOut = append(addrOut, amountBuffer...) addrOut = append(addrOut, limitsBuffer...) return addrOut, nil }
// PayToAddrScript creates a new script to pay a transaction output to a the // specified address. func PayToAddrScript(addr dcrutil.Address) ([]byte, error) { switch addr := addr.(type) { case *dcrutil.AddressPubKeyHash: if addr == nil { return nil, ErrUnsupportedAddress } switch addr.DSA(addr.Net()) { case chainec.ECTypeSecp256k1: return payToPubKeyHashScript(addr.ScriptAddress()) case chainec.ECTypeEdwards: return payToPubKeyHashEdwardsScript(addr.ScriptAddress()) case chainec.ECTypeSecSchnorr: return payToPubKeyHashSchnorrScript(addr.ScriptAddress()) } case *dcrutil.AddressScriptHash: if addr == nil { return nil, ErrUnsupportedAddress } return payToScriptHashScript(addr.ScriptAddress()) case *dcrutil.AddressSecpPubKey: if addr == nil { return nil, ErrUnsupportedAddress } return payToPubKeyScript(addr.ScriptAddress()) case *dcrutil.AddressEdwardsPubKey: if addr == nil { return nil, ErrUnsupportedAddress } return payToEdwardsPubKeyScript(addr.ScriptAddress()) case *dcrutil.AddressSecSchnorrPubKey: if addr == nil { return nil, ErrUnsupportedAddress } return payToSchnorrPubKeyScript(addr.ScriptAddress()) } return nil, ErrUnsupportedAddress }