Dero Web Wallet derosuite. This repo contains changes required for webwallet. With this changes any Dero daemon can become web wallet. All changes are related to daemon rpc server and wallet to make it light and faster.
Nelze vybrat více než 25 témat Téma musí začínat písmenem nebo číslem, může obsahovat pomlčky („-“) a může být dlouhé až 35 znaků.

385 lines
11KB

  1. // Copyright 2017-2018 DERO Project. All rights reserved.
  2. // Use of this source code in any form is governed by RESEARCH license.
  3. // license can be found in the LICENSE file.
  4. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
  5. //
  6. //
  7. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  8. // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  10. // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  11. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  12. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  13. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  14. // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  15. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. // 64 bit arch will use this DB
  17. package storage
  18. import "os"
  19. import "fmt"
  20. import "sync"
  21. import "strconv" // has intsize which give whether int is 64 bits or 32 bits
  22. import "runtime"
  23. import "path/filepath"
  24. import "encoding/binary"
  25. import "github.com/romana/rlog"
  26. import bolt "github.com/coreos/bbolt"
  27. import log "github.com/sirupsen/logrus"
  28. import "github.com/deroproject/derosuite/globals"
  29. type BoltStore struct {
  30. DB *bolt.DB
  31. tx *bolt.Tx
  32. sync.Mutex // lock this struct
  33. rw sync.RWMutex
  34. }
  35. // this object is returned
  36. type BoltTXWrapper struct {
  37. bdb *BoltStore
  38. tx *bolt.Tx
  39. }
  40. var Bolt_backend *BoltStore = &BoltStore{} // global variable
  41. var logger *log.Entry
  42. func (b *BoltStore) Init(params map[string]interface{}) (err error) {
  43. logger = globals.Logger.WithFields(log.Fields{"com": "STORE"})
  44. current_path := filepath.Join(globals.GetDataDirectory(), "derod_database.db")
  45. if params["--simulator"] == true {
  46. current_path = filepath.Join(os.TempDir(), "derod_simulation.db") // sp
  47. }
  48. logger.Infof("Initializing boltdb store at path %s", current_path)
  49. // Open the my.db data file in your current directory.
  50. // It will be created if it doesn't exist.
  51. options := &bolt.Options{InitialMmapSize :1 * 1024 * 1024 * 1024}
  52. if runtime.GOOS != "windows" && strconv.IntSize == 64 {
  53. options.InitialMmapSize *= 40 // default allocation 40 GB
  54. }else{
  55. options.InitialMmapSize = 0 // on windows, make it 0
  56. }
  57. b.DB, err = bolt.Open(current_path, 0600, options)
  58. if err != nil {
  59. logger.Fatalf("Cannot open boltdb store err %s", err)
  60. }
  61. // if simulation, delete the file , so as it gets cleaned up automcatically
  62. if params["--simulator"] == true {
  63. os.Remove(current_path)
  64. }
  65. // place db in no sync mode
  66. //b.DB.NoSync = true
  67. return nil
  68. }
  69. func (b *BoltStore) Shutdown() (err error) {
  70. logger.Infof("Shutting boltdb store")
  71. if b.DB != nil {
  72. b.DB.Sync() // sync the DB before closing
  73. b.DB.Close()
  74. }
  75. return nil
  76. }
  77. // get a new writable tx,
  78. // we will manage the writable txs manually
  79. // since a block may cause changes to a number of fields which must be reflected atomically
  80. // this function is always triggered while the atomic lock is taken
  81. // this is done avoid a race condition in returning the tx and using it
  82. func (b *BoltStore) get_new_writable_tx() (tx *bolt.Tx) {
  83. if b.tx != nil {
  84. tx = b.tx // use existing pending tx
  85. } else { // create new pending tx
  86. tx, err := b.DB.Begin(true) // begin a new writable tx
  87. if err != nil {
  88. logger.Warnf("Error while creating new writable tx, err %s", err)
  89. } else {
  90. b.tx = tx
  91. rlog.Tracef(1, "Beginning new writable TX")
  92. }
  93. }
  94. return b.tx
  95. }
  96. // Commit the pending transaction to disk
  97. func (b *BoltStore) BeginTX(writable bool) (DBTX, error) {
  98. // logger.Warnf(" new writable tx, err")
  99. txwrapper := &BoltTXWrapper{}
  100. tx, err := b.DB.Begin(writable) // begin a new writable tx
  101. if err != nil {
  102. logger.Warnf("Error while creating new writable tx, err %s", err)
  103. return nil, fmt.Errorf("Error while creating new writable tx, err %s", err)
  104. }
  105. txwrapper.tx = tx
  106. txwrapper.bdb = b // parent DB reference
  107. //logger.Warnf(" created new writable tx, err")
  108. return txwrapper, nil
  109. }
  110. func (b *BoltTXWrapper) Commit() error {
  111. err := b.tx.Commit()
  112. if err != nil {
  113. logger.Warnf("Error while committing tx, err %s", err)
  114. return err
  115. }
  116. //logger.Warnf(" Commiting TX")
  117. return nil
  118. }
  119. // Commit the pending transaction to disk
  120. func (b *BoltStore) Commit() {
  121. b.Lock()
  122. if b.tx != nil {
  123. rlog.Tracef(1, "Committing writable TX")
  124. err := b.tx.Commit()
  125. if err != nil {
  126. logger.Warnf("Error while commit tx, err %s", err)
  127. }
  128. b.tx = nil
  129. } else {
  130. logger.Warnf("Trying to Commit a NULL transaction, NOT possible")
  131. }
  132. b.Unlock()
  133. }
  134. // Roll back existing changes to disk
  135. func (b *BoltTXWrapper) Rollback() {
  136. // logger.Warnf(" Rollbacking TX")
  137. b.tx.Rollback()
  138. }
  139. // Roll back existing changes to disk
  140. // TODO implement this
  141. func (b *BoltTXWrapper) Sync() {
  142. }
  143. // Roll back existing changes to disk
  144. func (b *BoltStore) Rollback() {
  145. b.Lock()
  146. if b.tx != nil {
  147. rlog.Tracef(1, "Rollbacking writable TX")
  148. b.tx.Rollback()
  149. b.tx = nil
  150. } else {
  151. //logger.Warnf("Trying to Rollback a NULL transaction, NOT possible")
  152. }
  153. b.Unlock()
  154. }
  155. // sync the DB to disk
  156. func (b *BoltStore) Sync() {
  157. b.Lock()
  158. if b.DB != nil {
  159. b.DB.Sync() // sync the DB
  160. }
  161. b.Unlock()
  162. }
  163. func (b *BoltStore) StoreObject(tx *bolt.Tx, universe_name []byte, galaxy_name []byte, solar_name []byte, key []byte, data []byte) (err error) {
  164. rlog.Tracef(10, "Storing object %s %s %x data len %d", string(universe_name), string(galaxy_name), key, len(data))
  165. // open universe bucket
  166. universe, err := tx.CreateBucketIfNotExists(universe_name)
  167. if err != nil {
  168. logger.Errorf("Error while creating universe bucket %s", err)
  169. return err
  170. }
  171. galaxy, err := universe.CreateBucketIfNotExists(galaxy_name)
  172. if err != nil {
  173. logger.Errorf("Error while creating galaxy bucket %s err %s", string(galaxy_name), err)
  174. return err
  175. }
  176. solar, err := galaxy.CreateBucketIfNotExists(solar_name)
  177. if err != nil {
  178. logger.Errorf("Error while creating solar bucket %s err %s", string(solar_name), err)
  179. return err
  180. }
  181. // now lets update the object attribute
  182. err = solar.Put(key, data)
  183. return err
  184. }
  185. func (b *BoltTXWrapper) StoreObject(universe_name []byte, galaxy_name []byte, solar_name []byte, key []byte, data []byte) (err error) {
  186. return b.bdb.StoreObject(b.tx, universe_name, galaxy_name, solar_name, key, data)
  187. }
  188. // creates an empty bucket
  189. func (b *BoltStore) CreateBucket(tx *bolt.Tx, universe_name []byte, galaxy_name []byte, solar_name []byte) (err error) {
  190. //rlog.Tracef(10, "Storing object %s %s %x data len %d", string(universe_name), string(galaxy_name), key, len(data))
  191. universe, err := tx.CreateBucketIfNotExists(universe_name)
  192. if err != nil {
  193. logger.Errorf("Error while creating universe bucket %s", err)
  194. return err
  195. }
  196. galaxy, err := universe.CreateBucketIfNotExists(galaxy_name)
  197. if err != nil {
  198. logger.Errorf("Error while creating galaxy bucket %s err %s", string(galaxy_name), err)
  199. return err
  200. }
  201. solar, err := galaxy.CreateBucketIfNotExists(solar_name)
  202. if err != nil {
  203. logger.Errorf("Error while creating solar bucket %s err %s", string(solar_name), err)
  204. return err
  205. }
  206. _ = solar
  207. return err
  208. }
  209. func (b *BoltTXWrapper) CreateBucket(universe_name []byte, galaxy_name []byte, solar_name []byte) (err error) {
  210. return b.bdb.CreateBucket(b.tx, universe_name, galaxy_name, solar_name)
  211. }
  212. // a tx is shared by multiple goroutines, so they are protected by a mutex
  213. func (b *BoltStore) LoadObject(tx *bolt.Tx, universe_name []byte, bucket_name []byte, solar_bucket []byte, key []byte) (data []byte, err error) {
  214. //rlog.Tracef(10, "Loading object %s %s %x", string(universe_name), string(bucket_name), key)
  215. b.Lock()
  216. defer b.Unlock()
  217. //b.rw.RLock()
  218. //defer b.rw.RUnlock()
  219. // open universe bucket
  220. {
  221. universe := tx.Bucket(universe_name)
  222. if universe == nil {
  223. return data, fmt.Errorf("No Such Universe %x", universe_name)
  224. }
  225. bucket := universe.Bucket(bucket_name)
  226. if bucket == nil {
  227. return data, fmt.Errorf("No Such Bucket %x", bucket_name)
  228. }
  229. solar := bucket.Bucket(solar_bucket)
  230. if solar == nil {
  231. return data, fmt.Errorf("No Such Bucket %x", solar_bucket)
  232. }
  233. // now lets find the object
  234. value := solar.Get(key)
  235. data = make([]byte, len(value), len(value))
  236. copy(data, value) // job done
  237. }
  238. return
  239. }
  240. func (b *BoltTXWrapper) LoadObject(universe_name []byte, bucket_name []byte, solar_bucket []byte, key []byte) (data []byte, err error) {
  241. return b.bdb.LoadObject(b.tx, universe_name, bucket_name, solar_bucket, key)
  242. }
  243. func (b *BoltStore) LoadObjects(tx *bolt.Tx, universe_name []byte, bucket_name []byte, solar_bucket []byte) (keys [][]byte, values [][]byte, err error) {
  244. //rlog.Tracef(10, "Loading object %s %s %x", string(universe_name), string(bucket_name), key)
  245. b.Lock()
  246. defer b.Unlock()
  247. // open universe bucket
  248. {
  249. universe := tx.Bucket(universe_name)
  250. if universe == nil {
  251. return keys, values, fmt.Errorf("No Such Universe %x", universe_name)
  252. }
  253. bucket := universe.Bucket(bucket_name)
  254. if bucket == nil {
  255. return keys, values, fmt.Errorf("No Such Bucket %x", bucket_name)
  256. }
  257. solar := bucket.Bucket(solar_bucket)
  258. if solar == nil {
  259. return keys, values, fmt.Errorf("No Such Bucket %x", solar_bucket)
  260. }
  261. // Create a cursor for iteration.
  262. cursor := solar.Cursor()
  263. // Iterate over items in sorted key order. This starts from the
  264. // first key/value pair and updates the k/v variables to the
  265. // next key/value on each iteration.
  266. //
  267. // The loop finishes at the end of the cursor when a nil key is returned.
  268. for k, v := cursor.First(); k != nil; k, v = cursor.Next() {
  269. key := make([]byte, len(k), len(k))
  270. value := make([]byte, len(v), len(v))
  271. copy(key, k) // job done
  272. copy(value, v) // job done
  273. keys = append(keys, key)
  274. values = append(values, value)
  275. // fmt.Printf("A %s is %s.", k, v)
  276. }
  277. }
  278. return
  279. }
  280. func (b *BoltTXWrapper) LoadObjects(universe_name []byte, galaxy_name []byte, solar_name []byte) (keys [][]byte, values [][]byte, err error) {
  281. return b.bdb.LoadObjects(b.tx, universe_name, galaxy_name, solar_name)
  282. }
  283. // this function stores a uint64
  284. // this will automcatically use the lock
  285. func (b *BoltTXWrapper) StoreUint64(universe_bucket []byte, galaxy_bucket []byte, solar_bucket []byte, key []byte, data uint64) error {
  286. return b.bdb.StoreObject(b.tx, universe_bucket, galaxy_bucket, solar_bucket, key, itob(data))
  287. }
  288. // this function loads the data as 64 byte integer
  289. func (b *BoltTXWrapper) LoadUint64(universe_bucket []byte, galaxy_bucket []byte, solar_bucket []byte, key []byte) (uint64, error) {
  290. object_data, err := b.LoadObject(universe_bucket, galaxy_bucket, solar_bucket, key)
  291. if err != nil {
  292. return 0, err
  293. }
  294. if len(object_data) == 0 {
  295. return 0, fmt.Errorf("No value stored here, we should look more")
  296. }
  297. if len(object_data) != 8 {
  298. panic("Database corruption, invalid data ")
  299. }
  300. value := binary.BigEndian.Uint64(object_data)
  301. return value, nil
  302. }
  303. // itob returns an 8-byte big endian representation of v.
  304. func itob(v uint64) []byte {
  305. b := make([]byte, 8)
  306. binary.BigEndian.PutUint64(b, uint64(v))
  307. return b
  308. }