package account
import (
- "crypto/hmac"
- "crypto/sha256"
- "encoding/hex"
- "encoding/json"
- "fmt"
"reflect"
- "sort"
"strings"
"sync"
"github.com/golang/groupcache/lru"
+ "github.com/google/uuid"
log "github.com/sirupsen/logrus"
- dbm "github.com/tendermint/tmlibs/db"
"github.com/vapor/blockchain/signers"
"github.com/vapor/blockchain/txbuilder"
"github.com/vapor/consensus"
"github.com/vapor/consensus/segwit"
"github.com/vapor/crypto"
- "github.com/vapor/crypto/ed25519"
"github.com/vapor/crypto/ed25519/chainkd"
"github.com/vapor/crypto/sha3pool"
- chainjson "github.com/vapor/encoding/json"
- "github.com/vapor/equity/compiler"
"github.com/vapor/errors"
"github.com/vapor/protocol"
"github.com/vapor/protocol/bc"
// HardenedKeyStart bip32 hierarchical deterministic wallets
// keys with index ≥ 0x80000000 are hardened keys
HardenedKeyStart = 0x80000000
-)
-
-var (
- accountIndexPrefix = []byte("AccountIndex:")
- accountPrefix = []byte("Account:")
- aliasPrefix = []byte("AccountAlias:")
- contractIndexPrefix = []byte("ContractIndex")
- contractPrefix = []byte("Contract:")
- miningAddressKey = []byte("MiningAddress")
- CoinbaseAbKey = []byte("CoinbaseArbitrary")
+ logModule = "account"
)
// pre-define errors for supporting bytom errorFormatter
var (
- ErrDuplicateAlias = errors.New("duplicate account alias")
- ErrDuplicateIndex = errors.New("duplicate account with same xPubs and index")
- ErrFindAccount = errors.New("fail to find account")
- ErrMarshalAccount = errors.New("failed marshal account")
- ErrInvalidAddress = errors.New("invalid address")
- ErrFindCtrlProgram = errors.New("fail to find account control program")
- ErrDeriveRule = errors.New("invalid key derive rule")
- ErrContractIndex = errors.New("exceed the maximum addresses per account")
- ErrAccountIndex = errors.New("exceed the maximum accounts per xpub")
- ErrFindTransaction = errors.New("no transaction")
+ ErrDuplicateAlias = errors.New("Duplicate account alias")
+ ErrDuplicateIndex = errors.New("Duplicate account with same xPubs and index")
+ ErrFindAccount = errors.New("Failed to find account")
+ ErrMarshalAccount = errors.New("Failed to marshal account")
+ ErrInvalidAddress = errors.New("Invalid address")
+ ErrFindCtrlProgram = errors.New("Failed to find account control program")
+ ErrDeriveRule = errors.New("Invalid key derivation rule")
+ ErrContractIndex = errors.New("Exceeded maximum addresses per account")
+ ErrAccountIndex = errors.New("Exceeded maximum accounts per xpub")
+ ErrFindTransaction = errors.New("No transaction")
+ ErrFindMiningAddress = errors.New("Failed to find mining address")
+ ErrAccountIDEmpty = errors.New("account_id is empty")
)
-// ContractKey account control promgram store prefix
-func ContractKey(hash common.Hash) []byte {
- return append(contractPrefix, hash[:]...)
-}
-
-// Key account store prefix
-func Key(name string) []byte {
- return append(accountPrefix, []byte(name)...)
-}
-
-func aliasKey(name string) []byte {
- return append(aliasPrefix, []byte(name)...)
-}
-
-func bip44ContractIndexKey(accountID string, change bool) []byte {
- key := append(contractIndexPrefix, accountID...)
- if change {
- return append(key, []byte{1}...)
- }
- return append(key, []byte{0}...)
-}
-
-func contractIndexKey(accountID string) []byte {
- return append(contractIndexPrefix, []byte(accountID)...)
-}
-
// Account is structure of Bytom account
type Account struct {
*signers.Signer
// Manager stores accounts and their associated control programs.
type Manager struct {
- db dbm.DB
+ store AccountStore
chain *protocol.Chain
utxoKeeper *utxoKeeper
}
// NewManager creates a new account manager
-func NewManager(walletDB dbm.DB, chain *protocol.Chain) *Manager {
+func NewManager(store AccountStore, chain *protocol.Chain) *Manager {
return &Manager{
- db: walletDB,
+ store: store,
chain: chain,
- utxoKeeper: newUtxoKeeper(chain.BestBlockHeight, walletDB),
+ utxoKeeper: newUtxoKeeper(chain.BestBlockHeight, store),
cache: lru.New(maxAccountCache),
aliasCache: lru.New(maxAccountCache),
delayedACPs: make(map[*txbuilder.TemplateBuilder][]*CtrlProgram),
return nil, errors.Wrap(err)
}
- id := signers.IDGenerate()
+ id := uuid.New().String()
return &Account{Signer: signer, ID: id, Alias: strings.ToLower(strings.TrimSpace(alias))}, nil
}
-func (m *Manager) saveAccount(account *Account, updateIndex bool) error {
- rawAccount, err := json.Marshal(account)
- if err != nil {
- return ErrMarshalAccount
+func (m *Manager) saveAccount(account *Account) error {
+ newStore := m.store.InitBatch()
+
+ // update account index
+ newStore.SetAccountIndex(account)
+ if err := newStore.SetAccount(account); err != nil {
+ return err
}
- storeBatch := m.db.NewBatch()
- storeBatch.Set(Key(account.ID), rawAccount)
- storeBatch.Set(aliasKey(account.Alias), []byte(account.ID))
- if updateIndex {
- storeBatch.Set(GetAccountIndexKey(account.XPubs), common.Unit64ToBytes(account.KeyIndex))
+ if err := newStore.CommitBatch(); err != nil {
+ return err
}
- storeBatch.Write()
+
return nil
}
m.accountMu.Lock()
defer m.accountMu.Unlock()
- if existed := m.db.Get(aliasKey(account.Alias)); existed != nil {
+ _, err := m.store.GetAccountByAlias(account.Alias)
+ if err == nil {
return ErrDuplicateAlias
}
- acct, err := m.GetAccountByXPubsIndex(account.XPubs, account.KeyIndex)
- if err != nil {
+ if err != ErrFindAccount {
return err
}
- if acct != nil {
+ acct, err := m.GetAccountByXPubsIndex(account.XPubs, account.KeyIndex)
+ if err != nil && err != ErrFindAccount {
+ return err
+ } else if acct != nil {
return ErrDuplicateIndex
}
- currentIndex := uint64(0)
- if rawIndexBytes := m.db.Get(GetAccountIndexKey(account.XPubs)); rawIndexBytes != nil {
- currentIndex = common.BytesToUnit64(rawIndexBytes)
- }
- return m.saveAccount(account, account.KeyIndex > currentIndex)
+ return m.saveAccount(account)
}
// Create creates and save a new Account.
m.accountMu.Lock()
defer m.accountMu.Unlock()
- if existed := m.db.Get(aliasKey(alias)); existed != nil {
+ _, err := m.store.GetAccountByAlias(alias)
+ if err == nil {
return nil, ErrDuplicateAlias
+ } else if err != ErrFindAccount {
+ return nil, err
}
acctIndex := uint64(1)
- if rawIndexBytes := m.db.Get(GetAccountIndexKey(xpubs)); rawIndexBytes != nil {
- acctIndex = common.BytesToUnit64(rawIndexBytes) + 1
+ if currentIndex := m.store.GetAccountIndex(xpubs); currentIndex != 0 {
+ acctIndex = currentIndex + 1
}
+
account, err := CreateAccount(xpubs, quorum, alias, acctIndex, deriveRule)
if err != nil {
return nil, err
}
- if err := m.saveAccount(account, true); err != nil {
+ if err := m.saveAccount(account); err != nil {
return nil, err
}
return account, nil
}
-func (m *Manager) UpdateAccountAlias(accountID string, newAlias string) (err error) {
+func (m *Manager) UpdateAccountAlias(accountID string, newAlias string) error {
m.accountMu.Lock()
defer m.accountMu.Unlock()
if err != nil {
return err
}
- oldAlias := account.Alias
+ oldAccount := *account
normalizedAlias := strings.ToLower(strings.TrimSpace(newAlias))
- if existed := m.db.Get(aliasKey(normalizedAlias)); existed != nil {
+ _, err = m.store.GetAccountByAlias(normalizedAlias)
+ if err == nil {
return ErrDuplicateAlias
}
+ if err != ErrFindAccount {
+ return err
+ }
m.cacheMu.Lock()
- m.aliasCache.Remove(oldAlias)
+ m.aliasCache.Remove(oldAccount.Alias)
m.cacheMu.Unlock()
account.Alias = normalizedAlias
- rawAccount, err := json.Marshal(account)
- if err != nil {
- return ErrMarshalAccount
+
+ newStore := m.store.InitBatch()
+
+ if err := newStore.DeleteAccount(&oldAccount); err != nil {
+ return err
+ }
+
+ if err := newStore.SetAccount(account); err != nil {
+ return err
+ }
+
+ if err := newStore.CommitBatch(); err != nil {
+ return err
}
- storeBatch := m.db.NewBatch()
- storeBatch.Delete(aliasKey(oldAlias))
- storeBatch.Set(Key(accountID), rawAccount)
- storeBatch.Set(aliasKey(normalizedAlias), []byte(accountID))
- storeBatch.Write()
return nil
}
return nil
}
-// deleteAccountControlPrograms deletes control program matching accountID
-func (m *Manager) deleteAccountControlPrograms(accountID string) error {
- cps, err := m.ListControlProgram()
- if err != nil {
- return err
- }
-
- var hash common.Hash
- for _, cp := range cps {
- if cp.AccountID == accountID {
- sha3pool.Sum256(hash[:], cp.ControlProgram)
- m.db.Delete(ContractKey(hash))
- }
- }
- return nil
-}
-
-// deleteAccountUtxos deletes utxos matching accountID
-func (m *Manager) deleteAccountUtxos(accountID string) error {
- accountUtxoIter := m.db.IteratorPrefix([]byte(UTXOPreFix))
- defer accountUtxoIter.Release()
- for accountUtxoIter.Next() {
- accountUtxo := &UTXO{}
- if err := json.Unmarshal(accountUtxoIter.Value(), accountUtxo); err != nil {
- return err
- }
-
- if accountID == accountUtxo.AccountID {
- m.db.Delete(StandardUTXOKey(accountUtxo.OutputID))
- }
- }
- return nil
-}
-
// DeleteAccount deletes the account's ID or alias matching account ID.
-func (m *Manager) DeleteAccount(accountID string) (err error) {
+func (m *Manager) DeleteAccount(accountID string) error {
m.accountMu.Lock()
defer m.accountMu.Unlock()
return err
}
- if err := m.deleteAccountControlPrograms(accountID); err != nil {
- return err
- }
- if err := m.deleteAccountUtxos(accountID); err != nil {
- return err
- }
-
m.cacheMu.Lock()
m.aliasCache.Remove(account.Alias)
m.cacheMu.Unlock()
- storeBatch := m.db.NewBatch()
- storeBatch.Delete(aliasKey(account.Alias))
- storeBatch.Delete(Key(account.ID))
- storeBatch.Write()
- return nil
+ return m.store.DeleteAccount(account)
}
// FindByAlias retrieves an account's Signer record by its alias
return m.FindByID(cachedID.(string))
}
- rawID := m.db.Get(aliasKey(alias))
- if rawID == nil {
- return nil, ErrFindAccount
- }
-
- accountID := string(rawID)
- m.cacheMu.Lock()
- m.aliasCache.Add(alias, accountID)
- m.cacheMu.Unlock()
- return m.FindByID(accountID)
+ return m.store.GetAccountByAlias(alias)
}
// FindByID returns an account's Signer record by its ID.
return cachedAccount.(*Account), nil
}
- rawAccount := m.db.Get(Key(id))
- if rawAccount == nil {
- return nil, ErrFindAccount
- }
-
- account := &Account{}
- if err := json.Unmarshal(rawAccount, account); err != nil {
+ account, err := m.store.GetAccountByID(id)
+ if err != nil {
return nil, err
}
// GetAccountByProgram return Account by given CtrlProgram
func (m *Manager) GetAccountByProgram(program *CtrlProgram) (*Account, error) {
- rawAccount := m.db.Get(Key(program.AccountID))
- if rawAccount == nil {
- return nil, ErrFindAccount
- }
-
- account := &Account{}
- return account, json.Unmarshal(rawAccount, account)
+ return m.store.GetAccountByID(program.AccountID)
}
// GetAccountByXPubsIndex get account by xPubs and index
return account, nil
}
}
- return nil, nil
+ return nil, ErrFindAccount
}
// GetAliasByID return the account alias by given ID
func (m *Manager) GetAliasByID(id string) string {
- rawAccount := m.db.Get(Key(id))
- if rawAccount == nil {
+ account, err := m.store.GetAccountByID(id)
+ if err != nil {
log.Warn("GetAliasByID fail to find account")
return ""
}
-
- account := &Account{}
- if err := json.Unmarshal(rawAccount, account); err != nil {
- log.Warn(err)
- }
return account.Alias
}
func (m *Manager) GetCoinbaseArbitrary() []byte {
- if arbitrary := m.db.Get(CoinbaseAbKey); arbitrary != nil {
+ if arbitrary := m.store.GetCoinbaseArbitrary(); arbitrary != nil {
return arbitrary
}
return []byte{}
log.Warningf("GetCoinbaseControlProgram: can't find any account in db")
return vmutil.DefaultCoinbaseProgram()
}
+
if err != nil {
return nil, err
}
+
return cp.ControlProgram, nil
}
// GetCoinbaseCtrlProgram will return the coinbase CtrlProgram
func (m *Manager) GetCoinbaseCtrlProgram() (*CtrlProgram, error) {
- if data := m.db.Get(miningAddressKey); data != nil {
- cp := &CtrlProgram{}
- return cp, json.Unmarshal(data, cp)
+ if cp, err := m.store.GetMiningAddress(); err == nil {
+ return cp, nil
+ } else if err != ErrFindMiningAddress {
+ return nil, err
}
- accountIter := m.db.IteratorPrefix([]byte(accountPrefix))
- defer accountIter.Release()
- if !accountIter.Next() {
- return nil, ErrFindAccount
+ account := new(Account)
+ accounts, err := m.store.ListAccounts("")
+ if err != nil {
+ return nil, err
}
- account := &Account{}
- if err := json.Unmarshal(accountIter.Value(), account); err != nil {
- return nil, err
+ if len(accounts) > 0 {
+ account = accounts[0]
+ } else {
+ return nil, ErrFindAccount
}
program, err := m.CreateAddress(account.ID, false)
return nil, err
}
- rawCP, err := json.Marshal(program)
- if err != nil {
+ if err := m.store.SetMiningAddress(program); err != nil {
return nil, err
}
- m.db.Set(miningAddressKey, rawCP)
return program, nil
}
-// GetContractIndex return the current index
-func (m *Manager) GetContractIndex(accountID string) uint64 {
- index := uint64(0)
- if rawIndexBytes := m.db.Get(contractIndexKey(accountID)); rawIndexBytes != nil {
- index = common.BytesToUnit64(rawIndexBytes)
- }
- return index
-}
-
// GetBip44ContractIndex return the current bip44 contract index
func (m *Manager) GetBip44ContractIndex(accountID string, change bool) uint64 {
- index := uint64(0)
- if rawIndexBytes := m.db.Get(bip44ContractIndexKey(accountID, change)); rawIndexBytes != nil {
- index = common.BytesToUnit64(rawIndexBytes)
- }
- return index
+ return m.store.GetBip44ContractIndex(accountID, change)
}
// GetLocalCtrlProgramByAddress return CtrlProgram by given address
var hash [32]byte
sha3pool.Sum256(hash[:], program)
- rawProgram := m.db.Get(ContractKey(hash))
- if rawProgram == nil {
- return nil, ErrFindCtrlProgram
+
+ cp, err := m.store.GetControlProgram(bc.NewHash(hash))
+ if err != nil {
+ return nil, err
}
- cp := &CtrlProgram{}
- return cp, json.Unmarshal(rawProgram, cp)
+ return cp, nil
}
// GetMiningAddress will return the mining address
if err != nil {
return "", err
}
+
return cp.Address, nil
}
// IsLocalControlProgram check is the input control program belong to local
func (m *Manager) IsLocalControlProgram(prog []byte) bool {
- var hash common.Hash
+ var hash [32]byte
sha3pool.Sum256(hash[:], prog)
- bytes := m.db.Get(ContractKey(hash))
- return bytes != nil
+ cp, err := m.store.GetControlProgram(bc.NewHash(hash))
+ if err != nil || cp == nil {
+ return false
+ }
+ return true
}
// ListAccounts will return the accounts in the db
func (m *Manager) ListAccounts(id string) ([]*Account, error) {
- accounts := []*Account{}
- accountIter := m.db.IteratorPrefix(Key(strings.TrimSpace(id)))
- defer accountIter.Release()
-
- for accountIter.Next() {
- account := &Account{}
- if err := json.Unmarshal(accountIter.Value(), &account); err != nil {
- return nil, err
- }
- accounts = append(accounts, account)
- }
- return accounts, nil
+ return m.store.ListAccounts(id)
}
// ListControlProgram return all the local control program
func (m *Manager) ListControlProgram() ([]*CtrlProgram, error) {
- cps := []*CtrlProgram{}
- cpIter := m.db.IteratorPrefix(contractPrefix)
- defer cpIter.Release()
-
- for cpIter.Next() {
- cp := &CtrlProgram{}
- if err := json.Unmarshal(cpIter.Value(), cp); err != nil {
- return nil, err
- }
- cps = append(cps, cp)
- }
- return cps, nil
+ return m.store.ListControlPrograms()
}
func (m *Manager) ListUnconfirmedUtxo(accountID string, isSmartContract bool) []*UTXO {
Address: miningAddress,
ControlProgram: program,
}
- rawCP, err := json.Marshal(cp)
- if err != nil {
- return "", err
+ if err := m.store.SetMiningAddress(cp); err != nil {
+ return cp.Address, err
}
- m.db.Set(miningAddressKey, rawCP)
return m.GetMiningAddress()
}
func (m *Manager) SetCoinbaseArbitrary(arbitrary []byte) {
- m.db.Set(CoinbaseAbKey, arbitrary)
+ m.store.SetCoinbaseArbitrary(arbitrary)
}
// CreateCtrlProgram generate an address for the select account
} else {
cp, err = createP2SH(account, path)
}
+
if err != nil {
return nil, err
}
+
cp.KeyIndex, cp.Change = addrIdx, change
return cp, nil
}
if err != nil {
return nil, err
}
- scriptHash := crypto.Sha256(signScript)
+ scriptHash := crypto.Sha256(signScript)
address, err := common.NewAddressWitnessScriptHash(scriptHash, &consensus.ActiveNetParams)
if err != nil {
return nil, err
}, nil
}
-func GetAccountIndexKey(xpubs []chainkd.XPub) []byte {
- var hash [32]byte
- var xPubs []byte
- cpy := append([]chainkd.XPub{}, xpubs[:]...)
- sort.Sort(signers.SortKeys(cpy))
- for _, xpub := range cpy {
- xPubs = append(xPubs, xpub[:]...)
- }
- sha3pool.Sum256(hash[:], xPubs)
- return append(accountIndexPrefix, hash[:]...)
+func (m *Manager) GetContractIndex(accountID string) uint64 {
+ return m.store.GetContractIndex(accountID)
}
func (m *Manager) getCurrentContractIndex(account *Account, change bool) (uint64, error) {
switch account.DeriveRule {
case signers.BIP0032:
- return m.GetContractIndex(account.ID), nil
+ return m.store.GetContractIndex(account.ID), nil
case signers.BIP0044:
- return m.GetBip44ContractIndex(account.ID, change), nil
+ return m.store.GetBip44ContractIndex(account.ID, change), nil
}
return 0, ErrDeriveRule
}
if err != nil {
return nil, err
}
+
redeemContract := addr.ScriptAddress()
program := []byte{}
switch addr.(type) {
if err != nil {
return nil, err
}
+
return program, nil
}
func (m *Manager) saveControlProgram(prog *CtrlProgram, updateIndex bool) error {
- var hash common.Hash
+ var hash [32]byte
sha3pool.Sum256(hash[:], prog.ControlProgram)
acct, err := m.GetAccountByProgram(prog)
return err
}
- accountCP, err := json.Marshal(prog)
- if err != nil {
- return err
+ newStore := m.store.InitBatch()
+
+ if err := newStore.SetControlProgram(bc.NewHash(hash), prog); err != nil {
+ return nil
}
- storeBatch := m.db.NewBatch()
- storeBatch.Set(ContractKey(hash), accountCP)
if updateIndex {
switch acct.DeriveRule {
case signers.BIP0032:
- storeBatch.Set(contractIndexKey(acct.ID), common.Unit64ToBytes(prog.KeyIndex))
+ newStore.SetContractIndex(acct.ID, prog.KeyIndex)
case signers.BIP0044:
- storeBatch.Set(bip44ContractIndexKey(acct.ID, prog.Change), common.Unit64ToBytes(prog.KeyIndex))
+ newStore.SetBip44ContractIndex(acct.ID, prog.Change, prog.KeyIndex)
}
}
- storeBatch.Write()
- return nil
+ return newStore.CommitBatch()
}
// SaveControlPrograms save account control programs
return nil
}
-func (m *Manager) CreatePeginAddress(accountID string, change bool) (string, []byte, error) {
- // 通过配置获取
- claimCtrlProg, _ := m.CreateAddress(accountID, change)
- claimScript := claimCtrlProg.ControlProgram
-
- federationRedeemScript := vmutil.CalculateContract(consensus.ActiveNetParams.FedpegXPubs, claimScript)
-
- scriptHash := crypto.Sha256(federationRedeemScript)
-
- address, err := common.NewPeginAddressWitnessScriptHash(scriptHash, &consensus.ActiveNetParams)
- if err != nil {
- return "", nil, err
- }
-
- return address.EncodeAddress(), claimScript, nil
-
+func (m *Manager) SetStandardUTXO(outputID bc.Hash, utxo *UTXO) error {
+ return m.store.SetStandardUTXO(outputID, utxo)
}
-func (m *Manager) GetPeginControlPrograms(claimScript []byte) (string, []byte) {
- federationRedeemScript := vmutil.CalculateContract(consensus.ActiveNetParams.FedpegXPubs, claimScript)
- scriptHash := crypto.Sha256(federationRedeemScript)
-
- address, err := common.NewPeginAddressWitnessScriptHash(scriptHash, &consensus.ActiveNetParams)
- if err != nil {
- return "", nil
- }
-
- redeemContract := address.ScriptAddress()
-
- program := []byte{}
- program, err = vmutil.P2WSHProgram(redeemContract)
- if err != nil {
- return "", nil
- }
-
- return address.EncodeAddress(), program
-}
-
-var lockWith2of3KeysFmt = `
-contract LockWith2of3Keys(%s) locks amount of asset {
- clause unlockWith2Sigs(%s) {
- verify checkTxMultiSig(%s)
- unlock amount of asset
- }
-}
-`
-
-func (m *Manager) CreatePeginContractPrograms(accountID string, change bool) (string, []byte, error) {
- // 通过配置获取
- claimCtrlProg, err := m.CreateAddress(accountID, change)
- if err != nil {
- return "", nil, err
- }
- claimScript := claimCtrlProg.ControlProgram
-
- peginContractPrograms, err := m.GetPeginContractPrograms(claimScript)
- if err != nil {
- return "", nil, err
- }
- return hex.EncodeToString(peginContractPrograms), claimScript, nil
-
-}
-
-func (m *Manager) CreatePeginContractAddress(accountID string, change bool) (string, []byte, error) {
- // 通过配置获取
- claimCtrlProg, err := m.CreateAddress(accountID, change)
- if err != nil {
- return "", nil, err
- }
- claimScript := claimCtrlProg.ControlProgram
-
- peginContractPrograms, err := m.GetPeginContractPrograms(claimScript)
- if err != nil {
- return "", nil, err
- }
-
- scriptHash := crypto.Sha256(peginContractPrograms)
-
- address, err := common.NewPeginAddressWitnessScriptHash(scriptHash, &consensus.ActiveNetParams)
- if err != nil {
- return "", nil, err
- }
-
- return address.EncodeAddress(), claimScript, nil
-
+func (m *Manager) DeleteStandardUTXO(outputID bc.Hash) {
+ m.store.DeleteStandardUTXO(outputID)
}
-func (m *Manager) GetPeginContractControlPrograms(claimScript []byte) (string, []byte) {
-
- peginContractPrograms, err := m.GetPeginContractPrograms(claimScript)
- if err != nil {
- return "", nil
- }
- scriptHash := crypto.Sha256(peginContractPrograms)
-
- address, err := common.NewPeginAddressWitnessScriptHash(scriptHash, &consensus.ActiveNetParams)
- if err != nil {
- return "", nil
- }
-
- redeemContract := address.ScriptAddress()
-
- program := []byte{}
- program, err = vmutil.P2WSHProgram(redeemContract)
- if err != nil {
- return "", nil
- }
-
- return address.EncodeAddress(), program
-}
-
-func (m *Manager) GetPeginContractPrograms(claimScript []byte) ([]byte, error) {
-
- pubkeys := getNewXpub(consensus.ActiveNetParams.FedpegXPubs, claimScript)
- num := len(pubkeys)
- if num == 0 {
- return nil, errors.New("Fedpeg's XPubs is empty")
- }
- params := ""
- unlockParams := ""
- checkParams := "["
-
- for index := 0; index < num; index++ {
- param := fmt.Sprintf("pubkey%d", index+1)
- params += param
- checkParams += param
- if (index + 1) < num {
- params += ","
- checkParams += ","
- }
- }
- params += ": PublicKey"
- checkParams += "],["
-
- signNum := getNumberOfSignaturesRequired(pubkeys)
- for index := 0; index < signNum; index++ {
- param := fmt.Sprintf("sig%d", index+1)
- unlockParams += param
- checkParams += param
- if index+1 < signNum {
- unlockParams += ","
- checkParams += ","
- }
- }
-
- unlockParams += ": Signature"
- checkParams += "]"
-
- lockWith2of3Keys := fmt.Sprintf(lockWith2of3KeysFmt, params, unlockParams, checkParams)
- r := strings.NewReader(lockWith2of3Keys)
- compiled, err := compiler.Compile(r)
- if err != nil {
- return nil, errors.New("Compile contract failed")
- }
-
- contract := compiled[len(compiled)-1]
-
- if num < len(contract.Params) {
- return nil, errors.New("Compile contract failed")
- }
-
- contractArgs, err := convertArguments(contract, pubkeys)
- if err != nil {
- fmt.Println("Convert arguments into contract parameters error:", err)
- return nil, errors.New("Convert arguments into contract parameters error")
- }
-
- instantProg, err := instantiateContract(contract, contractArgs)
- if err != nil {
- fmt.Println("Instantiate contract error:", err)
- return nil, errors.New("Instantiate contract error")
- }
-
- return instantProg, nil
-}
-
-func getNewXpub(federationRedeemXPub []chainkd.XPub, claimScript []byte) []ed25519.PublicKey {
-
- var pubkeys []ed25519.PublicKey
- for _, xpub := range federationRedeemXPub {
- // pub + scriptPubKey 生成一个随机数A
- var tmp [32]byte
- h := hmac.New(sha256.New, xpub[:])
- h.Write(claimScript)
- tweak := h.Sum(tmp[:])
- // pub + A 生成一个新的公钥pub_new
- chaildXPub := xpub.Child(tweak)
- pubkeys = append(pubkeys, chaildXPub.PublicKey())
- }
- return pubkeys
-}
-
-func getNumberOfSignaturesRequired(pubkeys []ed25519.PublicKey) int {
- return len(pubkeys)/2 + 1
-}
-
-// InstantiateContract instantiate contract parameters
-func instantiateContract(contract *compiler.Contract, args []compiler.ContractArg) ([]byte, error) {
- program, err := compiler.Instantiate(contract.Body, contract.Params, contract.Recursive, args)
- if err != nil {
- return nil, err
- }
-
- return program, nil
-}
-
-func convertArguments(contract *compiler.Contract, args []ed25519.PublicKey) ([]compiler.ContractArg, error) {
- var contractArgs []compiler.ContractArg
- for i, p := range contract.Params {
- var argument compiler.ContractArg
- switch p.Type {
- case "PublicKey":
- argument.S = (*chainjson.HexBytes)(&args[i])
- default:
- return nil, errors.New("Contract parameter type error")
- }
- contractArgs = append(contractArgs, argument)
- }
-
- return contractArgs, nil
+func (m *Manager) GetControlProgram(hash bc.Hash) (*CtrlProgram, error) {
+ return m.store.GetControlProgram(hash)
}