bucashcoins.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. package bucash
  2. import (
  3. "encoding/json"
  4. //"errors"
  5. "fmt"
  6. "strconv"
  7. "sync"
  8. . "template"
  9. "time"
  10. simplejson "github.com/go-simplejson"
  11. tml "github.com/toml-master"
  12. )
  13. var (
  14. Config config
  15. CoinApi BuCashApi
  16. m_unspent []map[string]interface{}
  17. m_mutUnspent sync.Mutex
  18. )
  19. type Bucash struct {
  20. walletstatus bool
  21. }
  22. const (
  23. NameCoin = "BCC"
  24. )
  25. func (m Bucash) InitDriver(parm interface{}) bool {
  26. if m.initconfig() == false {
  27. return false
  28. }
  29. go m.getwalletinfo()
  30. //缓存当前未花费的
  31. m_unspent = make([]map[string]interface{}, 0)
  32. go AsyncRoutine()
  33. return true
  34. }
  35. //get the server's total available balance
  36. func (m Bucash) CoinBalance(parm interface{}) ([]byte, error) {
  37. confirmedBalance, err := CoinApi.WalleGetBalance("*")
  38. if err != nil {
  39. LOG("ERROR", " GetBalance err:%v", err.Error())
  40. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, GETBALANCE_ERR, getErrMsg(GETBALANCE_ERR, nil))
  41. }
  42. UnconfirmedBalance, err := CoinApi.WalleGetUnconfirmedBalance("")
  43. if err != nil {
  44. LOG("ERROR", " GetUnconfirmedBalance err:%s", err.Error())
  45. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, GETUNCONFIRMEDBALANCE_ERR, getErrMsg(GETUNCONFIRMEDBALANCE_ERR, nil))
  46. }
  47. var jbuf []byte
  48. resp := make(map[string]interface{})
  49. resp["confirmedbalance"] = confirmedBalance
  50. resp["unconfirmed"] = UnconfirmedBalance
  51. resp["errcode"] = 0
  52. resp["exact"] = 0
  53. if jbuf, err = json.Marshal(resp); err != nil {
  54. LOG("ERROR", "lite inner json error:%v", err.Error())
  55. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  56. }
  57. return jbuf, nil
  58. }
  59. //Returns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.
  60. func (m Bucash) TransInfo(parm interface{}) ([]byte, error) {
  61. pjs := parm.(*simplejson.Json)
  62. startH := pjs.Get("starth").MustUint64()
  63. endH := pjs.Get("endh").MustUint64()
  64. if startH < 1 {
  65. LOG("DEBUG", " input para err:%v", startH)
  66. startH = 1
  67. }
  68. //get longest block count
  69. blockcount, err := CoinApi.WalleGetBlockCount()
  70. if err != nil {
  71. LOG("ERROR", " WalleGetBlockCount err:%v", err.Error())
  72. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, GETCLOCKCOUNT_ERR, getErrMsg(GETCLOCKCOUNT_ERR, nil))
  73. }
  74. //get startblock hash by height
  75. if startH > blockcount {
  76. LOG("DEBUG", " startheight:%v > blockcount:%v", startH, blockcount)
  77. startH = blockcount
  78. }
  79. startblockhash, err := CoinApi.WalletGetBlockHash(uint64(startH - 1))
  80. if err != nil {
  81. LOG("ERROR", " WalletGetBlockHash startH:%v err:%v", startH, err.Error())
  82. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, GETBLOCKINFO_ERR, getErrMsg(GETBLOCKINFO_ERR, nil))
  83. }
  84. //get endblock time by height
  85. if endH > blockcount {
  86. LOG("DEBUG", " endheight:%v > blockcount:%v", endH, blockcount)
  87. endH = blockcount
  88. }
  89. endblockhash, err := CoinApi.WalletGetBlockHash(uint64(endH))
  90. if err != nil {
  91. LOG("ERROR", " WalletGetBlockHash startH:%v err:%v", startH, err.Error())
  92. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, GETBLOCKINFO_ERR, getErrMsg(GETBLOCKINFO_ERR, nil))
  93. }
  94. endblocktime, err := CoinApi.WalletGetBlockTime(endblockhash)
  95. if err != nil {
  96. LOG("ERROR", " WalletGetBlockTime endH:%v err:%v", endH, err.Error())
  97. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, GETBLOCKINFO_ERR, getErrMsg(GETBLOCKINFO_ERR, nil))
  98. }
  99. //Get all transactions in blocks since block [blockhash]
  100. resp, err := CoinApi.WalleListSinceBlock(startblockhash)
  101. if err != nil {
  102. LOG("ERROR", " WalleListSinceBlock err:%v", err.Error())
  103. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, TRANSINFO_ERR, getErrMsg(TRANSINFO_ERR, nil))
  104. }
  105. var litelisttransactionsinfo []Listtransactions
  106. if err = json.Unmarshal([]byte(resp), &litelisttransactionsinfo); err != nil {
  107. LOG("ERROR", " inner json error:%v", err.Error())
  108. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  109. }
  110. outputsArr := make([]map[string]interface{}, 0)
  111. for _, listtransaction := range litelisttransactionsinfo {
  112. // get all transactions from block startHright to endHeight
  113. if listtransaction.Blocktime <= endblocktime {
  114. requestData := make(map[string]interface{})
  115. confirmationheight, err := CoinApi.WalletGetBlockHeight(listtransaction.Blockhash)
  116. if err != nil {
  117. LOG("ERROR", "WalletGetBlockHeight error:%v", err.Error())
  118. continue
  119. }
  120. requestData["confirmationheight"] = confirmationheight
  121. requestData["address"] = listtransaction.Address
  122. requestData["confirmationtimestamp"] = listtransaction.Timereceived
  123. requestData["value"] = listtransaction.Amount
  124. requestData["transactionid"] = listtransaction.Txid
  125. requestData["confirmations"] = listtransaction.Confirmations
  126. requestData["walletaddress"] = true
  127. requestData["vout"] = listtransaction.Vout
  128. outputsArr = append(outputsArr, requestData)
  129. }
  130. }
  131. var jbuf []byte
  132. resptmp := make(map[string]interface{})
  133. resptmp["errcode"] = 0
  134. resptmp["cointype"] = "BCC"
  135. resptmp["outputs"] = outputsArr
  136. if jbuf, err = json.Marshal(resptmp); err != nil {
  137. LOG("ERROR", " inner json error:%v", err.Error())
  138. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  139. }
  140. return jbuf, nil
  141. }
  142. //Sent an amount from an account to a lite address.
  143. func (m Bucash) TransferAccounts(parm interface{}) ([]byte, error) {
  144. pjs := parm.(*simplejson.Json)
  145. amountTmp := pjs.Get("amount").MustString()
  146. destination := pjs.Get("address").MustString()
  147. if len(amountTmp) == 0 {
  148. LOG("ERROR", " amount illeagal")
  149. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, AMOUNT_ERR, getErrMsg(AMOUNT_ERR, nil))
  150. }
  151. f, err := strconv.ParseFloat(amountTmp, 64)
  152. if err != nil {
  153. LOG("ERROR", " inner json error:%v", err.Error())
  154. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  155. }
  156. amount := float64(f)
  157. transactionid, err := CoinApi.WalleSendFrom("", destination, amount, 1, "", "")
  158. if err != nil {
  159. LOG("ERROR", " Send coin error:%v", err.Error())
  160. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, SENDCOINS_ERR, getErrMsg(SENDCOINS_ERR, nil))
  161. }
  162. if len(transactionid) != 0 {
  163. var jbuf []byte
  164. resp := make(map[string]interface{})
  165. resp["transcationids"] = []string{transactionid}
  166. resp["errcode"] = 0
  167. resp["msg"] = "ok"
  168. if jbuf, err = json.Marshal(resp); err != nil {
  169. LOG("ERROR", " inner json error:%v", err.Error())
  170. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  171. }
  172. return jbuf, nil
  173. }
  174. LOG("ERROR", " transactionid is null error:%v", err.Error())
  175. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  176. }
  177. //create a new address&key for receiving payments
  178. func (m Bucash) CreateAddress(parm interface{}) ([]byte, error) {
  179. addr, err := CoinApi.WalletNewAddr()
  180. if err != nil {
  181. LOG("ERROR", " get new address error:%v", err.Error())
  182. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, GETNEWADDRESS_ERR, getErrMsg(GETNEWADDRESS_ERR, nil))
  183. }
  184. if len(addr) != 0 {
  185. //get key by the address
  186. key, err := CoinApi.WalletDumpPrivKey(addr)
  187. if err != nil {
  188. LOG("ERROR", " dump private key error:%v", err.Error())
  189. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, DUMPPRIVKEY_ERR, getErrMsg(DUMPPRIVKEY_ERR, nil))
  190. }
  191. if len(key) != 0 {
  192. var jbuf []byte
  193. resp := make(map[string]interface{})
  194. resp["address"] = addr
  195. resp["privkey"] = key
  196. resp["errcode"] = 0
  197. if jbuf, err = json.Marshal(resp); err != nil {
  198. LOG("ERROR", " inner json error:%v", err.Error())
  199. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  200. }
  201. return jbuf, nil
  202. }
  203. LOG("ERROR", " privkey is null error:%v")
  204. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  205. }
  206. LOG("ERROR", " address is null error:%v")
  207. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  208. }
  209. func (m Bucash) getwalletinfo() bool {
  210. fmt.Println("WalletInfo:")
  211. m.walletstatus = false
  212. for {
  213. if m.walletstatus == false {
  214. resp, err := CoinApi.WalletInfo()
  215. if err != nil {
  216. LOG("ERROR", "WalletInfo error:%v", err.Error())
  217. time.Sleep(time.Second * 1)
  218. continue
  219. }
  220. LOG("DEBUG", "WalletInfo resp:%v", string(resp))
  221. m.walletstatus = true
  222. }
  223. time.Sleep(time.Second)
  224. }
  225. }
  226. //config rpc from lite.toml
  227. func (m Bucash) initconfig() bool {
  228. if _, err := tml.DecodeFile("./src/bucash/bucash.toml", &Config); err != nil {
  229. fmt.Println(err)
  230. return false
  231. }
  232. fmt.Printf("%+v\n", Config)
  233. User := Config.Rpc.Rpcuser
  234. Password := Config.Rpc.Rpcpassword
  235. Host := Config.Rpc.Rpchost
  236. Port := Config.Rpc.Rpcport
  237. CoinApi.InitRpcConf(User, Password, Host, Port)
  238. initLiteErr()
  239. f, err := strconv.ParseFloat(Config.Limit.Fee, 64)
  240. if err != nil {
  241. LOG("ERROR", "inner json error:%v", err.Error())
  242. return false
  243. }
  244. fee := float64(f)
  245. CoinApi.WalletSetTxFee(fee)
  246. return true
  247. }
  248. func (m Bucash) ChainHeight(parm interface{}) ([]byte, error) {
  249. blockcount, err := CoinApi.WalleGetBlockCount()
  250. if err != nil {
  251. LOG("ERROR", " get current block count error:%v", err.Error())
  252. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, GETCLOCKCOUNT_ERR, getErrMsg(GETCLOCKCOUNT_ERR, nil))
  253. }
  254. sendstr := fmt.Sprintf(`{"errcode":%v,"height":%v}`, OK, blockcount)
  255. return []byte(sendstr), nil
  256. }
  257. func (m Bucash) ListUnspent(parm interface{}) ([]byte, error) {
  258. i_unspent := make([]map[string]interface{}, 0)
  259. pjs := parm.(*simplejson.Json)
  260. Issync, err := pjs.Get("Sync").Bool()
  261. if !Issync {
  262. fmt.Println("The listunspent data Asynchrony!!!!")
  263. i_unspent = m_unspent
  264. } else {
  265. address, err := pjs.Get("address").StringArray()
  266. if err != nil {
  267. LOG("ERROR", " input parm error:%v", err.Error())
  268. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, LISTUNSPENT_ERR, getErrMsg(LISTUNSPENT_ERR, nil))
  269. }
  270. unspent, err := CoinApi.Listunspent(address)
  271. if err != nil {
  272. LOG("ERROR", " get listunspent:%v", err.Error())
  273. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, LISTUNSPENT_ERR, getErrMsg(LISTUNSPENT_ERR, nil))
  274. }
  275. i_unspent = unspent
  276. }
  277. var jbuf []byte
  278. resptmp := make(map[string]interface{})
  279. resptmp["errcode"] = 0
  280. resptmp["cointype"] = "BCC"
  281. resptmp["unspents"] = i_unspent
  282. if jbuf, err = json.Marshal(resptmp); err != nil {
  283. LOG("ERROR", " inner json error:%v", err.Error())
  284. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  285. }
  286. return jbuf, nil
  287. }
  288. func (m Bucash) SendRawTransaction(parm interface{}) ([]byte, error) {
  289. pjs := parm.(*simplejson.Json)
  290. transdata := pjs.Get("data").MustString()
  291. if len(transdata) == 0 {
  292. return nil, fmt.Errorf(`{"cointype":"BCC","errcode":%v,"msg":"%v"}`, PARM_ERR, getErrMsg(PARM_ERR, []byte("hexstring is null")))
  293. }
  294. transactionhex, err := CoinApi.SendRawTransaction(transdata)
  295. if err != nil {
  296. LOG("ERROR", " SendRawTransaction err:%s", err.Error())
  297. return nil, fmt.Errorf(`{"cointype":"BCC","errcode":%v,"msg":"%s"}`, SEND_RAW_TRANSACTION_ERR, getErrMsg(SEND_RAW_TRANSACTION_ERR, nil))
  298. }
  299. var jbuf []byte
  300. resp := make(map[string]interface{})
  301. resp["cointype"] = "BCC"
  302. resp["transactionids"] = transactionhex
  303. resp["errcode"] = 0
  304. resp["msg"] = "OK"
  305. if jbuf, err = json.Marshal(resp); err != nil {
  306. LOG("ERROR", "inner json error:%v", err.Error())
  307. return nil, fmt.Errorf(`{"cointype":"BCC","errcode":%v,"msg":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  308. }
  309. return jbuf, nil
  310. }
  311. func (m Bucash) SumcoinBalance(parm interface{}) ([]byte, error) {
  312. return nil, nil
  313. }
  314. func (m Bucash) AccountsBalance(parm interface{}) (jbuf []byte, err error) {
  315. var balancestotal, offlinebalancetotal float64
  316. ilistunspent := m_unspent
  317. accountbalance := make([]map[string]interface{}, 0)
  318. offlinebalance := make([]map[string]interface{}, 0)
  319. for _, value := range ilistunspent {
  320. if value["spendable"] == true {
  321. balancestotal += value["Amount"].(float64)
  322. accountbalance = append(accountbalance, value)
  323. } else {
  324. offlinebalancetotal += value["Amount"].(float64)
  325. offlinebalance = append(offlinebalance, value)
  326. }
  327. }
  328. resptmp := make(map[string]interface{})
  329. resptmp["errcode"] = 0
  330. resptmp["cointype"] = "BCC"
  331. resptmp["accountbalance"] = accountbalance
  332. resptmp["balancestotal"] = balancestotal
  333. resptmp["offlinebalance"] = offlinebalance
  334. resptmp["offlinebalancetotal"] = offlinebalancetotal
  335. if jbuf, err = json.Marshal(resptmp); err != nil {
  336. LOG("ERROR", " inner json error:%v", err.Error())
  337. return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, INNER_ERR, getErrMsg(INNER_ERR, nil))
  338. }
  339. return jbuf, nil
  340. }
  341. func AsyncRoutine() {
  342. CachelistunspentTicker := time.NewTicker(120 * time.Second)
  343. for {
  344. select {
  345. case _ = <-CachelistunspentTicker.C:
  346. Cachelistunspent()
  347. }
  348. }
  349. }
  350. func Cachelistunspent() {
  351. fmt.Println("cachelistunspent time:", time.Now().Format("2006-01-02 15:04:05"))
  352. var address []string
  353. unspent, err := CoinApi.Listunspent(address)
  354. if err != nil {
  355. LOG("ERROR", " get listunspent:%v", err.Error())
  356. //return nil, fmt.Errorf(`{"errcode":%v,"mesage":"%s"}`, LISTUNSPENT_ERR, getErrMsg(LISTUNSPENT_ERR, nil))
  357. }
  358. m_mutUnspent.Lock()
  359. m_unspent = unspent
  360. m_mutUnspent.Unlock()
  361. }
  362. func init() {
  363. Register(NameCoin, &Bucash{})
  364. }