neo-go/pkg/database/leveldb.go
decentralisedkev f8979fe7af
Fix lint errors (#182)
* golint and minor changes to make code readable
2019-03-17 18:26:35 +00:00

164 lines
4 KiB
Go

package database
import (
"bytes"
"encoding/binary"
"fmt"
"github.com/CityOfZion/neo-go/pkg/wire/payload"
"github.com/CityOfZion/neo-go/pkg/wire/payload/transaction"
"github.com/CityOfZion/neo-go/pkg/wire/util"
"github.com/syndtr/goleveldb/leveldb"
"github.com/syndtr/goleveldb/leveldb/errors"
)
// LDB represents a leveldb object
type LDB struct {
db *leveldb.DB
path string
}
// Database contains all methods needed for an object to be a database
type Database interface {
// Has checks whether the key is in the database
Has(key []byte) (bool, error)
// Put adds the key value pair into the pair
Put(key []byte, value []byte) error
// Get returns the value for the given key
Get(key []byte) ([]byte, error)
// Delete deletes the given value for the key from the database
Delete(key []byte) error
// Close closes the underlying db object
Close() error
}
var (
// TX is the prefix used when inserting a tx into the db
TX = []byte("TX")
// HEADER is the prefix used when inserting a header into the db
HEADER = []byte("HEADER")
// LATESTHEADER is the prefix used when inserting the latests header into the db
LATESTHEADER = []byte("LH")
// UTXO is the prefix used when inserting a utxo into the db
UTXO = []byte("UTXO")
)
// New will return a new leveldb instance
func New(path string) *LDB {
db, err := leveldb.OpenFile(path, nil)
if _, corrupted := err.(*errors.ErrCorrupted); corrupted {
db, err = leveldb.RecoverFile(path, nil)
}
if err != nil {
return nil
}
return &LDB{
db,
path,
}
}
// Has implements the database interface
func (l *LDB) Has(key []byte) (bool, error) {
return l.db.Has(key, nil)
}
// Put implements the database interface
func (l *LDB) Put(key []byte, value []byte) error {
return l.db.Put(key, value, nil)
}
// Get implements the database interface
func (l *LDB) Get(key []byte) ([]byte, error) {
return l.db.Get(key, nil)
}
// Delete implements the database interface
func (l *LDB) Delete(key []byte) error {
return l.db.Delete(key, nil)
}
// Close implements the database interface
func (l *LDB) Close() error {
return l.db.Close()
}
// AddHeader adds a header into the database
func (l *LDB) AddHeader(header *payload.BlockBase) error {
table := NewTable(l, HEADER)
byt, err := header.Bytes()
if err != nil {
fmt.Println("Could not Get bytes from decoded BlockBase")
return nil
}
fmt.Println("Adding Header, This should be batched!!!!")
// This is the main mapping
//Key: HEADER+BLOCKHASH Value: contents of blockhash
key := header.Hash.Bytes()
err = table.Put(key, byt)
if err != nil {
fmt.Println("Error trying to add the original mapping into the DB for Header. Mapping is [Header]+[Hash]")
return err
}
// This is the secondary mapping
// Key: HEADER + BLOCKHEIGHT Value: blockhash
bh := uint32ToBytes(header.Index)
key = []byte(bh)
err = table.Put(key, header.Hash.Bytes())
if err != nil {
return err
}
// This is the third mapping
// WARNING: This assumes that headers are adding in order.
return table.Put(LATESTHEADER, header.Hash.Bytes())
}
// AddTransactions adds a set of transactions into the database
func (l *LDB) AddTransactions(blockhash util.Uint256, txs []transaction.Transactioner) error {
// SHOULD BE DONE IN BATCH!!!!
for i, tx := range txs {
buf := new(bytes.Buffer)
fmt.Println(tx.ID())
tx.Encode(buf)
txByt := buf.Bytes()
txhash, err := tx.ID()
if err != nil {
fmt.Println("Error adding transaction with bytes", txByt)
return err
}
// This is the original mapping
// Key: [TX] + TXHASH
key := append(TX, txhash.Bytes()...)
l.Put(key, txByt)
// This is the index
// Key: [TX] + BLOCKHASH + I <- i is the incrementer from the for loop
//Value : TXHASH
key = append(TX, blockhash.Bytes()...)
key = append(key, uint32ToBytes(uint32(i))...)
err = l.Put(key, txhash.Bytes())
if err != nil {
fmt.Println("Error could not add tx index into db")
return err
}
}
return nil
}
// BigEndian
func uint32ToBytes(h uint32) []byte {
a := make([]byte, 4)
binary.BigEndian.PutUint32(a, h)
return a
}