-
Notifications
You must be signed in to change notification settings - Fork 27
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
DPOS example #2
base: master
Are you sure you want to change the base?
DPOS example #2
Changes from 4 commits
448b58f
5a97571
e7af1a4
b0cecf9
a9c9d40
e3af21a
c8f3a26
15158e6
6d2e71a
1eae066
530e749
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,6 +21,10 @@ import ( | |
"gopkg.in/mgo.v2/bson" | ||
) | ||
|
||
const ( | ||
numActiveValidators = 3 | ||
) | ||
|
||
var _ types.Application = (*JSONStoreApplication)(nil) | ||
var db *mgo.Database | ||
|
||
|
@@ -74,6 +78,14 @@ type UserCommentVote struct { | |
CommentID bson.ObjectId `bson:"commentID" json:"commentID"` | ||
} | ||
|
||
// Validator | ||
type Validator struct { | ||
ID bson.ObjectId `bson:"_id" json:"_id"` | ||
Name string `bson:"name" json:"name"` | ||
PublicKey []byte `bson:"publicKey" json:"publicKey"` | ||
Votes []bson.ObjectId `bson:"votes" json:"votes"` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Validator documents can quickly grow in size (MongoDB documents have a 16MB size limit) if we store the ObjectIDs of voters in the same document ( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. as discussed added UserValidatorVote collection |
||
} | ||
|
||
// JSONStoreApplication ... | ||
type JSONStoreApplication struct { | ||
types.BaseApplication | ||
|
@@ -88,7 +100,7 @@ func byteToHex(input []byte) string { | |
} | ||
|
||
func findTotalDocuments(db *mgo.Database) int64 { | ||
collections := [5]string{"posts", "comments", "users", "userpostvotes", "usercommentvotes"} | ||
collections := [6]string{"posts", "comments", "users", "userpostvotes", "usercommentvotes", "validators"} | ||
var sum int64 | ||
|
||
for _, collection := range collections { | ||
|
@@ -235,6 +247,35 @@ func (app *JSONStoreApplication) DeliverTx(tx []byte) types.ResponseDeliverTx { | |
} | ||
|
||
break | ||
|
||
case "upvoteValidator": | ||
entity := body["entity"].(map[string]interface{}) | ||
|
||
// validate user exists | ||
pubKeyBytes, errDecode := base64.StdEncoding.DecodeString(message["publicKey"].(string)) | ||
|
||
if errDecode != nil { | ||
panic(errDecode) | ||
} | ||
|
||
publicKey := strings.ToUpper(byteToHex(pubKeyBytes)) | ||
|
||
var user User | ||
err := db.C("users").Find(bson.M{"publicKey": publicKey}).One(&user) | ||
if err != nil { | ||
panic(err) | ||
} | ||
|
||
fmt.Println("user validated!") | ||
|
||
// validate validator exists & update votes | ||
validatorID := bson.ObjectIdHex(entity["validator"].(string)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is also possible to retrieve validatorID via the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nice. Didn't realise that. Make sense since NodeId is derived the same way There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i got back to this comment now and realised it doesnt work for me.. let's discuss it in the morning |
||
err = db.C("validators").Update(bson.M{"_id": validatorID}, bson.M{"$addToSet": bson.M{"votes": user.ID}}) | ||
if err != nil { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are doing only There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thought of that but I didnt implement it as I wanted to test what I had first and was struggling with that at the end. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've added scenario to downvote validator. |
||
panic(err) | ||
} | ||
fmt.Println("validator validated!") | ||
|
||
case "upvotePost": | ||
entity := body["entity"].(map[string]interface{}) | ||
|
||
|
@@ -446,6 +487,24 @@ func (app *JSONStoreApplication) CheckTx(tx []byte) types.ResponseCheckTx { | |
|
||
// ===== Data Validation ======= | ||
switch body["type"] { | ||
// TODO consider doing more sophisticated validations here like | ||
// checking existance of users and validators here | ||
// assuming tx cannot be tempered with beteen CheckTx and DeliverTx | ||
case "upvoteValidator": | ||
fmt.Println("received upvote start") | ||
entity := body["entity"].(map[string]interface{}) | ||
|
||
if (entity["validator"] == nil) || (bson.IsObjectIdHex(entity["validator"].(string)) != true) { | ||
codeType = code.CodeTypeBadData | ||
break | ||
} | ||
fmt.Println("received upvote here") | ||
if (entity["user"] == nil) || (bson.IsObjectIdHex(entity["user"].(string)) != true) { | ||
codeType = code.CodeTypeBadData | ||
break | ||
} | ||
fmt.Println("received upvote end") | ||
|
||
case "createPost": | ||
entity := body["entity"].(map[string]interface{}) | ||
|
||
|
@@ -524,3 +583,73 @@ func (app *JSONStoreApplication) Commit() types.ResponseCommit { | |
func (app *JSONStoreApplication) Query(reqQuery types.RequestQuery) (resQuery types.ResponseQuery) { | ||
return | ||
} | ||
|
||
func (app *JSONStoreApplication) InitChain(req types.RequestInitChain) types.ResponseInitChain { | ||
fmt.Println("calling InitChain") | ||
validators := req.GetValidators() | ||
var mintValidators []interface{} | ||
if validators != nil { | ||
for _, element := range validators { | ||
validator := Validator{ | ||
ID: bson.NewObjectId(), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. that's a bug. We cannot generate random value for each like that cos it will create different IDs on on every validator node. |
||
Name: "validatorName", | ||
PublicKey: element.GetPubKey(), | ||
Votes: []bson.ObjectId{}, | ||
} | ||
mintValidators = append(mintValidators, validator) | ||
} | ||
dbErr := db.C("validators").Insert(mintValidators...) | ||
if dbErr != nil { | ||
panic(dbErr) | ||
} | ||
} | ||
return types.ResponseInitChain{} | ||
} | ||
|
||
func (app *JSONStoreApplication) EndBlock(req types.RequestEndBlock) types.ResponseEndBlock { | ||
// TODO below solution needs confirmation through testing on multiple nodes. | ||
// according to documentation "To add a new validator or update an existing one, | ||
// simply include them in the list returned in the EndBlock response. | ||
// To remove one, include it in the list with a power equal to 0." | ||
// That means below solution may not be removing any validators atm! | ||
|
||
// TODO I've noticed that the order of elements with the same vote value is not nondeterministic | ||
// which means last active can be swapped with first standby potentially on every query | ||
// that could be considered an issue depending on requirements | ||
project := bson.M{ | ||
"$project": bson.M{ | ||
"name": 1, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We don't have to use aggregation if we just maintain another property called There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. good point. Could have added "increment" and new field There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. added vote count as a part of adding extra collection |
||
"publicKey": 1, | ||
"votes": bson.M{"$size": "$votes"}, | ||
}, | ||
} | ||
sort := bson.M{ | ||
"$sort": bson.M{ | ||
"votes": -1, | ||
}, | ||
} | ||
limit := bson.M{ | ||
"$limit": numActiveValidators, | ||
} | ||
|
||
iter := db.C("validators").Pipe([]bson.M{project, sort, limit}).Iter() | ||
defer iter.Close() | ||
|
||
var tdValidators []types.Validator | ||
|
||
var dbResult bson.M | ||
for iter.Next(&dbResult) { | ||
// fmt.Println(dbResult) | ||
validator := types.Validator{ | ||
PubKey: dbResult["publicKey"].([]byte), | ||
Power: 10, | ||
} | ||
tdValidators = append(tdValidators, validator) | ||
} | ||
if iter.Err() != nil { | ||
panic(iter.Err()) | ||
} | ||
fmt.Println(tdValidators) | ||
|
||
return types.ResponseEndBlock{ValidatorUpdates: tdValidators} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,10 @@ | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"mint/jsonstore" | ||
"os" | ||
"strconv" | ||
|
||
"github.com/tendermint/abci/server" | ||
"github.com/tendermint/abci/types" | ||
|
@@ -22,14 +24,16 @@ func initJSONStore() error { | |
// Create the application | ||
var app types.Application | ||
|
||
session, err := mgo.Dial("localhost") | ||
fmt.Println("running aginst mongo: ", os.Getenv("MONGO_URL")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it uses localhost:27017 but tbh its not obvious from the client library code... When I added it and run it just still worked which surprised me too. (unless there is another bug I missed ;) ) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so turned out i was wrong and it doesn't default to localhost:27017.. must have forgotten i've added it. This way or the other im removing it as well as removing override for the ABCI port. Since you may be merging it there is no point in me forcing code basically added for testing |
||
session, err := mgo.Dial(os.Getenv("MONGO_URL")) | ||
if err != nil { | ||
panic(err) | ||
} | ||
db := session.DB("tendermintdb") | ||
|
||
// Clean the DB on each reboot | ||
collections := [5]string{"posts", "comments", "users", "userpostvotes", "usercommentvotes"} | ||
collections := [6]string{"posts", "comments", "users", "userpostvotes", "usercommentvotes", "validators"} | ||
// collections := [6]string{"posts", "comments", "users", "userpostvotes", "usercommentvotes"} | ||
|
||
for _, collection := range collections { | ||
db.C(collection).RemoveAll(nil) | ||
|
@@ -38,7 +42,16 @@ func initJSONStore() error { | |
app = jsonstore.NewJSONStoreApplication(db) | ||
|
||
// Start the listener | ||
srv, err := server.NewServer("tcp://0.0.0.0:46658", "socket", app) | ||
port := 46658 | ||
if os.Args[1] != "" { | ||
port, err = strconv.Atoi(os.Args[1]) | ||
if err != nil { | ||
panic(err) | ||
} | ||
} | ||
fmt.Println(os.Args[1:]) | ||
fmt.Println(port) | ||
srv, err := server.NewServer(fmt.Sprintf("tcp://0.0.0.0:%d", port), "socket", app) | ||
if err != nil { | ||
return err | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we set it to at least
4
? so that we can test out the byzantine fault tolerance. Tendermint will continue to produce blocks as long as more than 2/3 of validators are non-malicious.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes you are right, that was originally 4 but I've started decreasing it when I struggled to set up nodes locally.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed