ci: test functional-tests
-.PHONY: all target release-all clean test benchmark
\ No newline at end of file
+.PHONY: all target release-all clean test benchmark
ErrFindCtrlProgram = errors.New("fail to find account control program")
)
-func aliasKey(name string) []byte {
- return append(aliasPrefix, []byte(name)...)
+// ContractKey account control promgram store prefix
+func ContractKey(hash common.Hash) []byte {
+ return append(contractPrefix, hash[:]...)
}
// Key account store prefix
return append(accountPrefix, []byte(name)...)
}
-// ContractKey account control promgram store prefix
-func ContractKey(hash common.Hash) []byte {
- return append(contractPrefix, hash[:]...)
+func aliasKey(name string) []byte {
+ return append(aliasPrefix, []byte(name)...)
}
func contractIndexKey(accountID string) []byte {
// GetCoinbaseControlProgram will return a coinbase script
func (m *Manager) GetCoinbaseControlProgram() ([]byte, error) {
+ cp, err := m.GetCoinbaseCtrlProgram()
+ if err == ErrFindAccount {
+ 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.ControlProgram, json.Unmarshal(data, cp)
+ return cp, json.Unmarshal(data, cp)
}
accountIter := m.db.IteratorPrefix([]byte(accountPrefix))
defer accountIter.Release()
if !accountIter.Next() {
- log.Warningf("GetCoinbaseControlProgram: can't find any account in db")
- return vmutil.DefaultCoinbaseProgram()
+ return nil, ErrFindAccount
}
account := &Account{}
}
m.db.Set(miningAddressKey, rawCP)
- return program.ControlProgram, nil
+ return program, nil
}
// GetContractIndex return the current index
return index
}
-// GetProgramByAddress return CtrlProgram by given address
-func (m *Manager) GetProgramByAddress(address string) (*CtrlProgram, error) {
- addr, err := common.DecodeAddress(address, &consensus.ActiveNetParams)
- if err != nil {
- return nil, err
- }
-
- redeemContract := addr.ScriptAddress()
- program := []byte{}
- switch addr.(type) {
- case *common.AddressWitnessPubKeyHash:
- program, err = vmutil.P2WPKHProgram(redeemContract)
- case *common.AddressWitnessScriptHash:
- program, err = vmutil.P2WSHProgram(redeemContract)
- default:
- return nil, ErrInvalidAddress
- }
+// GetLocalCtrlProgramByAddress return CtrlProgram by given address
+func (m *Manager) GetLocalCtrlProgramByAddress(address string) (*CtrlProgram, error) {
+ program, err := m.getProgramByAddress(address)
if err != nil {
return nil, err
}
return cp, json.Unmarshal(rawProgram, cp)
}
+// GetMiningAddress will return the mining address
+func (m *Manager) GetMiningAddress() (string, error) {
+ cp, err := m.GetCoinbaseCtrlProgram()
+ 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
m.utxoKeeper.RemoveUnconfirmedUtxo(hashes)
}
+// SetMiningAddress will set the mining address
+func (m *Manager) SetMiningAddress(miningAddress string) (string, error) {
+ program, err := m.getProgramByAddress(miningAddress)
+ if err != nil {
+ return "", err
+ }
+
+ cp := &CtrlProgram{
+ Address: miningAddress,
+ ControlProgram: program,
+ }
+ rawCP, err := json.Marshal(cp)
+ if err != nil {
+ return "", err
+ }
+
+ m.db.Set(miningAddressKey, rawCP)
+ return m.GetMiningAddress()
+}
+
// CreateAddress generate an address for the select account
func (m *Manager) createAddress(account *Account, change bool) (cp *CtrlProgram, err error) {
if len(account.XPubs) == 1 {
return nextIndex
}
+func (m *Manager) getProgramByAddress(address string) ([]byte, error) {
+ addr, err := common.DecodeAddress(address, &consensus.ActiveNetParams)
+ if err != nil {
+ return nil, err
+ }
+
+ redeemContract := addr.ScriptAddress()
+ program := []byte{}
+ switch addr.(type) {
+ case *common.AddressWitnessPubKeyHash:
+ program, err = vmutil.P2WPKHProgram(redeemContract)
+ case *common.AddressWitnessScriptHash:
+ program, err = vmutil.P2WSHProgram(redeemContract)
+ default:
+ return nil, ErrInvalidAddress
+ }
+ if err != nil {
+ return nil, err
+ }
+ return program, nil
+}
+
func (m *Manager) insertControlPrograms(progs ...*CtrlProgram) error {
var hash common.Hash
for _, prog := range progs {
sort.Sort(SortByIndex(addresses))
return NewSuccessResponse(addresses)
}
+
+type minigAddressResp struct {
+ MiningAddress string `json:"mining_address"`
+}
+
+func (a *API) getMiningAddress(ctx context.Context) Response {
+ miningAddress, err := a.wallet.AccountMgr.GetMiningAddress()
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+ return NewSuccessResponse(minigAddressResp{
+ MiningAddress: miningAddress,
+ })
+}
+
+// POST /set-mining-address
+func (a *API) setMiningAddress(ctx context.Context, in struct {
+ MiningAddress string `json:"mining_address"`
+}) Response {
+ miningAddress, err := a.wallet.AccountMgr.SetMiningAddress(in.MiningAddress)
+ if err != nil {
+ return NewErrorResponse(err)
+ }
+ return NewSuccessResponse(minigAddressResp{
+ MiningAddress: miningAddress,
+ })
+}
m.Handle("/validate-address", jsonHandler(a.validateAddress))
m.Handle("/list-pubkeys", jsonHandler(a.listPubKeys))
+ m.Handle("/get-mining-address", jsonHandler(a.getMiningAddress))
+ m.Handle("/set-mining-address", jsonHandler(a.setMiningAddress))
+
m.Handle("/create-asset", jsonHandler(a.createAsset))
m.Handle("/update-asset-alias", jsonHandler(a.updateAssetAlias))
m.Handle("/get-asset", jsonHandler(a.getAsset))
"github.com/bytom/accesstoken"
"github.com/bytom/blockchain/rpc"
"github.com/bytom/blockchain/txbuilder"
- "github.com/bytom/testutil"
"github.com/bytom/consensus"
+ "github.com/bytom/testutil"
)
func TestAPIHandler(t *testing.T) {
respWant *EstimateTxGasResp
}{
{
- path: "/estimate-transaction-gas",
- tmplStr: `{"raw_transaction":"070100010160015e9a4e2bbae57dd71b6a827fb50aaeb744ce3ae6f45c4aec7494ad097213220e8affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0cea1bc5800011600144a6322008c5424251c7502c7d7d55f6389c3c358010001013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086f29b3301160014fa61b0629e5f2da2bb8b08e7fc948dbd265234f700","signing_instructions":[{"position":0,"witness_components":[{"type":"raw_tx_signature","quorum":1,"keys":[{"xpub":"19204fe9172cb0eeae86b39ec7a61ddc556656c8df08fd43ef6074296f32b347349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257","derivation_path":["010100000000000000","0700000000000000"]}],"signatures":null},{"type":"data","value":"a527a92a7488c010bc42b39d6b50f0822183e51efab228af8ca8ca81ca459237"}]}],"allow_additional_actions":false}`,
- respWant: &EstimateTxGasResp{
- TotalNeu: 2095 * consensus.VMGasRate,
+ path: "/estimate-transaction-gas",
+ tmplStr: `{"raw_transaction":"070100010160015e9a4e2bbae57dd71b6a827fb50aaeb744ce3ae6f45c4aec7494ad097213220e8affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0cea1bc5800011600144a6322008c5424251c7502c7d7d55f6389c3c358010001013dffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe086f29b3301160014fa61b0629e5f2da2bb8b08e7fc948dbd265234f700","signing_instructions":[{"position":0,"witness_components":[{"type":"raw_tx_signature","quorum":1,"keys":[{"xpub":"19204fe9172cb0eeae86b39ec7a61ddc556656c8df08fd43ef6074296f32b347349722316972e382c339b79b7e1d83a565c6b3e7cf46847733a47044ae493257","derivation_path":["010100000000000000","0700000000000000"]}],"signatures":null},{"type":"data","value":"a527a92a7488c010bc42b39d6b50f0822183e51efab228af8ca8ca81ca459237"}]}],"allow_additional_actions":false}`,
+ respWant: &EstimateTxGasResp{
+ TotalNeu: 2095 * consensus.VMGasRate,
},
},
{
- path: "/estimate-transaction-gas",
- tmplStr: `{"raw_transaction":"07010001016d016bcf24f1471d67c25a01ac84482ecdd8550229180171cae22321f87fe43d4f6a13ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8086a6d5f2020001220020713ef71e6087a58d6055ce81e8a8ea8a60ca19aef77923859e53a1fa9df0042989010240844b99bab9f393e89ca3bb272b1ba146852124f13a2d37fc47da6a7320f5ae1a4b6df1322750906ad480796db663e35ef7fd9544718eea08e51c5388f9813d0446ae20bd609e953918ab2ce120c43486894ff38dc4b65c2c1b4e19f6b41265d76b062120508684f922c1e5eea3dcbd592b00d297b2ddf92d35d5acabea9ff491ef514abe5152ad02014affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bef6b4cd0201220020dc794f041d19c67108a05d2a6d797a2b12029f31b2c91ec699c9477727f25315000149ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80fef9b123012200200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac6600","signing_instructions":[{"position":0,"witness_components":[{"type":"raw_tx_signature","quorum":1,"keys":[{"xpub":"5ff7f79f0fd4eb9ccb17191b0a1ac9bed5b4a03320a06d2ff8170dd51f9ad9089c4038ec7280b5eb6745ef3d36284e67f5cf2ed2a0177d462d24abf53c0399ed","derivationPath":["010200000000000000","0400000000000000"]},{"xpub":"d0e7607bec7f68ea9135fbb9e3e94ef05a034d28be847070740fcba9454a749f6e21942cfef90f1437184cb70775beb290c13852c1497631dbcb137f74788e4f","derivationPath":["010200000000000000","0400000000000000"]}],"signatures":["","844b99bab9f393e89ca3bb272b1ba146852124f13a2d37fc47da6a7320f5ae1a4b6df1322750906ad480796db663e35ef7fd9544718eea08e51c5388f9813d04"]},{"type":"data","value":"ae20bd609e953918ab2ce120c43486894ff38dc4b65c2c1b4e19f6b41265d76b062120508684f922c1e5eea3dcbd592b00d297b2ddf92d35d5acabea9ff491ef514abe5152ad"}]}],"allow_additional_actions":false}`,
- respWant: &EstimateTxGasResp{
- TotalNeu: 3305 * consensus.VMGasRate,
+ path: "/estimate-transaction-gas",
+ tmplStr: `{"raw_transaction":"07010001016d016bcf24f1471d67c25a01ac84482ecdd8550229180171cae22321f87fe43d4f6a13ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8086a6d5f2020001220020713ef71e6087a58d6055ce81e8a8ea8a60ca19aef77923859e53a1fa9df0042989010240844b99bab9f393e89ca3bb272b1ba146852124f13a2d37fc47da6a7320f5ae1a4b6df1322750906ad480796db663e35ef7fd9544718eea08e51c5388f9813d0446ae20bd609e953918ab2ce120c43486894ff38dc4b65c2c1b4e19f6b41265d76b062120508684f922c1e5eea3dcbd592b00d297b2ddf92d35d5acabea9ff491ef514abe5152ad02014affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80bef6b4cd0201220020dc794f041d19c67108a05d2a6d797a2b12029f31b2c91ec699c9477727f25315000149ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80fef9b123012200200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac6600","signing_instructions":[{"position":0,"witness_components":[{"type":"raw_tx_signature","quorum":1,"keys":[{"xpub":"5ff7f79f0fd4eb9ccb17191b0a1ac9bed5b4a03320a06d2ff8170dd51f9ad9089c4038ec7280b5eb6745ef3d36284e67f5cf2ed2a0177d462d24abf53c0399ed","derivationPath":["010200000000000000","0400000000000000"]},{"xpub":"d0e7607bec7f68ea9135fbb9e3e94ef05a034d28be847070740fcba9454a749f6e21942cfef90f1437184cb70775beb290c13852c1497631dbcb137f74788e4f","derivationPath":["010200000000000000","0400000000000000"]}],"signatures":["","844b99bab9f393e89ca3bb272b1ba146852124f13a2d37fc47da6a7320f5ae1a4b6df1322750906ad480796db663e35ef7fd9544718eea08e51c5388f9813d04"]},{"type":"data","value":"ae20bd609e953918ab2ce120c43486894ff38dc4b65c2c1b4e19f6b41265d76b062120508684f922c1e5eea3dcbd592b00d297b2ddf92d35d5acabea9ff491ef514abe5152ad"}]}],"allow_additional_actions":false}`,
+ respWant: &EstimateTxGasResp{
+ TotalNeu: 3305 * consensus.VMGasRate,
},
},
{
- path: "/estimate-transaction-gas",
- tmplStr: `{"raw_transaction":"07010002016c016acf24f1471d67c25a01ac84482ecdd8550229180171cae22321f87fe43d4f6a13ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80b4c4c32101012200200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac66ef020440f5baa1530bd7ded5c37f1c91360e28e736c91a7933eff961d68eebf90bdce63eb4361689759a8aa420256af565e38921985026de8d27dd7b66f0d01c90170a0440b23b44f62f3e97bcbd5f80cb9bb3d63cb154c62d402851e5b4d5d89849fef74271c8c38f594b944b75222d06ef18bddec4b6278ad3185f72ac5321ce5948e90940a00b096eef5b3bed5c6a2843d29e1820ef1413947d3e278c21cc70976c47976d1159468f071bf853b244be8f6cc55d78615ea6594c946f1a6e6622d8e9d42206a901ae20d441b6f375659325a04eede4fc3b74579bb08ccd05b41b99776501e22d6dca7320af6d98ca2c3cd10bf0affbfa6e86609b750523cfadb662ec963c164f05798a49209820b9f1553b03aaebe7e3f9e9222ed7db73b5079b18564042fd3b2cef74156a20271b52de5f554aa4a6f1358f1c2193617bfb3fed4546d13c4af773096a429f9420eeb4a78d8b5cb8283c221ca2d3fd96b8946b3cddee02b7ceffb8f605932588595355ad016c016a158f56c5673a52876bbbed4cd8724428b43a8d9ddd2a759c9df06b46898f101affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80fef9b12301012200200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac66ef020440c3c4fdbe99f9266a42df767cf03c22d9d09096446a8882b9d0c0076d9c85da28add31320705452fb566a091515cedb1ea9966647201236a0da13a020f848b8084043e22fe631cee95e3185ecd0c6fc4a262689d674725abe7d7f3158d8d43c776338edeec76600776fc0dcee280bd7a1a8a2b23909c6cefa7fbb55c27522b6100640fefe403941035a66ba9b6d097dfe0ada68ae6d006272928fad2ba23341fe878690e9e2fa1d2d3992c16aa20125fb2da7f7687920c12a36e4964533ceeccd3602a901ae20d441b6f375659325a04eede4fc3b74579bb08ccd05b41b99776501e22d6dca7320af6d98ca2c3cd10bf0affbfa6e86609b750523cfadb662ec963c164f05798a49209820b9f1553b03aaebe7e3f9e9222ed7db73b5079b18564042fd3b2cef74156a20271b52de5f554aa4a6f1358f1c2193617bfb3fed4546d13c4af773096a429f9420eeb4a78d8b5cb8283c221ca2d3fd96b8946b3cddee02b7ceffb8f605932588595355ad020149ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80ea8ed51f01220020036f3d1665dc802fd36aded656c2f4b2b2c5b00e86c44f5352257b718941a4e9000149ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80fef9b12301220020e402787b2bf9749f8fcdcc132a44e86bacf36780ec5df2189a11020d590533ee00","signing_instructions":[{"position":0,"witness_components":[{"type":"raw_tx_signature","quorum":3,"keys":[{"xpub":"5ff7f79f0fd4eb9ccb17191b0a1ac9bed5b4a03320a06d2ff8170dd51f9ad9089c4038ec7280b5eb6745ef3d36284e67f5cf2ed2a0177d462d24abf53c0399ed","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"7d1c7a9094ab23f432e60afbbfe2791ba9ab3daba8aaa544634218243b8659985cb0ae9fe2b0f5da8a84c6b117c9491bf38f5e59b0d05642d90ba34cf7611eec","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"b0d2d90cdee01976d51b55963ae214493708d8db44f7516d2d4853a542cba4c07fbd0ad3e7a9ff4b6fbe6b71e66f4538a9424eaf15f538d958aa7025f5f752dc","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"d0e7607bec7f68ea9135fbb9e3e94ef05a034d28be847070740fcba9454a749f6e21942cfef90f1437184cb70775beb290c13852c1497631dbcb137f74788e4f","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"e18b9d219e960d761e8d03290acddb5211fea1140c87663908ea74f212763ca8d809bb0fe861884e662429564fa0f2725b5787175054c17685a83a68e160344d","derivationPath":["010300000000000000","0100000000000000"]}],"signatures":["","f5baa1530bd7ded5c37f1c91360e28e736c91a7933eff961d68eebf90bdce63eb4361689759a8aa420256af565e38921985026de8d27dd7b66f0d01c90170a04","b23b44f62f3e97bcbd5f80cb9bb3d63cb154c62d402851e5b4d5d89849fef74271c8c38f594b944b75222d06ef18bddec4b6278ad3185f72ac5321ce5948e909","a00b096eef5b3bed5c6a2843d29e1820ef1413947d3e278c21cc70976c47976d1159468f071bf853b244be8f6cc55d78615ea6594c946f1a6e6622d8e9d42206",""]},{"type":"data","value":"ae20d441b6f375659325a04eede4fc3b74579bb08ccd05b41b99776501e22d6dca7320af6d98ca2c3cd10bf0affbfa6e86609b750523cfadb662ec963c164f05798a49209820b9f1553b03aaebe7e3f9e9222ed7db73b5079b18564042fd3b2cef74156a20271b52de5f554aa4a6f1358f1c2193617bfb3fed4546d13c4af773096a429f9420eeb4a78d8b5cb8283c221ca2d3fd96b8946b3cddee02b7ceffb8f605932588595355ad"}]},{"position":1,"witness_components":[{"type":"raw_tx_signature","quorum":3,"keys":[{"xpub":"5ff7f79f0fd4eb9ccb17191b0a1ac9bed5b4a03320a06d2ff8170dd51f9ad9089c4038ec7280b5eb6745ef3d36284e67f5cf2ed2a0177d462d24abf53c0399ed","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"7d1c7a9094ab23f432e60afbbfe2791ba9ab3daba8aaa544634218243b8659985cb0ae9fe2b0f5da8a84c6b117c9491bf38f5e59b0d05642d90ba34cf7611eec","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"b0d2d90cdee01976d51b55963ae214493708d8db44f7516d2d4853a542cba4c07fbd0ad3e7a9ff4b6fbe6b71e66f4538a9424eaf15f538d958aa7025f5f752dc","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"d0e7607bec7f68ea9135fbb9e3e94ef05a034d28be847070740fcba9454a749f6e21942cfef90f1437184cb70775beb290c13852c1497631dbcb137f74788e4f","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"e18b9d219e960d761e8d03290acddb5211fea1140c87663908ea74f212763ca8d809bb0fe861884e662429564fa0f2725b5787175054c17685a83a68e160344d","derivationPath":["010300000000000000","0100000000000000"]}],"signatures":["","c3c4fdbe99f9266a42df767cf03c22d9d09096446a8882b9d0c0076d9c85da28add31320705452fb566a091515cedb1ea9966647201236a0da13a020f848b808","43e22fe631cee95e3185ecd0c6fc4a262689d674725abe7d7f3158d8d43c776338edeec76600776fc0dcee280bd7a1a8a2b23909c6cefa7fbb55c27522b61006","fefe403941035a66ba9b6d097dfe0ada68ae6d006272928fad2ba23341fe878690e9e2fa1d2d3992c16aa20125fb2da7f7687920c12a36e4964533ceeccd3602",""]},{"type":"data","value":"ae20d441b6f375659325a04eede4fc3b74579bb08ccd05b41b99776501e22d6dca7320af6d98ca2c3cd10bf0affbfa6e86609b750523cfadb662ec963c164f05798a49209820b9f1553b03aaebe7e3f9e9222ed7db73b5079b18564042fd3b2cef74156a20271b52de5f554aa4a6f1358f1c2193617bfb3fed4546d13c4af773096a429f9420eeb4a78d8b5cb8283c221ca2d3fd96b8946b3cddee02b7ceffb8f605932588595355ad"}]}],"allow_additional_actions":false}`,
- respWant: &EstimateTxGasResp{
- TotalNeu: 13556 * consensus.VMGasRate,
+ path: "/estimate-transaction-gas",
+ tmplStr: `{"raw_transaction":"07010002016c016acf24f1471d67c25a01ac84482ecdd8550229180171cae22321f87fe43d4f6a13ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80b4c4c32101012200200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac66ef020440f5baa1530bd7ded5c37f1c91360e28e736c91a7933eff961d68eebf90bdce63eb4361689759a8aa420256af565e38921985026de8d27dd7b66f0d01c90170a0440b23b44f62f3e97bcbd5f80cb9bb3d63cb154c62d402851e5b4d5d89849fef74271c8c38f594b944b75222d06ef18bddec4b6278ad3185f72ac5321ce5948e90940a00b096eef5b3bed5c6a2843d29e1820ef1413947d3e278c21cc70976c47976d1159468f071bf853b244be8f6cc55d78615ea6594c946f1a6e6622d8e9d42206a901ae20d441b6f375659325a04eede4fc3b74579bb08ccd05b41b99776501e22d6dca7320af6d98ca2c3cd10bf0affbfa6e86609b750523cfadb662ec963c164f05798a49209820b9f1553b03aaebe7e3f9e9222ed7db73b5079b18564042fd3b2cef74156a20271b52de5f554aa4a6f1358f1c2193617bfb3fed4546d13c4af773096a429f9420eeb4a78d8b5cb8283c221ca2d3fd96b8946b3cddee02b7ceffb8f605932588595355ad016c016a158f56c5673a52876bbbed4cd8724428b43a8d9ddd2a759c9df06b46898f101affffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80fef9b12301012200200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac66ef020440c3c4fdbe99f9266a42df767cf03c22d9d09096446a8882b9d0c0076d9c85da28add31320705452fb566a091515cedb1ea9966647201236a0da13a020f848b8084043e22fe631cee95e3185ecd0c6fc4a262689d674725abe7d7f3158d8d43c776338edeec76600776fc0dcee280bd7a1a8a2b23909c6cefa7fbb55c27522b6100640fefe403941035a66ba9b6d097dfe0ada68ae6d006272928fad2ba23341fe878690e9e2fa1d2d3992c16aa20125fb2da7f7687920c12a36e4964533ceeccd3602a901ae20d441b6f375659325a04eede4fc3b74579bb08ccd05b41b99776501e22d6dca7320af6d98ca2c3cd10bf0affbfa6e86609b750523cfadb662ec963c164f05798a49209820b9f1553b03aaebe7e3f9e9222ed7db73b5079b18564042fd3b2cef74156a20271b52de5f554aa4a6f1358f1c2193617bfb3fed4546d13c4af773096a429f9420eeb4a78d8b5cb8283c221ca2d3fd96b8946b3cddee02b7ceffb8f605932588595355ad020149ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80ea8ed51f01220020036f3d1665dc802fd36aded656c2f4b2b2c5b00e86c44f5352257b718941a4e9000149ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80fef9b12301220020e402787b2bf9749f8fcdcc132a44e86bacf36780ec5df2189a11020d590533ee00","signing_instructions":[{"position":0,"witness_components":[{"type":"raw_tx_signature","quorum":3,"keys":[{"xpub":"5ff7f79f0fd4eb9ccb17191b0a1ac9bed5b4a03320a06d2ff8170dd51f9ad9089c4038ec7280b5eb6745ef3d36284e67f5cf2ed2a0177d462d24abf53c0399ed","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"7d1c7a9094ab23f432e60afbbfe2791ba9ab3daba8aaa544634218243b8659985cb0ae9fe2b0f5da8a84c6b117c9491bf38f5e59b0d05642d90ba34cf7611eec","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"b0d2d90cdee01976d51b55963ae214493708d8db44f7516d2d4853a542cba4c07fbd0ad3e7a9ff4b6fbe6b71e66f4538a9424eaf15f538d958aa7025f5f752dc","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"d0e7607bec7f68ea9135fbb9e3e94ef05a034d28be847070740fcba9454a749f6e21942cfef90f1437184cb70775beb290c13852c1497631dbcb137f74788e4f","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"e18b9d219e960d761e8d03290acddb5211fea1140c87663908ea74f212763ca8d809bb0fe861884e662429564fa0f2725b5787175054c17685a83a68e160344d","derivationPath":["010300000000000000","0100000000000000"]}],"signatures":["","f5baa1530bd7ded5c37f1c91360e28e736c91a7933eff961d68eebf90bdce63eb4361689759a8aa420256af565e38921985026de8d27dd7b66f0d01c90170a04","b23b44f62f3e97bcbd5f80cb9bb3d63cb154c62d402851e5b4d5d89849fef74271c8c38f594b944b75222d06ef18bddec4b6278ad3185f72ac5321ce5948e909","a00b096eef5b3bed5c6a2843d29e1820ef1413947d3e278c21cc70976c47976d1159468f071bf853b244be8f6cc55d78615ea6594c946f1a6e6622d8e9d42206",""]},{"type":"data","value":"ae20d441b6f375659325a04eede4fc3b74579bb08ccd05b41b99776501e22d6dca7320af6d98ca2c3cd10bf0affbfa6e86609b750523cfadb662ec963c164f05798a49209820b9f1553b03aaebe7e3f9e9222ed7db73b5079b18564042fd3b2cef74156a20271b52de5f554aa4a6f1358f1c2193617bfb3fed4546d13c4af773096a429f9420eeb4a78d8b5cb8283c221ca2d3fd96b8946b3cddee02b7ceffb8f605932588595355ad"}]},{"position":1,"witness_components":[{"type":"raw_tx_signature","quorum":3,"keys":[{"xpub":"5ff7f79f0fd4eb9ccb17191b0a1ac9bed5b4a03320a06d2ff8170dd51f9ad9089c4038ec7280b5eb6745ef3d36284e67f5cf2ed2a0177d462d24abf53c0399ed","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"7d1c7a9094ab23f432e60afbbfe2791ba9ab3daba8aaa544634218243b8659985cb0ae9fe2b0f5da8a84c6b117c9491bf38f5e59b0d05642d90ba34cf7611eec","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"b0d2d90cdee01976d51b55963ae214493708d8db44f7516d2d4853a542cba4c07fbd0ad3e7a9ff4b6fbe6b71e66f4538a9424eaf15f538d958aa7025f5f752dc","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"d0e7607bec7f68ea9135fbb9e3e94ef05a034d28be847070740fcba9454a749f6e21942cfef90f1437184cb70775beb290c13852c1497631dbcb137f74788e4f","derivationPath":["010300000000000000","0100000000000000"]},{"xpub":"e18b9d219e960d761e8d03290acddb5211fea1140c87663908ea74f212763ca8d809bb0fe861884e662429564fa0f2725b5787175054c17685a83a68e160344d","derivationPath":["010300000000000000","0100000000000000"]}],"signatures":["","c3c4fdbe99f9266a42df767cf03c22d9d09096446a8882b9d0c0076d9c85da28add31320705452fb566a091515cedb1ea9966647201236a0da13a020f848b808","43e22fe631cee95e3185ecd0c6fc4a262689d674725abe7d7f3158d8d43c776338edeec76600776fc0dcee280bd7a1a8a2b23909c6cefa7fbb55c27522b61006","fefe403941035a66ba9b6d097dfe0ada68ae6d006272928fad2ba23341fe878690e9e2fa1d2d3992c16aa20125fb2da7f7687920c12a36e4964533ceeccd3602",""]},{"type":"data","value":"ae20d441b6f375659325a04eede4fc3b74579bb08ccd05b41b99776501e22d6dca7320af6d98ca2c3cd10bf0affbfa6e86609b750523cfadb662ec963c164f05798a49209820b9f1553b03aaebe7e3f9e9222ed7db73b5079b18564042fd3b2cef74156a20271b52de5f554aa4a6f1358f1c2193617bfb3fed4546d13c4af773096a429f9420eeb4a78d8b5cb8283c221ca2d3fd96b8946b3cddee02b7ceffb8f605932588595355ad"}]}],"allow_additional_actions":false}`,
+ respWant: &EstimateTxGasResp{
+ TotalNeu: 13556 * consensus.VMGasRate,
},
},
}
Message string `json:"message"`
Password string `json:"password"`
}) Response {
- cp, err := a.wallet.AccountMgr.GetProgramByAddress(ins.Address)
+ cp, err := a.wallet.AccountMgr.GetLocalCtrlProgramByAddress(ins.Address)
if err != nil {
return NewErrorResponse(err)
}
IsMining bool `json:"is_mining"`
}) Response {
if in.IsMining {
+ if _, err := a.wallet.AccountMgr.GetMiningAddress(); err != nil {
+ return NewErrorResponse(errors.New("Mining address does not exist"))
+ }
return a.startMining()
}
return a.stopMining()
}
}
+// generateBlock generates a block template to mine
func (m *MiningPool) generateBlock() {
m.mutex.Lock()
defer m.mutex.Unlock()
func (n *Node) OnStart() error {
if n.miningEnable {
- n.cpuMiner.Start()
+ if _, err := n.wallet.AccountMgr.GetMiningAddress(); err != nil {
+ n.miningEnable = false
+ log.Error(err)
+ } else {
+ n.cpuMiner.Start()
+ }
}
if !n.config.VaultMode {
n.syncManager.Start()
+++ /dev/null
-mining
-======
-
-[![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)](https://travis-ci.org/btcsuite/btcd)
-[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
-[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcd/mining)
-
-## Overview
-
-This package is currently a work in progress.
-
-## Installation and Updating
-
-```bash
-$ go get -u github.com/btcsuite/btcd/mining
-```
-
-## License
-
-Package mining is licensed under the [copyfree](http://copyfree.org) ISC
-License.
+++ /dev/null
-cpuminer
-========
-
-[![Build Status](http://img.shields.io/travis/btcsuite/btcd.svg)](https://travis-ci.org/btcsuite/btcd)
-[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org)
-[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/btcsuite/btcd/mining/cpuminer)
-
-## Overview
-
-This package is currently a work in progress. It works without issue since it
-is used in several of the integration tests, but the API is not really ready for
-public consumption as it has simply been refactored out of the main codebase for
-now.
-
-## Installation and Updating
-
-```bash
-$ go get -u github.com/btcsuite/btcd/mining/cpuminer
-```
-
-## License
-
-Package cpuminer is licensed under the [copyfree](http://copyfree.org) ISC
-License.
+++ /dev/null
-// Copyright (c) 2014-2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package cpuminer
-
-import (
- "errors"
- "fmt"
- "math/rand"
- "runtime"
- "sync"
- "time"
-
- "github.com/btcsuite/btcd/blockchain"
- "github.com/btcsuite/btcd/chaincfg"
- "github.com/btcsuite/btcd/chaincfg/chainhash"
- "github.com/btcsuite/btcd/mining"
- "github.com/btcsuite/btcd/wire"
- "github.com/btcsuite/btcutil"
-)
-
-const (
- // maxNonce is the maximum value a nonce can be in a block header.
- maxNonce = ^uint32(0) // 2^32 - 1
-
- // maxExtraNonce is the maximum value an extra nonce used in a coinbase
- // transaction can be.
- maxExtraNonce = ^uint64(0) // 2^64 - 1
-
- // hpsUpdateSecs is the number of seconds to wait in between each
- // update to the hashes per second monitor.
- hpsUpdateSecs = 10
-
- // hashUpdateSec is the number of seconds each worker waits in between
- // notifying the speed monitor with how many hashes have been completed
- // while they are actively searching for a solution. This is done to
- // reduce the amount of syncs between the workers that must be done to
- // keep track of the hashes per second.
- hashUpdateSecs = 15
-)
-
-var (
- // defaultNumWorkers is the default number of workers to use for mining
- // and is based on the number of processor cores. This helps ensure the
- // system stays reasonably responsive under heavy load.
- defaultNumWorkers = uint32(runtime.NumCPU())
-)
-
-// Config is a descriptor containing the cpu miner configuration.
-type Config struct {
- // ChainParams identifies which chain parameters the cpu miner is
- // associated with.
- ChainParams *chaincfg.Params
-
- // BlockTemplateGenerator identifies the instance to use in order to
- // generate block templates that the miner will attempt to solve.
- BlockTemplateGenerator *mining.BlkTmplGenerator
-
- // MiningAddrs is a list of payment addresses to use for the generated
- // blocks. Each generated block will randomly choose one of them.
- MiningAddrs []btcutil.Address
-
- // ProcessBlock defines the function to call with any solved blocks.
- // It typically must run the provided block through the same set of
- // rules and handling as any other block coming from the network.
- ProcessBlock func(*btcutil.Block, blockchain.BehaviorFlags) (bool, error)
-
- // ConnectedCount defines the function to use to obtain how many other
- // peers the server is connected to. This is used by the automatic
- // persistent mining routine to determine whether or it should attempt
- // mining. This is useful because there is no point in mining when not
- // connected to any peers since there would no be anyone to send any
- // found blocks to.
- ConnectedCount func() int32
-
- // IsCurrent defines the function to use to obtain whether or not the
- // block chain is current. This is used by the automatic persistent
- // mining routine to determine whether or it should attempt mining.
- // This is useful because there is no point in mining if the chain is
- // not current since any solved blocks would be on a side chain and and
- // up orphaned anyways.
- IsCurrent func() bool
-}
-
-// CPUMiner provides facilities for solving blocks (mining) using the CPU in
-// a concurrency-safe manner. It consists of two main goroutines -- a speed
-// monitor and a controller for worker goroutines which generate and solve
-// blocks. The number of goroutines can be set via the SetMaxGoRoutines
-// function, but the default is based on the number of processor cores in the
-// system which is typically sufficient.
-type CPUMiner struct {
- sync.Mutex
- g *mining.BlkTmplGenerator
- cfg Config
- numWorkers uint32
- started bool
- discreteMining bool
- submitBlockLock sync.Mutex
- wg sync.WaitGroup
- workerWg sync.WaitGroup
- updateNumWorkers chan struct{}
- queryHashesPerSec chan float64
- updateHashes chan uint64
- speedMonitorQuit chan struct{}
- quit chan struct{}
-}
-
-// speedMonitor handles tracking the number of hashes per second the mining
-// process is performing. It must be run as a goroutine.
-func (m *CPUMiner) speedMonitor() {
- log.Tracef("CPU miner speed monitor started")
-
- var hashesPerSec float64
- var totalHashes uint64
- ticker := time.NewTicker(time.Second * hpsUpdateSecs)
- defer ticker.Stop()
-
-out:
- for {
- select {
- // Periodic updates from the workers with how many hashes they
- // have performed.
- case numHashes := <-m.updateHashes:
- totalHashes += numHashes
-
- // Time to update the hashes per second.
- case <-ticker.C:
- curHashesPerSec := float64(totalHashes) / hpsUpdateSecs
- if hashesPerSec == 0 {
- hashesPerSec = curHashesPerSec
- }
- hashesPerSec = (hashesPerSec + curHashesPerSec) / 2
- totalHashes = 0
- if hashesPerSec != 0 {
- log.Debugf("Hash speed: %6.0f kilohashes/s",
- hashesPerSec/1000)
- }
-
- // Request for the number of hashes per second.
- case m.queryHashesPerSec <- hashesPerSec:
- // Nothing to do.
-
- case <-m.speedMonitorQuit:
- break out
- }
- }
-
- m.wg.Done()
- log.Tracef("CPU miner speed monitor done")
-}
-
-// submitBlock submits the passed block to network after ensuring it passes all
-// of the consensus validation rules.
-func (m *CPUMiner) submitBlock(block *btcutil.Block) bool {
- m.submitBlockLock.Lock()
- defer m.submitBlockLock.Unlock()
-
- // Ensure the block is not stale since a new block could have shown up
- // while the solution was being found. Typically that condition is
- // detected and all work on the stale block is halted to start work on
- // a new block, but the check only happens periodically, so it is
- // possible a block was found and submitted in between.
- msgBlock := block.MsgBlock()
- if !msgBlock.Header.PrevBlock.IsEqual(&m.g.BestSnapshot().Hash) {
- log.Debugf("Block submitted via CPU miner with previous "+
- "block %s is stale", msgBlock.Header.PrevBlock)
- return false
- }
-
- // Process this block using the same rules as blocks coming from other
- // nodes. This will in turn relay it to the network like normal.
- isOrphan, err := m.cfg.ProcessBlock(block, blockchain.BFNone)
- if err != nil {
- // Anything other than a rule violation is an unexpected error,
- // so log that error as an internal error.
- if _, ok := err.(blockchain.RuleError); !ok {
- log.Errorf("Unexpected error while processing "+
- "block submitted via CPU miner: %v", err)
- return false
- }
-
- log.Debugf("Block submitted via CPU miner rejected: %v", err)
- return false
- }
- if isOrphan {
- log.Debugf("Block submitted via CPU miner is an orphan")
- return false
- }
-
- // The block was accepted.
- coinbaseTx := block.MsgBlock().Transactions[0].TxOut[0]
- log.Infof("Block submitted via CPU miner accepted (hash %s, "+
- "amount %v)", block.Hash(), btcutil.Amount(coinbaseTx.Value))
- return true
-}
-
-// solveBlock attempts to find some combination of a nonce, extra nonce, and
-// current timestamp which makes the passed block hash to a value less than the
-// target difficulty. The timestamp is updated periodically and the passed
-// block is modified with all tweaks during this process. This means that
-// when the function returns true, the block is ready for submission.
-//
-// This function will return early with false when conditions that trigger a
-// stale block such as a new block showing up or periodically when there are
-// new transactions and enough time has elapsed without finding a solution.
-func (m *CPUMiner) solveBlock(msgBlock *wire.MsgBlock, blockHeight int32,
- ticker *time.Ticker, quit chan struct{}) bool {
-
- // Choose a random extra nonce offset for this block template and
- // worker.
- enOffset, err := wire.RandomUint64()
- if err != nil {
- log.Errorf("Unexpected error while generating random "+
- "extra nonce offset: %v", err)
- enOffset = 0
- }
-
- // Create some convenience variables.
- header := &msgBlock.Header
- targetDifficulty := blockchain.CompactToBig(header.Bits)
-
- // Initial state.
- lastGenerated := time.Now()
- lastTxUpdate := m.g.TxSource().LastUpdated()
- hashesCompleted := uint64(0)
-
- // Note that the entire extra nonce range is iterated and the offset is
- // added relying on the fact that overflow will wrap around 0 as
- // provided by the Go spec.
- for extraNonce := uint64(0); extraNonce < maxExtraNonce; extraNonce++ {
- // Update the extra nonce in the block template with the
- // new value by regenerating the coinbase script and
- // setting the merkle root to the new value.
- m.g.UpdateExtraNonce(msgBlock, blockHeight, extraNonce+enOffset)
-
- // Search through the entire nonce range for a solution while
- // periodically checking for early quit and stale block
- // conditions along with updates to the speed monitor.
- for i := uint32(0); i <= maxNonce; i++ {
- select {
- case <-quit:
- return false
-
- case <-ticker.C:
- m.updateHashes <- hashesCompleted
- hashesCompleted = 0
-
- // The current block is stale if the best block
- // has changed.
- best := m.g.BestSnapshot()
- if !header.PrevBlock.IsEqual(&best.Hash) {
- return false
- }
-
- // The current block is stale if the memory pool
- // has been updated since the block template was
- // generated and it has been at least one
- // minute.
- if lastTxUpdate != m.g.TxSource().LastUpdated() &&
- time.Now().After(lastGenerated.Add(time.Minute)) {
-
- return false
- }
-
- m.g.UpdateBlockTime(msgBlock)
-
- default:
- // Non-blocking select to fall through
- }
-
- // Update the nonce and hash the block header. Each
- // hash is actually a double sha256 (two hashes), so
- // increment the number of hashes completed for each
- // attempt accordingly.
- header.Nonce = i
- hash := header.BlockHash()
- hashesCompleted += 2
-
- // The block is solved when the new block hash is less
- // than the target difficulty. Yay!
- if blockchain.HashToBig(&hash).Cmp(targetDifficulty) <= 0 {
- m.updateHashes <- hashesCompleted
- return true
- }
- }
- }
-
- return false
-}
-
-// generateBlocks is a worker that is controlled by the miningWorkerController.
-// It is self contained in that it creates block templates and attempts to solve
-// them while detecting when it is performing stale work and reacting
-// accordingly by generating a new block template. When a block is solved, it
-// is submitted.
-//
-// It must be run as a goroutine.
-func (m *CPUMiner) generateBlocks(quit chan struct{}) {
- log.Tracef("Starting generate blocks worker")
-
- // Start a ticker which is used to signal checks for stale work and
- // updates to the speed monitor.
- ticker := time.NewTicker(time.Second * hashUpdateSecs)
- defer ticker.Stop()
-out:
- for {
- // Quit when the miner is stopped.
- select {
- case <-quit:
- break out
- default:
- // Non-blocking select to fall through
- }
-
- // Wait until there is a connection to at least one other peer
- // since there is no way to relay a found block or receive
- // transactions to work on when there are no connected peers.
- if m.cfg.ConnectedCount() == 0 {
- time.Sleep(time.Second)
- continue
- }
-
- // No point in searching for a solution before the chain is
- // synced. Also, grab the same lock as used for block
- // submission, since the current block will be changing and
- // this would otherwise end up building a new block template on
- // a block that is in the process of becoming stale.
- m.submitBlockLock.Lock()
- curHeight := m.g.BestSnapshot().Height
- if curHeight != 0 && !m.cfg.IsCurrent() {
- m.submitBlockLock.Unlock()
- time.Sleep(time.Second)
- continue
- }
-
- // Choose a payment address at random.
- rand.Seed(time.Now().UnixNano())
- payToAddr := m.cfg.MiningAddrs[rand.Intn(len(m.cfg.MiningAddrs))]
-
- // Create a new block template using the available transactions
- // in the memory pool as a source of transactions to potentially
- // include in the block.
- template, err := m.g.NewBlockTemplate(payToAddr)
- m.submitBlockLock.Unlock()
- if err != nil {
- errStr := fmt.Sprintf("Failed to create new block "+
- "template: %v", err)
- log.Errorf(errStr)
- continue
- }
-
- // Attempt to solve the block. The function will exit early
- // with false when conditions that trigger a stale block, so
- // a new block template can be generated. When the return is
- // true a solution was found, so submit the solved block.
- if m.solveBlock(template.Block, curHeight+1, ticker, quit) {
- block := btcutil.NewBlock(template.Block)
- m.submitBlock(block)
- }
- }
-
- m.workerWg.Done()
- log.Tracef("Generate blocks worker done")
-}
-
-// miningWorkerController launches the worker goroutines that are used to
-// generate block templates and solve them. It also provides the ability to
-// dynamically adjust the number of running worker goroutines.
-//
-// It must be run as a goroutine.
-func (m *CPUMiner) miningWorkerController() {
- // launchWorkers groups common code to launch a specified number of
- // workers for generating blocks.
- var runningWorkers []chan struct{}
- launchWorkers := func(numWorkers uint32) {
- for i := uint32(0); i < numWorkers; i++ {
- quit := make(chan struct{})
- runningWorkers = append(runningWorkers, quit)
-
- m.workerWg.Add(1)
- go m.generateBlocks(quit)
- }
- }
-
- // Launch the current number of workers by default.
- runningWorkers = make([]chan struct{}, 0, m.numWorkers)
- launchWorkers(m.numWorkers)
-
-out:
- for {
- select {
- // Update the number of running workers.
- case <-m.updateNumWorkers:
- // No change.
- numRunning := uint32(len(runningWorkers))
- if m.numWorkers == numRunning {
- continue
- }
-
- // Add new workers.
- if m.numWorkers > numRunning {
- launchWorkers(m.numWorkers - numRunning)
- continue
- }
-
- // Signal the most recently created goroutines to exit.
- for i := numRunning - 1; i >= m.numWorkers; i-- {
- close(runningWorkers[i])
- runningWorkers[i] = nil
- runningWorkers = runningWorkers[:i]
- }
-
- case <-m.quit:
- for _, quit := range runningWorkers {
- close(quit)
- }
- break out
- }
- }
-
- // Wait until all workers shut down to stop the speed monitor since
- // they rely on being able to send updates to it.
- m.workerWg.Wait()
- close(m.speedMonitorQuit)
- m.wg.Done()
-}
-
-// Start begins the CPU mining process as well as the speed monitor used to
-// track hashing metrics. Calling this function when the CPU miner has
-// already been started will have no effect.
-//
-// This function is safe for concurrent access.
-func (m *CPUMiner) Start() {
- m.Lock()
- defer m.Unlock()
-
- // Nothing to do if the miner is already running or if running in
- // discrete mode (using GenerateNBlocks).
- if m.started || m.discreteMining {
- return
- }
-
- m.quit = make(chan struct{})
- m.speedMonitorQuit = make(chan struct{})
- m.wg.Add(2)
- go m.speedMonitor()
- go m.miningWorkerController()
-
- m.started = true
- log.Infof("CPU miner started")
-}
-
-// Stop gracefully stops the mining process by signalling all workers, and the
-// speed monitor to quit. Calling this function when the CPU miner has not
-// already been started will have no effect.
-//
-// This function is safe for concurrent access.
-func (m *CPUMiner) Stop() {
- m.Lock()
- defer m.Unlock()
-
- // Nothing to do if the miner is not currently running or if running in
- // discrete mode (using GenerateNBlocks).
- if !m.started || m.discreteMining {
- return
- }
-
- close(m.quit)
- m.wg.Wait()
- m.started = false
- log.Infof("CPU miner stopped")
-}
-
-// IsMining returns whether or not the CPU miner has been started and is
-// therefore currenting mining.
-//
-// This function is safe for concurrent access.
-func (m *CPUMiner) IsMining() bool {
- m.Lock()
- defer m.Unlock()
-
- return m.started
-}
-
-// HashesPerSecond returns the number of hashes per second the mining process
-// is performing. 0 is returned if the miner is not currently running.
-//
-// This function is safe for concurrent access.
-func (m *CPUMiner) HashesPerSecond() float64 {
- m.Lock()
- defer m.Unlock()
-
- // Nothing to do if the miner is not currently running.
- if !m.started {
- return 0
- }
-
- return <-m.queryHashesPerSec
-}
-
-// SetNumWorkers sets the number of workers to create which solve blocks. Any
-// negative values will cause a default number of workers to be used which is
-// based on the number of processor cores in the system. A value of 0 will
-// cause all CPU mining to be stopped.
-//
-// This function is safe for concurrent access.
-func (m *CPUMiner) SetNumWorkers(numWorkers int32) {
- if numWorkers == 0 {
- m.Stop()
- }
-
- // Don't lock until after the first check since Stop does its own
- // locking.
- m.Lock()
- defer m.Unlock()
-
- // Use default if provided value is negative.
- if numWorkers < 0 {
- m.numWorkers = defaultNumWorkers
- } else {
- m.numWorkers = uint32(numWorkers)
- }
-
- // When the miner is already running, notify the controller about the
- // the change.
- if m.started {
- m.updateNumWorkers <- struct{}{}
- }
-}
-
-// NumWorkers returns the number of workers which are running to solve blocks.
-//
-// This function is safe for concurrent access.
-func (m *CPUMiner) NumWorkers() int32 {
- m.Lock()
- defer m.Unlock()
-
- return int32(m.numWorkers)
-}
-
-// GenerateNBlocks generates the requested number of blocks. It is self
-// contained in that it creates block templates and attempts to solve them while
-// detecting when it is performing stale work and reacting accordingly by
-// generating a new block template. When a block is solved, it is submitted.
-// The function returns a list of the hashes of generated blocks.
-func (m *CPUMiner) GenerateNBlocks(n uint32) ([]*chainhash.Hash, error) {
- m.Lock()
-
- // Respond with an error if server is already mining.
- if m.started || m.discreteMining {
- m.Unlock()
- return nil, errors.New("Server is already CPU mining. Please call " +
- "`setgenerate 0` before calling discrete `generate` commands.")
- }
-
- m.started = true
- m.discreteMining = true
-
- m.speedMonitorQuit = make(chan struct{})
- m.wg.Add(1)
- go m.speedMonitor()
-
- m.Unlock()
-
- log.Tracef("Generating %d blocks", n)
-
- i := uint32(0)
- blockHashes := make([]*chainhash.Hash, n)
-
- // Start a ticker which is used to signal checks for stale work and
- // updates to the speed monitor.
- ticker := time.NewTicker(time.Second * hashUpdateSecs)
- defer ticker.Stop()
-
- for {
- // Read updateNumWorkers in case someone tries a `setgenerate` while
- // we're generating. We can ignore it as the `generate` RPC call only
- // uses 1 worker.
- select {
- case <-m.updateNumWorkers:
- default:
- }
-
- // Grab the lock used for block submission, since the current block will
- // be changing and this would otherwise end up building a new block
- // template on a block that is in the process of becoming stale.
- m.submitBlockLock.Lock()
- curHeight := m.g.BestSnapshot().Height
-
- // Choose a payment address at random.
- rand.Seed(time.Now().UnixNano())
- payToAddr := m.cfg.MiningAddrs[rand.Intn(len(m.cfg.MiningAddrs))]
-
- // Create a new block template using the available transactions
- // in the memory pool as a source of transactions to potentially
- // include in the block.
- template, err := m.g.NewBlockTemplate(payToAddr)
- m.submitBlockLock.Unlock()
- if err != nil {
- errStr := fmt.Sprintf("Failed to create new block "+
- "template: %v", err)
- log.Errorf(errStr)
- continue
- }
-
- // Attempt to solve the block. The function will exit early
- // with false when conditions that trigger a stale block, so
- // a new block template can be generated. When the return is
- // true a solution was found, so submit the solved block.
- if m.solveBlock(template.Block, curHeight+1, ticker, nil) {
- block := btcutil.NewBlock(template.Block)
- m.submitBlock(block)
- blockHashes[i] = block.Hash()
- i++
- if i == n {
- log.Tracef("Generated %d blocks", i)
- m.Lock()
- close(m.speedMonitorQuit)
- m.wg.Wait()
- m.started = false
- m.discreteMining = false
- m.Unlock()
- return blockHashes, nil
- }
- }
- }
-}
-
-// New returns a new instance of a CPU miner for the provided configuration.
-// Use Start to begin the mining process. See the documentation for CPUMiner
-// type for more details.
-func New(cfg *Config) *CPUMiner {
- return &CPUMiner{
- g: cfg.BlockTemplateGenerator,
- cfg: *cfg,
- numWorkers: defaultNumWorkers,
- updateNumWorkers: make(chan struct{}),
- queryHashesPerSec: make(chan float64),
- updateHashes: make(chan uint64),
- }
-}
+++ /dev/null
-// Copyright (c) 2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package cpuminer
-
-import (
- "github.com/btcsuite/btclog"
-)
-
-// log is a logger that is initialized with no output filters. This
-// means the package will not perform any logging by default until the caller
-// requests it.
-var log btclog.Logger
-
-// The default amount of logging is none.
-func init() {
- DisableLog()
-}
-
-// DisableLog disables all library log output. Logging output is disabled
-// by default until UseLogger is called.
-func DisableLog() {
- log = btclog.Disabled
-}
-
-// UseLogger uses a specified Logger to output package logging info.
-func UseLogger(logger btclog.Logger) {
- log = logger
-}
+++ /dev/null
-// Copyright (c) 2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package mining
-
-import (
- "github.com/btcsuite/btclog"
-)
-
-// log is a logger that is initialized with no output filters. This
-// means the package will not perform any logging by default until the caller
-// requests it.
-var log btclog.Logger
-
-// The default amount of logging is none.
-func init() {
- DisableLog()
-}
-
-// DisableLog disables all library log output. Logging output is disabled
-// by default until UseLogger is called.
-func DisableLog() {
- log = btclog.Disabled
-}
-
-// UseLogger uses a specified Logger to output package logging info.
-func UseLogger(logger btclog.Logger) {
- log = logger
-}
+++ /dev/null
-// Copyright (c) 2014-2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package mining
-
-import (
- "bytes"
- "container/heap"
- "fmt"
- "time"
-
- "github.com/btcsuite/btcd/blockchain"
- "github.com/btcsuite/btcd/chaincfg"
- "github.com/btcsuite/btcd/chaincfg/chainhash"
- "github.com/btcsuite/btcd/txscript"
- "github.com/btcsuite/btcd/wire"
- "github.com/btcsuite/btcutil"
-)
-
-const (
- // MinHighPriority is the minimum priority value that allows a
- // transaction to be considered high priority.
- MinHighPriority = btcutil.SatoshiPerBitcoin * 144.0 / 250
-
- // blockHeaderOverhead is the max number of bytes it takes to serialize
- // a block header and max possible transaction count.
- blockHeaderOverhead = wire.MaxBlockHeaderPayload + wire.MaxVarIntPayload
-
- // CoinbaseFlags is added to the coinbase script of a generated block
- // and is used to monitor BIP16 support as well as blocks that are
- // generated via btcd.
- CoinbaseFlags = "/P2SH/btcd/"
-)
-
-// TxDesc is a descriptor about a transaction in a transaction source along with
-// additional metadata.
-type TxDesc struct {
- // Tx is the transaction associated with the entry.
- Tx *btcutil.Tx
-
- // Added is the time when the entry was added to the source pool.
- Added time.Time
-
- // Height is the block height when the entry was added to the the source
- // pool.
- Height int32
-
- // Fee is the total fee the transaction associated with the entry pays.
- Fee int64
-
- // FeePerKB is the fee the transaction pays in Satoshi per 1000 bytes.
- FeePerKB int64
-}
-
-// TxSource represents a source of transactions to consider for inclusion in
-// new blocks.
-//
-// The interface contract requires that all of these methods are safe for
-// concurrent access with respect to the source.
-type TxSource interface {
- // LastUpdated returns the last time a transaction was added to or
- // removed from the source pool.
- LastUpdated() time.Time
-
- // MiningDescs returns a slice of mining descriptors for all the
- // transactions in the source pool.
- MiningDescs() []*TxDesc
-
- // HaveTransaction returns whether or not the passed transaction hash
- // exists in the source pool.
- HaveTransaction(hash *chainhash.Hash) bool
-}
-
-// txPrioItem houses a transaction along with extra information that allows the
-// transaction to be prioritized and track dependencies on other transactions
-// which have not been mined into a block yet.
-type txPrioItem struct {
- tx *btcutil.Tx
- fee int64
- priority float64
- feePerKB int64
-
- // dependsOn holds a map of transaction hashes which this one depends
- // on. It will only be set when the transaction references other
- // transactions in the source pool and hence must come after them in
- // a block.
- dependsOn map[chainhash.Hash]struct{}
-}
-
-// txPriorityQueueLessFunc describes a function that can be used as a compare
-// function for a transaction priority queue (txPriorityQueue).
-type txPriorityQueueLessFunc func(*txPriorityQueue, int, int) bool
-
-// txPriorityQueue implements a priority queue of txPrioItem elements that
-// supports an arbitrary compare function as defined by txPriorityQueueLessFunc.
-type txPriorityQueue struct {
- lessFunc txPriorityQueueLessFunc
- items []*txPrioItem
-}
-
-// Len returns the number of items in the priority queue. It is part of the
-// heap.Interface implementation.
-func (pq *txPriorityQueue) Len() int {
- return len(pq.items)
-}
-
-// Less returns whether the item in the priority queue with index i should sort
-// before the item with index j by deferring to the assigned less function. It
-// is part of the heap.Interface implementation.
-func (pq *txPriorityQueue) Less(i, j int) bool {
- return pq.lessFunc(pq, i, j)
-}
-
-// Swap swaps the items at the passed indices in the priority queue. It is
-// part of the heap.Interface implementation.
-func (pq *txPriorityQueue) Swap(i, j int) {
- pq.items[i], pq.items[j] = pq.items[j], pq.items[i]
-}
-
-// Push pushes the passed item onto the priority queue. It is part of the
-// heap.Interface implementation.
-func (pq *txPriorityQueue) Push(x interface{}) {
- pq.items = append(pq.items, x.(*txPrioItem))
-}
-
-// Pop removes the highest priority item (according to Less) from the priority
-// queue and returns it. It is part of the heap.Interface implementation.
-func (pq *txPriorityQueue) Pop() interface{} {
- n := len(pq.items)
- item := pq.items[n-1]
- pq.items[n-1] = nil
- pq.items = pq.items[0 : n-1]
- return item
-}
-
-// SetLessFunc sets the compare function for the priority queue to the provided
-// function. It also invokes heap.Init on the priority queue using the new
-// function so it can immediately be used with heap.Push/Pop.
-func (pq *txPriorityQueue) SetLessFunc(lessFunc txPriorityQueueLessFunc) {
- pq.lessFunc = lessFunc
- heap.Init(pq)
-}
-
-// txPQByPriority sorts a txPriorityQueue by transaction priority and then fees
-// per kilobyte.
-func txPQByPriority(pq *txPriorityQueue, i, j int) bool {
- // Using > here so that pop gives the highest priority item as opposed
- // to the lowest. Sort by priority first, then fee.
- if pq.items[i].priority == pq.items[j].priority {
- return pq.items[i].feePerKB > pq.items[j].feePerKB
- }
- return pq.items[i].priority > pq.items[j].priority
-
-}
-
-// txPQByFee sorts a txPriorityQueue by fees per kilobyte and then transaction
-// priority.
-func txPQByFee(pq *txPriorityQueue, i, j int) bool {
- // Using > here so that pop gives the highest fee item as opposed
- // to the lowest. Sort by fee first, then priority.
- if pq.items[i].feePerKB == pq.items[j].feePerKB {
- return pq.items[i].priority > pq.items[j].priority
- }
- return pq.items[i].feePerKB > pq.items[j].feePerKB
-}
-
-// newTxPriorityQueue returns a new transaction priority queue that reserves the
-// passed amount of space for the elements. The new priority queue uses either
-// the txPQByPriority or the txPQByFee compare function depending on the
-// sortByFee parameter and is already initialized for use with heap.Push/Pop.
-// The priority queue can grow larger than the reserved space, but extra copies
-// of the underlying array can be avoided by reserving a sane value.
-func newTxPriorityQueue(reserve int, sortByFee bool) *txPriorityQueue {
- pq := &txPriorityQueue{
- items: make([]*txPrioItem, 0, reserve),
- }
- if sortByFee {
- pq.SetLessFunc(txPQByFee)
- } else {
- pq.SetLessFunc(txPQByPriority)
- }
- return pq
-}
-
-// BlockTemplate houses a block that has yet to be solved along with additional
-// details about the fees and the number of signature operations for each
-// transaction in the block.
-type BlockTemplate struct {
- // Block is a block that is ready to be solved by miners. Thus, it is
- // completely valid with the exception of satisfying the proof-of-work
- // requirement.
- Block *wire.MsgBlock
-
- // Fees contains the amount of fees each transaction in the generated
- // template pays in base units. Since the first transaction is the
- // coinbase, the first entry (offset 0) will contain the negative of the
- // sum of the fees of all other transactions.
- Fees []int64
-
- // SigOpCosts contains the number of signature operations each
- // transaction in the generated template performs.
- SigOpCosts []int64
-
- // Height is the height at which the block template connects to the main
- // chain.
- Height int32
-
- // ValidPayAddress indicates whether or not the template coinbase pays
- // to an address or is redeemable by anyone. See the documentation on
- // NewBlockTemplate for details on which this can be useful to generate
- // templates without a coinbase payment address.
- ValidPayAddress bool
-
- // WitnessCommitment is a commitment to the witness data (if any)
- // within the block. This field will only be populted once segregated
- // witness has been activated, and the block contains a transaction
- // which has witness data.
- WitnessCommitment []byte
-}
-
-// mergeUtxoView adds all of the entries in view to viewA. The result is that
-// viewA will contain all of its original entries plus all of the entries
-// in viewB. It will replace any entries in viewB which also exist in viewA
-// if the entry in viewA is fully spent.
-func mergeUtxoView(viewA *blockchain.UtxoViewpoint, viewB *blockchain.UtxoViewpoint) {
- viewAEntries := viewA.Entries()
- for hash, entryB := range viewB.Entries() {
- if entryA, exists := viewAEntries[hash]; !exists ||
- entryA == nil || entryA.IsFullySpent() {
-
- viewAEntries[hash] = entryB
- }
- }
-}
-
-// standardCoinbaseScript returns a standard script suitable for use as the
-// signature script of the coinbase transaction of a new block. In particular,
-// it starts with the block height that is required by version 2 blocks and adds
-// the extra nonce as well as additional coinbase flags.
-func standardCoinbaseScript(nextBlockHeight int32, extraNonce uint64) ([]byte, error) {
- return txscript.NewScriptBuilder().AddInt64(int64(nextBlockHeight)).
- AddInt64(int64(extraNonce)).AddData([]byte(CoinbaseFlags)).
- Script()
-}
-
-// createCoinbaseTx returns a coinbase transaction paying an appropriate subsidy
-// based on the passed block height to the provided address. When the address
-// is nil, the coinbase transaction will instead be redeemable by anyone.
-//
-// See the comment for NewBlockTemplate for more information about why the nil
-// address handling is useful.
-func createCoinbaseTx(params *chaincfg.Params, coinbaseScript []byte, nextBlockHeight int32, addr btcutil.Address) (*btcutil.Tx, error) {
- // Create the script to pay to the provided payment address if one was
- // specified. Otherwise create a script that allows the coinbase to be
- // redeemable by anyone.
- var pkScript []byte
- if addr != nil {
- var err error
- pkScript, err = txscript.PayToAddrScript(addr)
- if err != nil {
- return nil, err
- }
- } else {
- var err error
- scriptBuilder := txscript.NewScriptBuilder()
- pkScript, err = scriptBuilder.AddOp(txscript.OP_TRUE).Script()
- if err != nil {
- return nil, err
- }
- }
-
- tx := wire.NewMsgTx(wire.TxVersion)
- tx.AddTxIn(&wire.TxIn{
- // Coinbase transactions have no inputs, so previous outpoint is
- // zero hash and max index.
- PreviousOutPoint: *wire.NewOutPoint(&chainhash.Hash{},
- wire.MaxPrevOutIndex),
- SignatureScript: coinbaseScript,
- Sequence: wire.MaxTxInSequenceNum,
- })
- tx.AddTxOut(&wire.TxOut{
- Value: blockchain.CalcBlockSubsidy(nextBlockHeight, params),
- PkScript: pkScript,
- })
- return btcutil.NewTx(tx), nil
-}
-
-// spendTransaction updates the passed view by marking the inputs to the passed
-// transaction as spent. It also adds all outputs in the passed transaction
-// which are not provably unspendable as available unspent transaction outputs.
-func spendTransaction(utxoView *blockchain.UtxoViewpoint, tx *btcutil.Tx, height int32) error {
- for _, txIn := range tx.MsgTx().TxIn {
- originHash := &txIn.PreviousOutPoint.Hash
- originIndex := txIn.PreviousOutPoint.Index
- entry := utxoView.LookupEntry(originHash)
- if entry != nil {
- entry.SpendOutput(originIndex)
- }
- }
-
- utxoView.AddTxOuts(tx, height)
- return nil
-}
-
-// logSkippedDeps logs any dependencies which are also skipped as a result of
-// skipping a transaction while generating a block template at the trace level.
-func logSkippedDeps(tx *btcutil.Tx, deps map[chainhash.Hash]*txPrioItem) {
- if deps == nil {
- return
- }
-
- for _, item := range deps {
- log.Tracef("Skipping tx %s since it depends on %s\n",
- item.tx.Hash(), tx.Hash())
- }
-}
-
-// MinimumMedianTime returns the minimum allowed timestamp for a block building
-// on the end of the provided best chain. In particular, it is one second after
-// the median timestamp of the last several blocks per the chain consensus
-// rules.
-func MinimumMedianTime(chainState *blockchain.BestState) time.Time {
- return chainState.MedianTime.Add(time.Second)
-}
-
-// medianAdjustedTime returns the current time adjusted to ensure it is at least
-// one second after the median timestamp of the last several blocks per the
-// chain consensus rules.
-func medianAdjustedTime(chainState *blockchain.BestState, timeSource blockchain.MedianTimeSource) time.Time {
- // The timestamp for the block must not be before the median timestamp
- // of the last several blocks. Thus, choose the maximum between the
- // current time and one second after the past median time. The current
- // timestamp is truncated to a second boundary before comparison since a
- // block timestamp does not supported a precision greater than one
- // second.
- newTimestamp := timeSource.AdjustedTime()
- minTimestamp := MinimumMedianTime(chainState)
- if newTimestamp.Before(minTimestamp) {
- newTimestamp = minTimestamp
- }
-
- return newTimestamp
-}
-
-// BlkTmplGenerator provides a type that can be used to generate block templates
-// based on a given mining policy and source of transactions to choose from.
-// It also houses additional state required in order to ensure the templates
-// are built on top of the current best chain and adhere to the consensus rules.
-type BlkTmplGenerator struct {
- policy *Policy
- chainParams *chaincfg.Params
- txSource TxSource
- chain *blockchain.BlockChain
- timeSource blockchain.MedianTimeSource
- sigCache *txscript.SigCache
- hashCache *txscript.HashCache
-}
-
-// NewBlkTmplGenerator returns a new block template generator for the given
-// policy using transactions from the provided transaction source.
-//
-// The additional state-related fields are required in order to ensure the
-// templates are built on top of the current best chain and adhere to the
-// consensus rules.
-func NewBlkTmplGenerator(policy *Policy, params *chaincfg.Params,
- txSource TxSource, chain *blockchain.BlockChain,
- timeSource blockchain.MedianTimeSource,
- sigCache *txscript.SigCache,
- hashCache *txscript.HashCache) *BlkTmplGenerator {
-
- return &BlkTmplGenerator{
- policy: policy,
- chainParams: params,
- txSource: txSource,
- chain: chain,
- timeSource: timeSource,
- sigCache: sigCache,
- hashCache: hashCache,
- }
-}
-
-// NewBlockTemplate returns a new block template that is ready to be solved
-// using the transactions from the passed transaction source pool and a coinbase
-// that either pays to the passed address if it is not nil, or a coinbase that
-// is redeemable by anyone if the passed address is nil. The nil address
-// functionality is useful since there are cases such as the getblocktemplate
-// RPC where external mining software is responsible for creating their own
-// coinbase which will replace the one generated for the block template. Thus
-// the need to have configured address can be avoided.
-//
-// The transactions selected and included are prioritized according to several
-// factors. First, each transaction has a priority calculated based on its
-// value, age of inputs, and size. Transactions which consist of larger
-// amounts, older inputs, and small sizes have the highest priority. Second, a
-// fee per kilobyte is calculated for each transaction. Transactions with a
-// higher fee per kilobyte are preferred. Finally, the block generation related
-// policy settings are all taken into account.
-//
-// Transactions which only spend outputs from other transactions already in the
-// block chain are immediately added to a priority queue which either
-// prioritizes based on the priority (then fee per kilobyte) or the fee per
-// kilobyte (then priority) depending on whether or not the BlockPrioritySize
-// policy setting allots space for high-priority transactions. Transactions
-// which spend outputs from other transactions in the source pool are added to a
-// dependency map so they can be added to the priority queue once the
-// transactions they depend on have been included.
-//
-// Once the high-priority area (if configured) has been filled with
-// transactions, or the priority falls below what is considered high-priority,
-// the priority queue is updated to prioritize by fees per kilobyte (then
-// priority).
-//
-// When the fees per kilobyte drop below the TxMinFreeFee policy setting, the
-// transaction will be skipped unless the BlockMinSize policy setting is
-// nonzero, in which case the block will be filled with the low-fee/free
-// transactions until the block size reaches that minimum size.
-//
-// Any transactions which would cause the block to exceed the BlockMaxSize
-// policy setting, exceed the maximum allowed signature operations per block, or
-// otherwise cause the block to be invalid are skipped.
-//
-// Given the above, a block generated by this function is of the following form:
-//
-// ----------------------------------- -- --
-// | Coinbase Transaction | | |
-// |-----------------------------------| | |
-// | | | | ----- policy.BlockPrioritySize
-// | High-priority Transactions | | |
-// | | | |
-// |-----------------------------------| | --
-// | | |
-// | | |
-// | | |--- policy.BlockMaxSize
-// | Transactions prioritized by fee | |
-// | until <= policy.TxMinFreeFee | |
-// | | |
-// | | |
-// | | |
-// |-----------------------------------| |
-// | Low-fee/Non high-priority (free) | |
-// | transactions (while block size | |
-// | <= policy.BlockMinSize) | |
-// ----------------------------------- --
-func (g *BlkTmplGenerator) NewBlockTemplate(payToAddress btcutil.Address) (*BlockTemplate, error) {
- // Extend the most recently known best block.
- best := g.chain.BestSnapshot()
- nextBlockHeight := best.Height + 1
-
- // Create a standard coinbase transaction paying to the provided
- // address. NOTE: The coinbase value will be updated to include the
- // fees from the selected transactions later after they have actually
- // been selected. It is created here to detect any errors early
- // before potentially doing a lot of work below. The extra nonce helps
- // ensure the transaction is not a duplicate transaction (paying the
- // same value to the same public key address would otherwise be an
- // identical transaction for block version 1).
- extraNonce := uint64(0)
- coinbaseScript, err := standardCoinbaseScript(nextBlockHeight, extraNonce)
- if err != nil {
- return nil, err
- }
- coinbaseTx, err := createCoinbaseTx(g.chainParams, coinbaseScript,
- nextBlockHeight, payToAddress)
- if err != nil {
- return nil, err
- }
- coinbaseSigOpCost := int64(blockchain.CountSigOps(coinbaseTx)) * blockchain.WitnessScaleFactor
-
- // Get the current source transactions and create a priority queue to
- // hold the transactions which are ready for inclusion into a block
- // along with some priority related and fee metadata. Reserve the same
- // number of items that are available for the priority queue. Also,
- // choose the initial sort order for the priority queue based on whether
- // or not there is an area allocated for high-priority transactions.
- sourceTxns := g.txSource.MiningDescs()
- sortedByFee := g.policy.BlockPrioritySize == 0
- priorityQueue := newTxPriorityQueue(len(sourceTxns), sortedByFee)
-
- // Create a slice to hold the transactions to be included in the
- // generated block with reserved space. Also create a utxo view to
- // house all of the input transactions so multiple lookups can be
- // avoided.
- blockTxns := make([]*btcutil.Tx, 0, len(sourceTxns))
- blockTxns = append(blockTxns, coinbaseTx)
- blockUtxos := blockchain.NewUtxoViewpoint()
-
- // dependers is used to track transactions which depend on another
- // transaction in the source pool. This, in conjunction with the
- // dependsOn map kept with each dependent transaction helps quickly
- // determine which dependent transactions are now eligible for inclusion
- // in the block once each transaction has been included.
- dependers := make(map[chainhash.Hash]map[chainhash.Hash]*txPrioItem)
-
- // Create slices to hold the fees and number of signature operations
- // for each of the selected transactions and add an entry for the
- // coinbase. This allows the code below to simply append details about
- // a transaction as it is selected for inclusion in the final block.
- // However, since the total fees aren't known yet, use a dummy value for
- // the coinbase fee which will be updated later.
- txFees := make([]int64, 0, len(sourceTxns))
- txSigOpCosts := make([]int64, 0, len(sourceTxns))
- txFees = append(txFees, -1) // Updated once known
- txSigOpCosts = append(txSigOpCosts, coinbaseSigOpCost)
-
- log.Debugf("Considering %d transactions for inclusion to new block",
- len(sourceTxns))
-
-mempoolLoop:
- for _, txDesc := range sourceTxns {
- // A block can't have more than one coinbase or contain
- // non-finalized transactions.
- tx := txDesc.Tx
- if blockchain.IsCoinBase(tx) {
- log.Tracef("Skipping coinbase tx %s", tx.Hash())
- continue
- }
- if !blockchain.IsFinalizedTransaction(tx, nextBlockHeight,
- g.timeSource.AdjustedTime()) {
-
- log.Tracef("Skipping non-finalized tx %s", tx.Hash())
- continue
- }
-
- // Fetch all of the utxos referenced by the this transaction.
- // NOTE: This intentionally does not fetch inputs from the
- // mempool since a transaction which depends on other
- // transactions in the mempool must come after those
- // dependencies in the final generated block.
- utxos, err := g.chain.FetchUtxoView(tx)
- if err != nil {
- log.Warnf("Unable to fetch utxo view for tx %s: %v",
- tx.Hash(), err)
- continue
- }
-
- // Setup dependencies for any transactions which reference
- // other transactions in the mempool so they can be properly
- // ordered below.
- prioItem := &txPrioItem{tx: tx}
- for _, txIn := range tx.MsgTx().TxIn {
- originHash := &txIn.PreviousOutPoint.Hash
- originIndex := txIn.PreviousOutPoint.Index
- utxoEntry := utxos.LookupEntry(originHash)
- if utxoEntry == nil || utxoEntry.IsOutputSpent(originIndex) {
- if !g.txSource.HaveTransaction(originHash) {
- log.Tracef("Skipping tx %s because it "+
- "references unspent output %s "+
- "which is not available",
- tx.Hash(), txIn.PreviousOutPoint)
- continue mempoolLoop
- }
-
- // The transaction is referencing another
- // transaction in the source pool, so setup an
- // ordering dependency.
- deps, exists := dependers[*originHash]
- if !exists {
- deps = make(map[chainhash.Hash]*txPrioItem)
- dependers[*originHash] = deps
- }
- deps[*prioItem.tx.Hash()] = prioItem
- if prioItem.dependsOn == nil {
- prioItem.dependsOn = make(
- map[chainhash.Hash]struct{})
- }
- prioItem.dependsOn[*originHash] = struct{}{}
-
- // Skip the check below. We already know the
- // referenced transaction is available.
- continue
- }
- }
-
- // Calculate the final transaction priority using the input
- // value age sum as well as the adjusted transaction size. The
- // formula is: sum(inputValue * inputAge) / adjustedTxSize
- prioItem.priority = CalcPriority(tx.MsgTx(), utxos,
- nextBlockHeight)
-
- // Calculate the fee in Satoshi/kB.
- prioItem.feePerKB = txDesc.FeePerKB
- prioItem.fee = txDesc.Fee
-
- // Add the transaction to the priority queue to mark it ready
- // for inclusion in the block unless it has dependencies.
- if prioItem.dependsOn == nil {
- heap.Push(priorityQueue, prioItem)
- }
-
- // Merge the referenced outputs from the input transactions to
- // this transaction into the block utxo view. This allows the
- // code below to avoid a second lookup.
- mergeUtxoView(blockUtxos, utxos)
- }
-
- log.Tracef("Priority queue len %d, dependers len %d",
- priorityQueue.Len(), len(dependers))
-
- // The starting block size is the size of the block header plus the max
- // possible transaction count size, plus the size of the coinbase
- // transaction.
- blockWeight := uint32((blockHeaderOverhead * blockchain.WitnessScaleFactor) +
- blockchain.GetTransactionWeight(coinbaseTx))
- blockSigOpCost := coinbaseSigOpCost
- totalFees := int64(0)
-
- // Query the version bits state to see if segwit has been activated, if
- // so then this means that we'll include any transactions with witness
- // data in the mempool, and also add the witness commitment as an
- // OP_RETURN output in the coinbase transaction.
- segwitState, err := g.chain.ThresholdState(chaincfg.DeploymentSegwit)
- if err != nil {
- return nil, err
- }
- segwitActive := segwitState == blockchain.ThresholdActive
-
- witnessIncluded := false
-
- // Choose which transactions make it into the block.
- for priorityQueue.Len() > 0 {
- // Grab the highest priority (or highest fee per kilobyte
- // depending on the sort order) transaction.
- prioItem := heap.Pop(priorityQueue).(*txPrioItem)
- tx := prioItem.tx
-
- switch {
- // If segregated witness has not been activated yet, then we
- // shouldn't include any witness transactions in the block.
- case !segwitActive && tx.HasWitness():
- continue
-
- // Otherwise, Keep track of if we've included a transaction
- // with witness data or not. If so, then we'll need to include
- // the witness commitment as the last output in the coinbase
- // transaction.
- case segwitActive && !witnessIncluded && tx.HasWitness():
- // If we're about to include a transaction bearing
- // witness data, then we'll also need to include a
- // witness commitment in the coinbase transaction.
- // Therefore, we account for the additional weight
- // within the block with a model coinbase tx with a
- // witness commitment.
- coinbaseCopy := btcutil.NewTx(coinbaseTx.MsgTx().Copy())
- coinbaseCopy.MsgTx().TxIn[0].Witness = [][]byte{
- bytes.Repeat([]byte("a"),
- blockchain.CoinbaseWitnessDataLen),
- }
- coinbaseCopy.MsgTx().AddTxOut(&wire.TxOut{
- PkScript: bytes.Repeat([]byte("a"),
- blockchain.CoinbaseWitnessPkScriptLength),
- })
-
- // In order to accurately account for the weight
- // addition due to this coinbase transaction, we'll add
- // the difference of the transaction before and after
- // the addition of the commitment to the block weight.
- weightDiff := blockchain.GetTransactionWeight(coinbaseCopy) -
- blockchain.GetTransactionWeight(coinbaseTx)
-
- blockWeight += uint32(weightDiff)
-
- witnessIncluded = true
- }
-
- // Grab any transactions which depend on this one.
- deps := dependers[*tx.Hash()]
-
- // Enforce maximum block size. Also check for overflow.
- txWeight := uint32(blockchain.GetTransactionWeight(tx))
- blockPlusTxWeight := blockWeight + txWeight
- if blockPlusTxWeight < blockWeight ||
- blockPlusTxWeight >= g.policy.BlockMaxWeight {
-
- log.Tracef("Skipping tx %s because it would exceed "+
- "the max block weight", tx.Hash())
- logSkippedDeps(tx, deps)
- continue
- }
-
- // Enforce maximum signature operation cost per block. Also
- // check for overflow.
- sigOpCost, err := blockchain.GetSigOpCost(tx, false,
- blockUtxos, true, segwitActive)
- if err != nil {
- log.Tracef("Skipping tx %s due to error in "+
- "GetSigOpCost: %v", tx.Hash(), err)
- logSkippedDeps(tx, deps)
- continue
- }
- if blockSigOpCost+int64(sigOpCost) < blockSigOpCost ||
- blockSigOpCost+int64(sigOpCost) > blockchain.MaxBlockSigOpsCost {
- log.Tracef("Skipping tx %s because it would "+
- "exceed the maximum sigops per block", tx.Hash())
- logSkippedDeps(tx, deps)
- continue
- }
-
- // Skip free transactions once the block is larger than the
- // minimum block size.
- if sortedByFee &&
- prioItem.feePerKB < int64(g.policy.TxMinFreeFee) &&
- blockPlusTxWeight >= g.policy.BlockMinWeight {
-
- log.Tracef("Skipping tx %s with feePerKB %d "+
- "< TxMinFreeFee %d and block weight %d >= "+
- "minBlockWeight %d", tx.Hash(), prioItem.feePerKB,
- g.policy.TxMinFreeFee, blockPlusTxWeight,
- g.policy.BlockMinWeight)
- logSkippedDeps(tx, deps)
- continue
- }
-
- // Prioritize by fee per kilobyte once the block is larger than
- // the priority size or there are no more high-priority
- // transactions.
- if !sortedByFee && (blockPlusTxWeight >= g.policy.BlockPrioritySize ||
- prioItem.priority <= MinHighPriority) {
-
- log.Tracef("Switching to sort by fees per "+
- "kilobyte blockSize %d >= BlockPrioritySize "+
- "%d || priority %.2f <= minHighPriority %.2f",
- blockPlusTxWeight, g.policy.BlockPrioritySize,
- prioItem.priority, MinHighPriority)
-
- sortedByFee = true
- priorityQueue.SetLessFunc(txPQByFee)
-
- // Put the transaction back into the priority queue and
- // skip it so it is re-priortized by fees if it won't
- // fit into the high-priority section or the priority
- // is too low. Otherwise this transaction will be the
- // final one in the high-priority section, so just fall
- // though to the code below so it is added now.
- if blockPlusTxWeight > g.policy.BlockPrioritySize ||
- prioItem.priority < MinHighPriority {
-
- heap.Push(priorityQueue, prioItem)
- continue
- }
- }
-
- // Ensure the transaction inputs pass all of the necessary
- // preconditions before allowing it to be added to the block.
- _, err = blockchain.CheckTransactionInputs(tx, nextBlockHeight,
- blockUtxos, g.chainParams)
- if err != nil {
- log.Tracef("Skipping tx %s due to error in "+
- "CheckTransactionInputs: %v", tx.Hash(), err)
- logSkippedDeps(tx, deps)
- continue
- }
- err = blockchain.ValidateTransactionScripts(tx, blockUtxos,
- txscript.StandardVerifyFlags, g.sigCache,
- g.hashCache)
- if err != nil {
- log.Tracef("Skipping tx %s due to error in "+
- "ValidateTransactionScripts: %v", tx.Hash(), err)
- logSkippedDeps(tx, deps)
- continue
- }
-
- // Spend the transaction inputs in the block utxo view and add
- // an entry for it to ensure any transactions which reference
- // this one have it available as an input and can ensure they
- // aren't double spending.
- spendTransaction(blockUtxos, tx, nextBlockHeight)
-
- // Add the transaction to the block, increment counters, and
- // save the fees and signature operation counts to the block
- // template.
- blockTxns = append(blockTxns, tx)
- blockWeight += txWeight
- blockSigOpCost += int64(sigOpCost)
- totalFees += prioItem.fee
- txFees = append(txFees, prioItem.fee)
- txSigOpCosts = append(txSigOpCosts, int64(sigOpCost))
-
- log.Tracef("Adding tx %s (priority %.2f, feePerKB %.2f)",
- prioItem.tx.Hash(), prioItem.priority, prioItem.feePerKB)
-
- // Add transactions which depend on this one (and also do not
- // have any other unsatisified dependencies) to the priority
- // queue.
- for _, item := range deps {
- // Add the transaction to the priority queue if there
- // are no more dependencies after this one.
- delete(item.dependsOn, *tx.Hash())
- if len(item.dependsOn) == 0 {
- heap.Push(priorityQueue, item)
- }
- }
- }
-
- // Now that the actual transactions have been selected, update the
- // block weight for the real transaction count and coinbase value with
- // the total fees accordingly.
- blockWeight -= wire.MaxVarIntPayload -
- (uint32(wire.VarIntSerializeSize(uint64(len(blockTxns)))) *
- blockchain.WitnessScaleFactor)
- coinbaseTx.MsgTx().TxOut[0].Value += totalFees
- txFees[0] = -totalFees
-
- // If segwit is active and we included transactions with witness data,
- // then we'll need to include a commitment to the witness data in an
- // OP_RETURN output within the coinbase transaction.
- var witnessCommitment []byte
- if witnessIncluded {
- // The witness of the coinbase transaction MUST be exactly 32-bytes
- // of all zeroes.
- var witnessNonce [blockchain.CoinbaseWitnessDataLen]byte
- coinbaseTx.MsgTx().TxIn[0].Witness = wire.TxWitness{witnessNonce[:]}
-
- // Next, obtain the merkle root of a tree which consists of the
- // wtxid of all transactions in the block. The coinbase
- // transaction will have a special wtxid of all zeroes.
- witnessMerkleTree := blockchain.BuildMerkleTreeStore(blockTxns,
- true)
- witnessMerkleRoot := witnessMerkleTree[len(witnessMerkleTree)-1]
-
- // The preimage to the witness commitment is:
- // witnessRoot || coinbaseWitness
- var witnessPreimage [64]byte
- copy(witnessPreimage[:32], witnessMerkleRoot[:])
- copy(witnessPreimage[32:], witnessNonce[:])
-
- // The witness commitment itself is the double-sha256 of the
- // witness preimage generated above. With the commitment
- // generated, the witness script for the output is: OP_RETURN
- // OP_DATA_36 {0xaa21a9ed || witnessCommitment}. The leading
- // prefix is refered to as the "witness magic bytes".
- witnessCommitment = chainhash.DoubleHashB(witnessPreimage[:])
- witnessScript := append(blockchain.WitnessMagicBytes, witnessCommitment...)
-
- // Finally, create the OP_RETURN carrying witness commitment
- // output as an additional output within the coinbase.
- commitmentOutput := &wire.TxOut{
- Value: 0,
- PkScript: witnessScript,
- }
- coinbaseTx.MsgTx().TxOut = append(coinbaseTx.MsgTx().TxOut,
- commitmentOutput)
- }
-
- // Calculate the required difficulty for the block. The timestamp
- // is potentially adjusted to ensure it comes after the median time of
- // the last several blocks per the chain consensus rules.
- ts := medianAdjustedTime(best, g.timeSource)
- reqDifficulty, err := g.chain.CalcNextRequiredDifficulty(ts)
- if err != nil {
- return nil, err
- }
-
- // Calculate the next expected block version based on the state of the
- // rule change deployments.
- nextBlockVersion, err := g.chain.CalcNextBlockVersion()
- if err != nil {
- return nil, err
- }
-
- // Create a new block ready to be solved.
- merkles := blockchain.BuildMerkleTreeStore(blockTxns, false)
- var msgBlock wire.MsgBlock
- msgBlock.Header = wire.BlockHeader{
- Version: nextBlockVersion,
- PrevBlock: best.Hash,
- MerkleRoot: *merkles[len(merkles)-1],
- Timestamp: ts,
- Bits: reqDifficulty,
- }
- for _, tx := range blockTxns {
- if err := msgBlock.AddTransaction(tx.MsgTx()); err != nil {
- return nil, err
- }
- }
-
- // Finally, perform a full check on the created block against the chain
- // consensus rules to ensure it properly connects to the current best
- // chain with no issues.
- block := btcutil.NewBlock(&msgBlock)
- block.SetHeight(nextBlockHeight)
- if err := g.chain.CheckConnectBlock(block); err != nil {
- return nil, err
- }
-
- log.Debugf("Created new block template (%d transactions, %d in "+
- "fees, %d signature operations cost, %d weight, target difficulty "+
- "%064x)", len(msgBlock.Transactions), totalFees, blockSigOpCost,
- blockWeight, blockchain.CompactToBig(msgBlock.Header.Bits))
-
- return &BlockTemplate{
- Block: &msgBlock,
- Fees: txFees,
- SigOpCosts: txSigOpCosts,
- Height: nextBlockHeight,
- ValidPayAddress: payToAddress != nil,
- WitnessCommitment: witnessCommitment,
- }, nil
-}
-
-// UpdateBlockTime updates the timestamp in the header of the passed block to
-// the current time while taking into account the median time of the last
-// several blocks to ensure the new time is after that time per the chain
-// consensus rules. Finally, it will update the target difficulty if needed
-// based on the new time for the test networks since their target difficulty can
-// change based upon time.
-func (g *BlkTmplGenerator) UpdateBlockTime(msgBlock *wire.MsgBlock) error {
- // The new timestamp is potentially adjusted to ensure it comes after
- // the median time of the last several blocks per the chain consensus
- // rules.
- newTime := medianAdjustedTime(g.chain.BestSnapshot(), g.timeSource)
- msgBlock.Header.Timestamp = newTime
-
- // Recalculate the difficulty if running on a network that requires it.
- if g.chainParams.ReduceMinDifficulty {
- difficulty, err := g.chain.CalcNextRequiredDifficulty(newTime)
- if err != nil {
- return err
- }
- msgBlock.Header.Bits = difficulty
- }
-
- return nil
-}
-
-// UpdateExtraNonce updates the extra nonce in the coinbase script of the passed
-// block by regenerating the coinbase script with the passed value and block
-// height. It also recalculates and updates the new merkle root that results
-// from changing the coinbase script.
-func (g *BlkTmplGenerator) UpdateExtraNonce(msgBlock *wire.MsgBlock, blockHeight int32, extraNonce uint64) error {
- coinbaseScript, err := standardCoinbaseScript(blockHeight, extraNonce)
- if err != nil {
- return err
- }
- if len(coinbaseScript) > blockchain.MaxCoinbaseScriptLen {
- return fmt.Errorf("coinbase transaction script length "+
- "of %d is out of range (min: %d, max: %d)",
- len(coinbaseScript), blockchain.MinCoinbaseScriptLen,
- blockchain.MaxCoinbaseScriptLen)
- }
- msgBlock.Transactions[0].TxIn[0].SignatureScript = coinbaseScript
-
- // TODO(davec): A btcutil.Block should use saved in the state to avoid
- // recalculating all of the other transaction hashes.
- // block.Transactions[0].InvalidateCache()
-
- // Recalculate the merkle root with the updated extra nonce.
- block := btcutil.NewBlock(msgBlock)
- merkles := blockchain.BuildMerkleTreeStore(block.Transactions(), false)
- msgBlock.Header.MerkleRoot = *merkles[len(merkles)-1]
- return nil
-}
-
-// BestSnapshot returns information about the current best chain block and
-// related state as of the current point in time using the chain instance
-// associated with the block template generator. The returned state must be
-// treated as immutable since it is shared by all callers.
-//
-// This function is safe for concurrent access.
-func (g *BlkTmplGenerator) BestSnapshot() *blockchain.BestState {
- return g.chain.BestSnapshot()
-}
-
-// TxSource returns the associated transaction source.
-//
-// This function is safe for concurrent access.
-func (g *BlkTmplGenerator) TxSource() TxSource {
- return g.txSource
-}
+++ /dev/null
-// Copyright (c) 2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package mining
-
-import (
- "container/heap"
- "math/rand"
- "testing"
-
- "github.com/btcsuite/btcutil"
-)
-
-// TestTxFeePrioHeap ensures the priority queue for transaction fees and
-// priorities works as expected.
-func TestTxFeePrioHeap(t *testing.T) {
- // Create some fake priority items that exercise the expected sort
- // edge conditions.
- testItems := []*txPrioItem{
- {feePerKB: 5678, priority: 3},
- {feePerKB: 5678, priority: 1},
- {feePerKB: 5678, priority: 1}, // Duplicate fee and prio
- {feePerKB: 5678, priority: 5},
- {feePerKB: 5678, priority: 2},
- {feePerKB: 1234, priority: 3},
- {feePerKB: 1234, priority: 1},
- {feePerKB: 1234, priority: 5},
- {feePerKB: 1234, priority: 5}, // Duplicate fee and prio
- {feePerKB: 1234, priority: 2},
- {feePerKB: 10000, priority: 0}, // Higher fee, smaller prio
- {feePerKB: 0, priority: 10000}, // Higher prio, lower fee
- }
-
- // Add random data in addition to the edge conditions already manually
- // specified.
- randSeed := rand.Int63()
- defer func() {
- if t.Failed() {
- t.Logf("Random numbers using seed: %v", randSeed)
- }
- }()
- prng := rand.New(rand.NewSource(randSeed))
- for i := 0; i < 1000; i++ {
- testItems = append(testItems, &txPrioItem{
- feePerKB: int64(prng.Float64() * btcutil.SatoshiPerBitcoin),
- priority: prng.Float64() * 100,
- })
- }
-
- // Test sorting by fee per KB then priority.
- var highest *txPrioItem
- priorityQueue := newTxPriorityQueue(len(testItems), true)
- for i := 0; i < len(testItems); i++ {
- prioItem := testItems[i]
- if highest == nil {
- highest = prioItem
- }
- if prioItem.feePerKB >= highest.feePerKB &&
- prioItem.priority > highest.priority {
-
- highest = prioItem
- }
- heap.Push(priorityQueue, prioItem)
- }
-
- for i := 0; i < len(testItems); i++ {
- prioItem := heap.Pop(priorityQueue).(*txPrioItem)
- if prioItem.feePerKB >= highest.feePerKB &&
- prioItem.priority > highest.priority {
-
- t.Fatalf("fee sort: item (fee per KB: %v, "+
- "priority: %v) higher than than prev "+
- "(fee per KB: %v, priority %v)",
- prioItem.feePerKB, prioItem.priority,
- highest.feePerKB, highest.priority)
- }
- highest = prioItem
- }
-
- // Test sorting by priority then fee per KB.
- highest = nil
- priorityQueue = newTxPriorityQueue(len(testItems), false)
- for i := 0; i < len(testItems); i++ {
- prioItem := testItems[i]
- if highest == nil {
- highest = prioItem
- }
- if prioItem.priority >= highest.priority &&
- prioItem.feePerKB > highest.feePerKB {
-
- highest = prioItem
- }
- heap.Push(priorityQueue, prioItem)
- }
-
- for i := 0; i < len(testItems); i++ {
- prioItem := heap.Pop(priorityQueue).(*txPrioItem)
- if prioItem.priority >= highest.priority &&
- prioItem.feePerKB > highest.feePerKB {
-
- t.Fatalf("priority sort: item (fee per KB: %v, "+
- "priority: %v) higher than than prev "+
- "(fee per KB: %v, priority %v)",
- prioItem.feePerKB, prioItem.priority,
- highest.feePerKB, highest.priority)
- }
- highest = prioItem
- }
-}
+++ /dev/null
-// Copyright (c) 2014-2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package mining
-
-import (
- "github.com/btcsuite/btcd/blockchain"
- "github.com/btcsuite/btcd/wire"
- "github.com/btcsuite/btcutil"
-)
-
-const (
- // UnminedHeight is the height used for the "block" height field of the
- // contextual transaction information provided in a transaction store
- // when it has not yet been mined into a block.
- UnminedHeight = 0x7fffffff
-)
-
-// Policy houses the policy (configuration parameters) which is used to control
-// the generation of block templates. See the documentation for
-// NewBlockTemplate for more details on each of these parameters are used.
-type Policy struct {
- // BlockMinWeight is the minimum block weight to be used when
- // generating a block template.
- BlockMinWeight uint32
-
- // BlockMaxWeight is the maximum block weight to be used when
- // generating a block template.
- BlockMaxWeight uint32
-
- // BlockMinWeight is the minimum block size to be used when generating
- // a block template.
- BlockMinSize uint32
-
- // BlockMaxSize is the maximum block size to be used when generating a
- // block template.
- BlockMaxSize uint32
-
- // BlockPrioritySize is the size in bytes for high-priority / low-fee
- // transactions to be used when generating a block template.
- BlockPrioritySize uint32
-
- // TxMinFreeFee is the minimum fee in Satoshi/1000 bytes that is
- // required for a transaction to be treated as free for mining purposes
- // (block template generation).
- TxMinFreeFee btcutil.Amount
-}
-
-// minInt is a helper function to return the minimum of two ints. This avoids
-// a math import and the need to cast to floats.
-func minInt(a, b int) int {
- if a < b {
- return a
- }
- return b
-}
-
-// calcInputValueAge is a helper function used to calculate the input age of
-// a transaction. The input age for a txin is the number of confirmations
-// since the referenced txout multiplied by its output value. The total input
-// age is the sum of this value for each txin. Any inputs to the transaction
-// which are currently in the mempool and hence not mined into a block yet,
-// contribute no additional input age to the transaction.
-func calcInputValueAge(tx *wire.MsgTx, utxoView *blockchain.UtxoViewpoint, nextBlockHeight int32) float64 {
- var totalInputAge float64
- for _, txIn := range tx.TxIn {
- // Don't attempt to accumulate the total input age if the
- // referenced transaction output doesn't exist.
- originHash := &txIn.PreviousOutPoint.Hash
- originIndex := txIn.PreviousOutPoint.Index
- txEntry := utxoView.LookupEntry(originHash)
- if txEntry != nil && !txEntry.IsOutputSpent(originIndex) {
- // Inputs with dependencies currently in the mempool
- // have their block height set to a special constant.
- // Their input age should computed as zero since their
- // parent hasn't made it into a block yet.
- var inputAge int32
- originHeight := txEntry.BlockHeight()
- if originHeight == UnminedHeight {
- inputAge = 0
- } else {
- inputAge = nextBlockHeight - originHeight
- }
-
- // Sum the input value times age.
- inputValue := txEntry.AmountByIndex(originIndex)
- totalInputAge += float64(inputValue * int64(inputAge))
- }
- }
-
- return totalInputAge
-}
-
-// CalcPriority returns a transaction priority given a transaction and the sum
-// of each of its input values multiplied by their age (# of confirmations).
-// Thus, the final formula for the priority is:
-// sum(inputValue * inputAge) / adjustedTxSize
-func CalcPriority(tx *wire.MsgTx, utxoView *blockchain.UtxoViewpoint, nextBlockHeight int32) float64 {
- // In order to encourage spending multiple old unspent transaction
- // outputs thereby reducing the total set, don't count the constant
- // overhead for each input as well as enough bytes of the signature
- // script to cover a pay-to-script-hash redemption with a compressed
- // pubkey. This makes additional inputs free by boosting the priority
- // of the transaction accordingly. No more incentive is given to avoid
- // encouraging gaming future transactions through the use of junk
- // outputs. This is the same logic used in the reference
- // implementation.
- //
- // The constant overhead for a txin is 41 bytes since the previous
- // outpoint is 36 bytes + 4 bytes for the sequence + 1 byte the
- // signature script length.
- //
- // A compressed pubkey pay-to-script-hash redemption with a maximum len
- // signature is of the form:
- // [OP_DATA_73 <73-byte sig> + OP_DATA_35 + {OP_DATA_33
- // <33 byte compresed pubkey> + OP_CHECKSIG}]
- //
- // Thus 1 + 73 + 1 + 1 + 33 + 1 = 110
- overhead := 0
- for _, txIn := range tx.TxIn {
- // Max inputs + size can't possibly overflow here.
- overhead += 41 + minInt(110, len(txIn.SignatureScript))
- }
-
- serializedTxSize := tx.SerializeSize()
- if overhead >= serializedTxSize {
- return 0.0
- }
-
- inputValueAge := calcInputValueAge(tx, utxoView, nextBlockHeight)
- return inputValueAge / float64(serializedTxSize-overhead)
-}
+++ /dev/null
-// Copyright (c) 2016 The btcsuite developers
-// Use of this source code is governed by an ISC
-// license that can be found in the LICENSE file.
-
-package mining
-
-import (
- "encoding/hex"
- "testing"
-
- "github.com/btcsuite/btcd/blockchain"
- "github.com/btcsuite/btcd/chaincfg/chainhash"
- "github.com/btcsuite/btcd/wire"
- "github.com/btcsuite/btcutil"
-)
-
-// newHashFromStr converts the passed big-endian hex string into a
-// chainhash.Hash. It only differs from the one available in chainhash in that
-// it panics on an error since it will only (and must only) be called with
-// hard-coded, and therefore known good, hashes.
-func newHashFromStr(hexStr string) *chainhash.Hash {
- hash, err := chainhash.NewHashFromStr(hexStr)
- if err != nil {
- panic("invalid hash in source file: " + hexStr)
- }
- return hash
-}
-
-// hexToBytes converts the passed hex string into bytes and will panic if there
-// is an error. This is only provided for the hard-coded constants so errors in
-// the source code can be detected. It will only (and must only) be called with
-// hard-coded values.
-func hexToBytes(s string) []byte {
- b, err := hex.DecodeString(s)
- if err != nil {
- panic("invalid hex in source file: " + s)
- }
- return b
-}
-
-// newUtxoViewpoint returns a new utxo view populated with outputs of the
-// provided source transactions as if there were available at the respective
-// block height specified in the heights slice. The length of the source txns
-// and source tx heights must match or it will panic.
-func newUtxoViewpoint(sourceTxns []*wire.MsgTx, sourceTxHeights []int32) *blockchain.UtxoViewpoint {
- if len(sourceTxns) != len(sourceTxHeights) {
- panic("each transaction must have its block height specified")
- }
-
- view := blockchain.NewUtxoViewpoint()
- for i, tx := range sourceTxns {
- view.AddTxOuts(btcutil.NewTx(tx), sourceTxHeights[i])
- }
- return view
-}
-
-// TestCalcPriority ensures the priority calculations work as intended.
-func TestCalcPriority(t *testing.T) {
- // commonSourceTx1 is a valid transaction used in the tests below as an
- // input to transactions that are having their priority calculated.
- //
- // From block 7 in main blockchain.
- // tx 0437cd7f8525ceed2324359c2d0ba26006d92d856a9c20fa0241106ee5a597c9
- commonSourceTx1 := &wire.MsgTx{
- Version: 1,
- TxIn: []*wire.TxIn{{
- PreviousOutPoint: wire.OutPoint{
- Hash: chainhash.Hash{},
- Index: wire.MaxPrevOutIndex,
- },
- SignatureScript: hexToBytes("04ffff001d0134"),
- Sequence: 0xffffffff,
- }},
- TxOut: []*wire.TxOut{{
- Value: 5000000000,
- PkScript: hexToBytes("410411db93e1dcdb8a016b49840f8c5" +
- "3bc1eb68a382e97b1482ecad7b148a6909a5cb2e0ead" +
- "dfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8" +
- "643f656b412a3ac"),
- }},
- LockTime: 0,
- }
-
- // commonRedeemTx1 is a valid transaction used in the tests below as the
- // transaction to calculate the priority for.
- //
- // It originally came from block 170 in main blockchain.
- commonRedeemTx1 := &wire.MsgTx{
- Version: 1,
- TxIn: []*wire.TxIn{{
- PreviousOutPoint: wire.OutPoint{
- Hash: *newHashFromStr("0437cd7f8525ceed232435" +
- "9c2d0ba26006d92d856a9c20fa0241106ee5" +
- "a597c9"),
- Index: 0,
- },
- SignatureScript: hexToBytes("47304402204e45e16932b8af" +
- "514961a1d3a1a25fdf3f4f7732e9d624c6c61548ab5f" +
- "b8cd410220181522ec8eca07de4860a4acdd12909d83" +
- "1cc56cbbac4622082221a8768d1d0901"),
- Sequence: 0xffffffff,
- }},
- TxOut: []*wire.TxOut{{
- Value: 1000000000,
- PkScript: hexToBytes("4104ae1a62fe09c5f51b13905f07f06" +
- "b99a2f7159b2225f374cd378d71302fa28414e7aab37" +
- "397f554a7df5f142c21c1b7303b8a0626f1baded5c72" +
- "a704f7e6cd84cac"),
- }, {
- Value: 4000000000,
- PkScript: hexToBytes("410411db93e1dcdb8a016b49840f8c5" +
- "3bc1eb68a382e97b1482ecad7b148a6909a5cb2e0ead" +
- "dfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8" +
- "643f656b412a3ac"),
- }},
- LockTime: 0,
- }
-
- tests := []struct {
- name string // test description
- tx *wire.MsgTx // tx to calc priority for
- utxoView *blockchain.UtxoViewpoint // inputs to tx
- nextHeight int32 // height for priority calc
- want float64 // expected priority
- }{
- {
- name: "one height 7 input, prio tx height 169",
- tx: commonRedeemTx1,
- utxoView: newUtxoViewpoint([]*wire.MsgTx{commonSourceTx1},
- []int32{7}),
- nextHeight: 169,
- want: 5e9,
- },
- {
- name: "one height 100 input, prio tx height 169",
- tx: commonRedeemTx1,
- utxoView: newUtxoViewpoint([]*wire.MsgTx{commonSourceTx1},
- []int32{100}),
- nextHeight: 169,
- want: 2129629629.6296296,
- },
- {
- name: "one height 7 input, prio tx height 100000",
- tx: commonRedeemTx1,
- utxoView: newUtxoViewpoint([]*wire.MsgTx{commonSourceTx1},
- []int32{7}),
- nextHeight: 100000,
- want: 3086203703703.7036,
- },
- {
- name: "one height 100 input, prio tx height 100000",
- tx: commonRedeemTx1,
- utxoView: newUtxoViewpoint([]*wire.MsgTx{commonSourceTx1},
- []int32{100}),
- nextHeight: 100000,
- want: 3083333333333.3335,
- },
- }
-
- for i, test := range tests {
- got := CalcPriority(test.tx, test.utxoView, test.nextHeight)
- if got != test.want {
- t.Errorf("CalcPriority #%d (%q): unexpected priority "+
- "got %v want %v", i, test.name, got, test.want)
- continue
- }
- }
-}