Skip to content

Instantly share code, notes, and snippets.

@wolfposd
Created October 10, 2016 15:45
Show Gist options
  • Save wolfposd/685753e3f4779a9ffd69463e43613e1a to your computer and use it in GitHub Desktop.
Save wolfposd/685753e3f4779a9ffd69463e43613e1a to your computer and use it in GitHub Desktop.
Drop-in MongoDB replacement for LevelDB in Tendermint
/*
* Copyright (c) 2016 wolfposd
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// NOTES:
// edit node.go:
// line 389+390
// line 59+60
// uncomment blockstoreDB
// remove argument from bc.NewBlockstore()
package blockchain
import (
"io"
. "github.com/tendermint/go-common"
"github.com/tendermint/tendermint/types"
"gopkg.in/mgo.v2"
"gopkg.in/mgo.v2/bson"
)
type BlockStore struct {
session *mgo.Session
db *mgo.Database
height int
}
const MongoDBDatabase = "tendermint"
const DocumentBlock = "block"
const DocumentPart = "part"
const DocumentBlockMeta = "blockmeta"
const DocumentCommit = "commit"
const DocumentSeenCommit = "seencommit"
func NewBlockStore() *BlockStore {
sess, err := mgo.Dial("localhost")
if err != nil {
panic(err)
}
dbi := sess.DB(MongoDBDatabase)
return &BlockStore{
session: sess,
db: dbi,
height: 1,
}
}
func (m *BlockStore) Height() int {
return m.height
}
func (m *BlockStore) GetReader(key []byte) io.Reader {
return nil
}
func (m *BlockStore) LoadBlock(height int) *types.Block {
result := &types.Block{}
err := m.db.C(DocumentBlock).Find(bson.M{"header.height": height}).One(&result)
if err != nil {
log.Error("Got an error loading block:", err.Error())
return nil
} else {
return result
}
}
func (m *BlockStore) LoadBlockPart(height int, index int) *types.Part {
result := &types.Part{}
err := m.db.C(DocumentPart).Find(bson.M{"height": height, "index": index}).One(&result)
if err != nil {
log.Error("got an error loading blockpart:", err.Error())
return nil
} else {
return result
}
}
func (m *BlockStore) LoadBlockMeta(height int) *types.BlockMeta {
result := &types.BlockMeta{}
err := m.db.C(DocumentBlockMeta).Find(bson.M{"header.height": height}).One(&result)
if err != nil {
log.Error("got an error loading meta:", err.Error())
return nil
} else {
return result
}
}
func (m *BlockStore) LoadBlockCommit(height int) *types.Commit {
result := &types.Commit{}
// TODO THIS DOESNT WORK YET
// query should be like: "this.precommits[0].height" : height
err := m.db.C(DocumentCommit).Find(bson.M{"height": height}).One(&result)
if err != nil {
log.Error("Failed to load block", "error", err.Error())
return nil
} else {
return result
}
}
func (m *BlockStore) LoadSeenCommit(height int) *types.Commit {
result := &types.Commit{}
// TODO THIS DOESNT WORK YET
// query should be like: "this.precommits[0].height" : height
err := m.db.C(DocumentSeenCommit).Find(bson.M{"height": height}).One(&result)
if err != nil {
log.Error("Failed to load block", "error", err.Error())
return nil
} else {
return result
}
}
func (m *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenCommit *types.Commit) {
height := block.Height
if height != m.height+1 {
PanicSanity(Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", m.height+1, height))
}
if !blockParts.IsComplete() {
PanicSanity(Fmt("BlockStore can only save complete block part sets"))
}
log.Info("Trying to write block")
err := m.db.C(DocumentBlock).Insert(block)
if err != nil {
log.Error("Failed to save block", "error", err.Error())
}
meta := types.NewBlockMeta(block, blockParts)
err = m.db.C(DocumentBlockMeta).Insert(meta);
if err != nil {
log.Error("Failed to save block Meta", "error", err.Error())
}
for i := 0; i < blockParts.Total(); i++ {
m.saveBlockPart(height, i, blockParts.GetPart(i))
}
err = m.db.C(DocumentCommit).Insert(block.LastCommit)
if err != nil {
log.Error("Failed to save Commit", "error", err.Error())
}
err = m.db.C(DocumentSeenCommit).Insert(seenCommit)
if err != nil {
log.Error("Failed to save Seen Commit", "error", err.Error())
}
m.height++
}
func (m *BlockStore) saveBlockPart(height int, index int, part *types.Part) {
err := m.db.C(DocumentPart).Insert(bson.M{"height":height, "index":index, "part":part})
if err != nil {
log.Error("Failed to save block part", "error", err.Error())
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment