commit
900beb243b
9
Makefile
9
Makefile
|
@ -1,6 +1,11 @@
|
||||||
.PHONY: get_deps build all list_deps
|
.PHONY: get_deps build all list_deps install
|
||||||
|
|
||||||
all: build
|
all: install
|
||||||
|
|
||||||
|
install:
|
||||||
|
go install github.com/tendermint/tendermint/cmd/tendermint
|
||||||
|
go install github.com/tendermint/tendermint/cmd/barak
|
||||||
|
go install github.com/tendermint/tendermint/cmd/debora
|
||||||
|
|
||||||
build:
|
build:
|
||||||
go build -o build/tendermint github.com/tendermint/tendermint/cmd/tendermint
|
go build -o build/tendermint github.com/tendermint/tendermint/cmd/tendermint
|
||||||
|
|
|
@ -38,8 +38,8 @@ func HashSignBytes(chainID string, o Signable) []byte {
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Address []byte `json:"address"`
|
Address []byte `json:"address"`
|
||||||
PubKey PubKey `json:"pub_key"`
|
PubKey PubKey `json:"pub_key"`
|
||||||
Sequence uint `json:"sequence"`
|
Sequence int `json:"sequence"`
|
||||||
Balance uint64 `json:"balance"`
|
Balance int64 `json:"balance"`
|
||||||
Code []byte `json:"code"` // VM code
|
Code []byte `json:"code"` // VM code
|
||||||
StorageRoot []byte `json:"storage_root"` // VM storage merkle root.
|
StorageRoot []byte `json:"storage_root"` // VM storage merkle root.
|
||||||
}
|
}
|
||||||
|
|
|
@ -78,7 +78,7 @@ WriteBinary(foo, buf, n, err)
|
||||||
foo2 := ReadBinary(Foo{}, buf, n, err).(Foo)
|
foo2 := ReadBinary(Foo{}, buf, n, err).(Foo)
|
||||||
|
|
||||||
// Or, to decode onto a pointer:
|
// Or, to decode onto a pointer:
|
||||||
foo2 := ReadBinary(&Foo{}, buf, n, err).(*Foo)
|
foo2 := ReadBinaryPtr(&Foo{}, buf, n, err).(*Foo)
|
||||||
```
|
```
|
||||||
|
|
||||||
WriteBinary and ReadBinary can encode/decode structs recursively. However, interface field
|
WriteBinary and ReadBinary can encode/decode structs recursively. However, interface field
|
||||||
|
|
|
@ -9,7 +9,7 @@ import (
|
||||||
func ReadBinary(o interface{}, r io.Reader, n *int64, err *error) interface{} {
|
func ReadBinary(o interface{}, r io.Reader, n *int64, err *error) interface{} {
|
||||||
rv, rt := reflect.ValueOf(o), reflect.TypeOf(o)
|
rv, rt := reflect.ValueOf(o), reflect.TypeOf(o)
|
||||||
if rv.Kind() == reflect.Ptr {
|
if rv.Kind() == reflect.Ptr {
|
||||||
readReflectBinary(rv.Elem(), rt.Elem(), Options{}, r, n, err)
|
readReflectBinary(rv, rt, Options{}, r, n, err)
|
||||||
return o
|
return o
|
||||||
} else {
|
} else {
|
||||||
ptrRv := reflect.New(rt)
|
ptrRv := reflect.New(rt)
|
||||||
|
@ -18,12 +18,19 @@ func ReadBinary(o interface{}, r io.Reader, n *int64, err *error) interface{} {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ReadBinaryPtr(o interface{}, r io.Reader, n *int64, err *error) interface{} {
|
||||||
|
rv, rt := reflect.ValueOf(o), reflect.TypeOf(o)
|
||||||
|
if rv.Kind() == reflect.Ptr {
|
||||||
|
readReflectBinary(rv.Elem(), rt.Elem(), Options{}, r, n, err)
|
||||||
|
return o
|
||||||
|
} else {
|
||||||
|
panic("ReadBinaryPtr expects o to be a pointer")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func WriteBinary(o interface{}, w io.Writer, n *int64, err *error) {
|
func WriteBinary(o interface{}, w io.Writer, n *int64, err *error) {
|
||||||
rv := reflect.ValueOf(o)
|
rv := reflect.ValueOf(o)
|
||||||
rt := reflect.TypeOf(o)
|
rt := reflect.TypeOf(o)
|
||||||
if rv.Kind() == reflect.Ptr {
|
|
||||||
rv, rt = rv.Elem(), rt.Elem()
|
|
||||||
}
|
|
||||||
writeReflectBinary(rv, rt, Options{}, w, n, err)
|
writeReflectBinary(rv, rt, Options{}, w, n, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,12 +10,12 @@ const (
|
||||||
)
|
)
|
||||||
|
|
||||||
func WriteByteSlice(bz []byte, w io.Writer, n *int64, err *error) {
|
func WriteByteSlice(bz []byte, w io.Writer, n *int64, err *error) {
|
||||||
WriteUvarint(uint(len(bz)), w, n, err)
|
WriteVarint(len(bz), w, n, err)
|
||||||
WriteTo(bz, w, n, err)
|
WriteTo(bz, w, n, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadByteSlice(r io.Reader, n *int64, err *error) []byte {
|
func ReadByteSlice(r io.Reader, n *int64, err *error) []byte {
|
||||||
length := int(ReadUvarint(r, n, err))
|
length := ReadVarint(r, n, err)
|
||||||
if *err != nil {
|
if *err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func ReadByteSlice(r io.Reader, n *int64, err *error) []byte {
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
func WriteByteSlices(bzz [][]byte, w io.Writer, n *int64, err *error) {
|
func WriteByteSlices(bzz [][]byte, w io.Writer, n *int64, err *error) {
|
||||||
WriteUvarint(uint(len(bzz)), w, n, err)
|
WriteVarint(len(bzz), w, n, err)
|
||||||
for _, bz := range bzz {
|
for _, bz := range bzz {
|
||||||
WriteByteSlice(bz, w, n, err)
|
WriteByteSlice(bz, w, n, err)
|
||||||
if *err != nil {
|
if *err != nil {
|
||||||
|
@ -46,7 +46,7 @@ func WriteByteSlices(bzz [][]byte, w io.Writer, n *int64, err *error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadByteSlices(r io.Reader, n *int64, err *error) [][]byte {
|
func ReadByteSlices(r io.Reader, n *int64, err *error) [][]byte {
|
||||||
length := int(ReadUvarint(r, n, err))
|
length := ReadVarint(r, n, err)
|
||||||
if *err != nil {
|
if *err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,8 +158,7 @@ func ReadUint64(r io.Reader, n *int64, err *error) uint64 {
|
||||||
|
|
||||||
// Varint
|
// Varint
|
||||||
|
|
||||||
func uvarintSize(i_ uint) int {
|
func uvarintSize(i uint64) int {
|
||||||
i := uint64(i_)
|
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -193,7 +192,7 @@ func WriteVarint(i int, w io.Writer, n *int64, err *error) {
|
||||||
negate = true
|
negate = true
|
||||||
i = -i
|
i = -i
|
||||||
}
|
}
|
||||||
var size = uvarintSize(uint(i))
|
var size = uvarintSize(uint64(i))
|
||||||
if negate {
|
if negate {
|
||||||
// e.g. 0xF1 for a single negative byte
|
// e.g. 0xF1 for a single negative byte
|
||||||
WriteUint8(uint8(size+0xF0), w, n, err)
|
WriteUint8(uint8(size+0xF0), w, n, err)
|
||||||
|
@ -220,6 +219,9 @@ func ReadVarint(r io.Reader, n *int64, err *error) int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
if size == 0 {
|
if size == 0 {
|
||||||
|
if negate {
|
||||||
|
setFirstErr(err, errors.New("Varint does not allow negative zero"))
|
||||||
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
buf := make([]byte, 8)
|
buf := make([]byte, 8)
|
||||||
|
@ -236,7 +238,7 @@ func ReadVarint(r io.Reader, n *int64, err *error) int {
|
||||||
// Uvarint
|
// Uvarint
|
||||||
|
|
||||||
func WriteUvarint(i uint, w io.Writer, n *int64, err *error) {
|
func WriteUvarint(i uint, w io.Writer, n *int64, err *error) {
|
||||||
var size = uvarintSize(i)
|
var size = uvarintSize(uint64(i))
|
||||||
WriteUint8(uint8(size), w, n, err)
|
WriteUint8(uint8(size), w, n, err)
|
||||||
if size > 0 {
|
if size > 0 {
|
||||||
buf := make([]byte, 8)
|
buf := make([]byte, 8)
|
||||||
|
|
|
@ -226,6 +226,9 @@ func readReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, r io.Rea
|
||||||
typeInfo = GetTypeInfo(rt)
|
typeInfo = GetTypeInfo(rt)
|
||||||
if typeInfo.Byte != 0x00 {
|
if typeInfo.Byte != 0x00 {
|
||||||
r = NewPrefixedReader([]byte{typeByte}, r)
|
r = NewPrefixedReader([]byte{typeByte}, r)
|
||||||
|
} else if typeByte != 0x01 {
|
||||||
|
*err = errors.New(Fmt("Unexpected type byte %X for ptr of untyped thing", typeByte))
|
||||||
|
return
|
||||||
}
|
}
|
||||||
// continue...
|
// continue...
|
||||||
}
|
}
|
||||||
|
@ -250,7 +253,7 @@ func readReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, r io.Rea
|
||||||
} else {
|
} else {
|
||||||
var sliceRv reflect.Value
|
var sliceRv reflect.Value
|
||||||
// Read length
|
// Read length
|
||||||
length := int(ReadUvarint(r, n, err))
|
length := ReadVarint(r, n, err)
|
||||||
log.Debug(Fmt("Read length: %v", length))
|
log.Debug(Fmt("Read length: %v", length))
|
||||||
sliceRv = reflect.MakeSlice(rt, 0, 0)
|
sliceRv = reflect.MakeSlice(rt, 0, 0)
|
||||||
// read one ReflectSliceChunk at a time and append
|
// read one ReflectSliceChunk at a time and append
|
||||||
|
@ -322,7 +325,7 @@ func readReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, r io.Rea
|
||||||
|
|
||||||
case reflect.Uint64:
|
case reflect.Uint64:
|
||||||
if opts.Varint {
|
if opts.Varint {
|
||||||
num := ReadUvarint(r, n, err)
|
num := ReadVarint(r, n, err)
|
||||||
log.Debug(Fmt("Read num: %v", num))
|
log.Debug(Fmt("Read num: %v", num))
|
||||||
rv.SetUint(uint64(num))
|
rv.SetUint(uint64(num))
|
||||||
} else {
|
} else {
|
||||||
|
@ -347,7 +350,7 @@ func readReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, r io.Rea
|
||||||
rv.SetUint(uint64(num))
|
rv.SetUint(uint64(num))
|
||||||
|
|
||||||
case reflect.Uint:
|
case reflect.Uint:
|
||||||
num := ReadUvarint(r, n, err)
|
num := ReadVarint(r, n, err)
|
||||||
log.Debug(Fmt("Read num: %v", num))
|
log.Debug(Fmt("Read num: %v", num))
|
||||||
rv.SetUint(uint64(num))
|
rv.SetUint(uint64(num))
|
||||||
|
|
||||||
|
@ -432,7 +435,7 @@ func writeReflectBinary(rv reflect.Value, rt reflect.Type, opts Options, w io.Wr
|
||||||
} else {
|
} else {
|
||||||
// Write length
|
// Write length
|
||||||
length := rv.Len()
|
length := rv.Len()
|
||||||
WriteUvarint(uint(length), w, n, err)
|
WriteVarint(length, w, n, err)
|
||||||
// Write elems
|
// Write elems
|
||||||
for i := 0; i < length; i++ {
|
for i := 0; i < length; i++ {
|
||||||
elemRv := rv.Index(i)
|
elemRv := rv.Index(i)
|
||||||
|
|
|
@ -72,13 +72,14 @@ func TestAnimalInterface(t *testing.T) {
|
||||||
ptr := reflect.New(rte).Interface()
|
ptr := reflect.New(rte).Interface()
|
||||||
fmt.Printf("ptr: %v", ptr)
|
fmt.Printf("ptr: %v", ptr)
|
||||||
|
|
||||||
// Make a binary byteslice that represents a snake.
|
// Make a binary byteslice that represents a *snake.
|
||||||
snakeBytes := BinaryBytes(Snake([]byte("snake")))
|
foo = Snake([]byte("snake"))
|
||||||
|
snakeBytes := BinaryBytes(foo)
|
||||||
snakeReader := bytes.NewReader(snakeBytes)
|
snakeReader := bytes.NewReader(snakeBytes)
|
||||||
|
|
||||||
// Now you can read it.
|
// Now you can read it.
|
||||||
n, err := new(int64), new(error)
|
n, err := new(int64), new(error)
|
||||||
it := *ReadBinary(ptr, snakeReader, n, err).(*Animal)
|
it := ReadBinary(foo, snakeReader, n, err).(Animal)
|
||||||
fmt.Println(it, reflect.TypeOf(it))
|
fmt.Println(it, reflect.TypeOf(it))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -374,7 +375,7 @@ func TestBinary(t *testing.T) {
|
||||||
|
|
||||||
// Read onto a pointer
|
// Read onto a pointer
|
||||||
n, err = new(int64), new(error)
|
n, err = new(int64), new(error)
|
||||||
res = ReadBinary(instancePtr, bytes.NewReader(data), n, err)
|
res = ReadBinaryPtr(instancePtr, bytes.NewReader(data), n, err)
|
||||||
if *err != nil {
|
if *err != nil {
|
||||||
t.Fatalf("Failed to read into instance: %v", *err)
|
t.Fatalf("Failed to read into instance: %v", *err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,16 @@ import "io"
|
||||||
// String
|
// String
|
||||||
|
|
||||||
func WriteString(s string, w io.Writer, n *int64, err *error) {
|
func WriteString(s string, w io.Writer, n *int64, err *error) {
|
||||||
WriteUvarint(uint(len(s)), w, n, err)
|
WriteVarint(len(s), w, n, err)
|
||||||
WriteTo([]byte(s), w, n, err)
|
WriteTo([]byte(s), w, n, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadString(r io.Reader, n *int64, err *error) string {
|
func ReadString(r io.Reader, n *int64, err *error) string {
|
||||||
length := ReadUvarint(r, n, err)
|
length := ReadVarint(r, n, err)
|
||||||
if *err != nil {
|
if *err != nil {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
buf := make([]byte, int(length))
|
buf := make([]byte, length)
|
||||||
ReadFull(buf, r, n, err)
|
ReadFull(buf, r, n, err)
|
||||||
return string(buf)
|
return string(buf)
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,8 +36,8 @@ var (
|
||||||
type BlockPool struct {
|
type BlockPool struct {
|
||||||
// block requests
|
// block requests
|
||||||
requestsMtx sync.Mutex
|
requestsMtx sync.Mutex
|
||||||
requests map[uint]*bpRequest
|
requests map[int]*bpRequest
|
||||||
height uint // the lowest key in requests.
|
height int // the lowest key in requests.
|
||||||
numUnassigned int32 // number of requests not yet assigned to a peer
|
numUnassigned int32 // number of requests not yet assigned to a peer
|
||||||
numPending int32 // number of requests pending assignment or block response
|
numPending int32 // number of requests pending assignment or block response
|
||||||
|
|
||||||
|
@ -52,11 +52,11 @@ type BlockPool struct {
|
||||||
running int32 // atomic
|
running int32 // atomic
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockPool(start uint, requestsCh chan<- BlockRequest, timeoutsCh chan<- string) *BlockPool {
|
func NewBlockPool(start int, requestsCh chan<- BlockRequest, timeoutsCh chan<- string) *BlockPool {
|
||||||
return &BlockPool{
|
return &BlockPool{
|
||||||
peers: make(map[string]*bpPeer),
|
peers: make(map[string]*bpPeer),
|
||||||
|
|
||||||
requests: make(map[uint]*bpRequest),
|
requests: make(map[int]*bpRequest),
|
||||||
height: start,
|
height: start,
|
||||||
numUnassigned: 0,
|
numUnassigned: 0,
|
||||||
numPending: 0,
|
numPending: 0,
|
||||||
|
@ -108,7 +108,7 @@ RUN_LOOP:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *BlockPool) GetStatus() (uint, int32) {
|
func (pool *BlockPool) GetStatus() (int, int32) {
|
||||||
pool.requestsMtx.Lock() // Lock
|
pool.requestsMtx.Lock() // Lock
|
||||||
defer pool.requestsMtx.Unlock()
|
defer pool.requestsMtx.Unlock()
|
||||||
|
|
||||||
|
@ -146,7 +146,7 @@ func (pool *BlockPool) PopRequest() {
|
||||||
|
|
||||||
// Invalidates the block at pool.height.
|
// Invalidates the block at pool.height.
|
||||||
// Remove the peer and request from others.
|
// Remove the peer and request from others.
|
||||||
func (pool *BlockPool) RedoRequest(height uint) {
|
func (pool *BlockPool) RedoRequest(height int) {
|
||||||
pool.requestsMtx.Lock() // Lock
|
pool.requestsMtx.Lock() // Lock
|
||||||
defer pool.requestsMtx.Unlock()
|
defer pool.requestsMtx.Unlock()
|
||||||
|
|
||||||
|
@ -165,7 +165,7 @@ func (pool *BlockPool) RedoRequest(height uint) {
|
||||||
go requestRoutine(pool, height)
|
go requestRoutine(pool, height)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *BlockPool) hasBlock(height uint) bool {
|
func (pool *BlockPool) hasBlock(height int) bool {
|
||||||
pool.requestsMtx.Lock() // Lock
|
pool.requestsMtx.Lock() // Lock
|
||||||
defer pool.requestsMtx.Unlock()
|
defer pool.requestsMtx.Unlock()
|
||||||
|
|
||||||
|
@ -173,7 +173,7 @@ func (pool *BlockPool) hasBlock(height uint) bool {
|
||||||
return request != nil && request.block != nil
|
return request != nil && request.block != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *BlockPool) setPeerForRequest(height uint, peerId string) {
|
func (pool *BlockPool) setPeerForRequest(height int, peerId string) {
|
||||||
pool.requestsMtx.Lock() // Lock
|
pool.requestsMtx.Lock() // Lock
|
||||||
defer pool.requestsMtx.Unlock()
|
defer pool.requestsMtx.Unlock()
|
||||||
|
|
||||||
|
@ -185,7 +185,7 @@ func (pool *BlockPool) setPeerForRequest(height uint, peerId string) {
|
||||||
request.peerId = peerId
|
request.peerId = peerId
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *BlockPool) removePeerForRequest(height uint, peerId string) {
|
func (pool *BlockPool) removePeerForRequest(height int, peerId string) {
|
||||||
pool.requestsMtx.Lock() // Lock
|
pool.requestsMtx.Lock() // Lock
|
||||||
defer pool.requestsMtx.Unlock()
|
defer pool.requestsMtx.Unlock()
|
||||||
|
|
||||||
|
@ -224,7 +224,7 @@ func (pool *BlockPool) getPeer(peerId string) *bpPeer {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sets the peer's alleged blockchain height.
|
// Sets the peer's alleged blockchain height.
|
||||||
func (pool *BlockPool) SetPeerHeight(peerId string, height uint) {
|
func (pool *BlockPool) SetPeerHeight(peerId string, height int) {
|
||||||
pool.peersMtx.Lock() // Lock
|
pool.peersMtx.Lock() // Lock
|
||||||
defer pool.peersMtx.Unlock()
|
defer pool.peersMtx.Unlock()
|
||||||
|
|
||||||
|
@ -250,7 +250,7 @@ func (pool *BlockPool) RemovePeer(peerId string) {
|
||||||
|
|
||||||
// Pick an available peer with at least the given minHeight.
|
// Pick an available peer with at least the given minHeight.
|
||||||
// If no peers are available, returns nil.
|
// If no peers are available, returns nil.
|
||||||
func (pool *BlockPool) pickIncrAvailablePeer(minHeight uint) *bpPeer {
|
func (pool *BlockPool) pickIncrAvailablePeer(minHeight int) *bpPeer {
|
||||||
pool.peersMtx.Lock()
|
pool.peersMtx.Lock()
|
||||||
defer pool.peersMtx.Unlock()
|
defer pool.peersMtx.Unlock()
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ func (pool *BlockPool) makeNextRequest() {
|
||||||
pool.requestsMtx.Lock() // Lock
|
pool.requestsMtx.Lock() // Lock
|
||||||
defer pool.requestsMtx.Unlock()
|
defer pool.requestsMtx.Unlock()
|
||||||
|
|
||||||
nextHeight := pool.height + uint(len(pool.requests))
|
nextHeight := pool.height + len(pool.requests)
|
||||||
request := &bpRequest{
|
request := &bpRequest{
|
||||||
height: nextHeight,
|
height: nextHeight,
|
||||||
peerId: "",
|
peerId: "",
|
||||||
|
@ -296,7 +296,7 @@ func (pool *BlockPool) makeNextRequest() {
|
||||||
go requestRoutine(pool, nextHeight)
|
go requestRoutine(pool, nextHeight)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (pool *BlockPool) sendRequest(height uint, peerId string) {
|
func (pool *BlockPool) sendRequest(height int, peerId string) {
|
||||||
if atomic.LoadInt32(&pool.running) == 0 {
|
if atomic.LoadInt32(&pool.running) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -315,7 +315,7 @@ func (pool *BlockPool) debug() string {
|
||||||
defer pool.requestsMtx.Unlock()
|
defer pool.requestsMtx.Unlock()
|
||||||
|
|
||||||
str := ""
|
str := ""
|
||||||
for h := pool.height; h < pool.height+uint(len(pool.requests)); h++ {
|
for h := pool.height; h < pool.height+len(pool.requests); h++ {
|
||||||
if pool.requests[h] == nil {
|
if pool.requests[h] == nil {
|
||||||
str += Fmt("H(%v):X ", h)
|
str += Fmt("H(%v):X ", h)
|
||||||
} else {
|
} else {
|
||||||
|
@ -330,12 +330,12 @@ func (pool *BlockPool) debug() string {
|
||||||
|
|
||||||
type bpPeer struct {
|
type bpPeer struct {
|
||||||
id string
|
id string
|
||||||
height uint
|
height int
|
||||||
numRequests int32
|
numRequests int32
|
||||||
}
|
}
|
||||||
|
|
||||||
type bpRequest struct {
|
type bpRequest struct {
|
||||||
height uint
|
height int
|
||||||
peerId string
|
peerId string
|
||||||
block *types.Block
|
block *types.Block
|
||||||
}
|
}
|
||||||
|
@ -344,7 +344,7 @@ type bpRequest struct {
|
||||||
|
|
||||||
// Responsible for making more requests as necessary
|
// Responsible for making more requests as necessary
|
||||||
// Returns only when a block is found (e.g. AddBlock() is called)
|
// Returns only when a block is found (e.g. AddBlock() is called)
|
||||||
func requestRoutine(pool *BlockPool, height uint) {
|
func requestRoutine(pool *BlockPool, height int) {
|
||||||
for {
|
for {
|
||||||
var peer *bpPeer = nil
|
var peer *bpPeer = nil
|
||||||
PICK_LOOP:
|
PICK_LOOP:
|
||||||
|
@ -393,6 +393,6 @@ func requestRoutine(pool *BlockPool, height uint) {
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
type BlockRequest struct {
|
type BlockRequest struct {
|
||||||
Height uint
|
Height int
|
||||||
PeerId string
|
PeerId string
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,14 +11,14 @@ import (
|
||||||
|
|
||||||
type testPeer struct {
|
type testPeer struct {
|
||||||
id string
|
id string
|
||||||
height uint
|
height int
|
||||||
}
|
}
|
||||||
|
|
||||||
func makePeers(numPeers int, minHeight, maxHeight uint) map[string]testPeer {
|
func makePeers(numPeers int, minHeight, maxHeight int) map[string]testPeer {
|
||||||
peers := make(map[string]testPeer, numPeers)
|
peers := make(map[string]testPeer, numPeers)
|
||||||
for i := 0; i < numPeers; i++ {
|
for i := 0; i < numPeers; i++ {
|
||||||
peerId := RandStr(12)
|
peerId := RandStr(12)
|
||||||
height := minHeight + uint(rand.Intn(int(maxHeight-minHeight)))
|
height := minHeight + rand.Intn(maxHeight-minHeight)
|
||||||
peers[peerId] = testPeer{peerId, height}
|
peers[peerId] = testPeer{peerId, height}
|
||||||
}
|
}
|
||||||
return peers
|
return peers
|
||||||
|
@ -26,7 +26,7 @@ func makePeers(numPeers int, minHeight, maxHeight uint) map[string]testPeer {
|
||||||
|
|
||||||
func TestBasic(t *testing.T) {
|
func TestBasic(t *testing.T) {
|
||||||
peers := makePeers(10, 0, 1000)
|
peers := makePeers(10, 0, 1000)
|
||||||
start := uint(42)
|
start := 42
|
||||||
timeoutsCh := make(chan string, 100)
|
timeoutsCh := make(chan string, 100)
|
||||||
requestsCh := make(chan BlockRequest, 100)
|
requestsCh := make(chan BlockRequest, 100)
|
||||||
pool := NewBlockPool(start, requestsCh, timeoutsCh)
|
pool := NewBlockPool(start, requestsCh, timeoutsCh)
|
||||||
|
@ -78,7 +78,7 @@ func TestBasic(t *testing.T) {
|
||||||
|
|
||||||
func TestTimeout(t *testing.T) {
|
func TestTimeout(t *testing.T) {
|
||||||
peers := makePeers(10, 0, 1000)
|
peers := makePeers(10, 0, 1000)
|
||||||
start := uint(42)
|
start := 42
|
||||||
timeoutsCh := make(chan string, 100)
|
timeoutsCh := make(chan string, 100)
|
||||||
requestsCh := make(chan BlockRequest, 100)
|
requestsCh := make(chan BlockRequest, 100)
|
||||||
pool := NewBlockPool(start, requestsCh, timeoutsCh)
|
pool := NewBlockPool(start, requestsCh, timeoutsCh)
|
||||||
|
|
|
@ -232,7 +232,7 @@ FOR_LOOP:
|
||||||
firstPartsHeader := firstParts.Header()
|
firstPartsHeader := firstParts.Header()
|
||||||
// Finally, verify the first block using the second's validation.
|
// Finally, verify the first block using the second's validation.
|
||||||
err := bcR.state.BondedValidators.VerifyValidation(
|
err := bcR.state.BondedValidators.VerifyValidation(
|
||||||
bcR.state.ChainID, first.Hash(), firstPartsHeader, first.Height, second.Validation)
|
bcR.state.ChainID, first.Hash(), firstPartsHeader, first.Height, second.LastValidation)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Debug("error in validation", "error", err)
|
log.Debug("error in validation", "error", err)
|
||||||
bcR.pool.RedoRequest(first.Height)
|
bcR.pool.RedoRequest(first.Height)
|
||||||
|
@ -244,7 +244,7 @@ FOR_LOOP:
|
||||||
// TODO This is bad, are we zombie?
|
// TODO This is bad, are we zombie?
|
||||||
panic(Fmt("Failed to process committed block: %v", err))
|
panic(Fmt("Failed to process committed block: %v", err))
|
||||||
}
|
}
|
||||||
bcR.store.SaveBlock(first, firstParts, second.Validation)
|
bcR.store.SaveBlock(first, firstParts, second.LastValidation)
|
||||||
bcR.state.Save()
|
bcR.state.Save()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,7 +301,7 @@ func DecodeMessage(bz []byte) (msgType byte, msg BlockchainMessage, err error) {
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
type bcBlockRequestMessage struct {
|
type bcBlockRequestMessage struct {
|
||||||
Height uint
|
Height int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *bcBlockRequestMessage) String() string {
|
func (m *bcBlockRequestMessage) String() string {
|
||||||
|
@ -321,7 +321,7 @@ func (m *bcBlockResponseMessage) String() string {
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
type bcStatusRequestMessage struct {
|
type bcStatusRequestMessage struct {
|
||||||
Height uint
|
Height int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *bcStatusRequestMessage) String() string {
|
func (m *bcStatusRequestMessage) String() string {
|
||||||
|
@ -331,7 +331,7 @@ func (m *bcStatusRequestMessage) String() string {
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
type bcStatusResponseMessage struct {
|
type bcStatusResponseMessage struct {
|
||||||
Height uint
|
Height int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *bcStatusResponseMessage) String() string {
|
func (m *bcStatusResponseMessage) String() string {
|
||||||
|
|
|
@ -18,14 +18,14 @@ Simple low level store for blocks.
|
||||||
There are three types of information stored:
|
There are three types of information stored:
|
||||||
- BlockMeta: Meta information about each block
|
- BlockMeta: Meta information about each block
|
||||||
- Block part: Parts of each block, aggregated w/ PartSet
|
- Block part: Parts of each block, aggregated w/ PartSet
|
||||||
- Validation: The Validation part of each block, for gossiping commit votes
|
- Validation: The Validation part of each block, for gossiping precommit votes
|
||||||
|
|
||||||
Currently the commit signatures are duplicated in the Block parts as
|
Currently the precommit signatures are duplicated in the Block parts as
|
||||||
well as the Validation. In the future this may change, perhaps by moving
|
well as the Validation. In the future this may change, perhaps by moving
|
||||||
the Validation data outside the Block.
|
the Validation data outside the Block.
|
||||||
*/
|
*/
|
||||||
type BlockStore struct {
|
type BlockStore struct {
|
||||||
height uint
|
height int
|
||||||
db dbm.DB
|
db dbm.DB
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,7 +38,7 @@ func NewBlockStore(db dbm.DB) *BlockStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Height() returns the last known contiguous block height.
|
// Height() returns the last known contiguous block height.
|
||||||
func (bs *BlockStore) Height() uint {
|
func (bs *BlockStore) Height() int {
|
||||||
return bs.height
|
return bs.height
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,7 +50,7 @@ func (bs *BlockStore) GetReader(key []byte) io.Reader {
|
||||||
return bytes.NewReader(bytez)
|
return bytes.NewReader(bytez)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BlockStore) LoadBlock(height uint) *types.Block {
|
func (bs *BlockStore) LoadBlock(height int) *types.Block {
|
||||||
var n int64
|
var n int64
|
||||||
var err error
|
var err error
|
||||||
r := bs.GetReader(calcBlockMetaKey(height))
|
r := bs.GetReader(calcBlockMetaKey(height))
|
||||||
|
@ -62,7 +62,7 @@ func (bs *BlockStore) LoadBlock(height uint) *types.Block {
|
||||||
panic(Fmt("Error reading block meta: %v", err))
|
panic(Fmt("Error reading block meta: %v", err))
|
||||||
}
|
}
|
||||||
bytez := []byte{}
|
bytez := []byte{}
|
||||||
for i := uint(0); i < meta.Parts.Total; i++ {
|
for i := 0; i < meta.PartsHeader.Total; i++ {
|
||||||
part := bs.LoadBlockPart(height, i)
|
part := bs.LoadBlockPart(height, i)
|
||||||
bytez = append(bytez, part.Bytes...)
|
bytez = append(bytez, part.Bytes...)
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,7 @@ func (bs *BlockStore) LoadBlock(height uint) *types.Block {
|
||||||
return block
|
return block
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BlockStore) LoadBlockPart(height uint, index uint) *types.Part {
|
func (bs *BlockStore) LoadBlockPart(height int, index int) *types.Part {
|
||||||
var n int64
|
var n int64
|
||||||
var err error
|
var err error
|
||||||
r := bs.GetReader(calcBlockPartKey(height, index))
|
r := bs.GetReader(calcBlockPartKey(height, index))
|
||||||
|
@ -87,7 +87,7 @@ func (bs *BlockStore) LoadBlockPart(height uint, index uint) *types.Part {
|
||||||
return part
|
return part
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BlockStore) LoadBlockMeta(height uint) *types.BlockMeta {
|
func (bs *BlockStore) LoadBlockMeta(height int) *types.BlockMeta {
|
||||||
var n int64
|
var n int64
|
||||||
var err error
|
var err error
|
||||||
r := bs.GetReader(calcBlockMetaKey(height))
|
r := bs.GetReader(calcBlockMetaKey(height))
|
||||||
|
@ -101,10 +101,9 @@ func (bs *BlockStore) LoadBlockMeta(height uint) *types.BlockMeta {
|
||||||
return meta
|
return meta
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: the Commit-vote heights are for the block at `height-1`
|
// The +2/3 and other Precommit-votes for block at `height`.
|
||||||
// Since these are included in the subsequent block, the height
|
// This Validation comes from block.LastValidation for `height+1`.
|
||||||
// is off by 1.
|
func (bs *BlockStore) LoadBlockValidation(height int) *types.Validation {
|
||||||
func (bs *BlockStore) LoadBlockValidation(height uint) *types.Validation {
|
|
||||||
var n int64
|
var n int64
|
||||||
var err error
|
var err error
|
||||||
r := bs.GetReader(calcBlockValidationKey(height))
|
r := bs.GetReader(calcBlockValidationKey(height))
|
||||||
|
@ -118,8 +117,8 @@ func (bs *BlockStore) LoadBlockValidation(height uint) *types.Validation {
|
||||||
return validation
|
return validation
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: the Commit-vote heights are for the block at `height`
|
// NOTE: the Precommit-vote heights are for the block at `height`
|
||||||
func (bs *BlockStore) LoadSeenValidation(height uint) *types.Validation {
|
func (bs *BlockStore) LoadSeenValidation(height int) *types.Validation {
|
||||||
var n int64
|
var n int64
|
||||||
var err error
|
var err error
|
||||||
r := bs.GetReader(calcSeenValidationKey(height))
|
r := bs.GetReader(calcSeenValidationKey(height))
|
||||||
|
@ -134,12 +133,10 @@ func (bs *BlockStore) LoadSeenValidation(height uint) *types.Validation {
|
||||||
}
|
}
|
||||||
|
|
||||||
// blockParts: Must be parts of the block
|
// blockParts: Must be parts of the block
|
||||||
// seenValidation: The +2/3 commits that were seen which finalized the height.
|
// seenValidation: The +2/3 precommits that were seen which committed at height.
|
||||||
// If all the nodes restart after committing a block,
|
// If all the nodes restart after committing a block,
|
||||||
// we need this to reload the commits to catch-up nodes to the
|
// we need this to reload the precommits to catch-up nodes to the
|
||||||
// most recent height. Otherwise they'd stall at H-1.
|
// most recent height. Otherwise they'd stall at H-1.
|
||||||
// Also good to have to debug consensus issues & punish wrong-signers
|
|
||||||
// whose commits weren't included in the block.
|
|
||||||
func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenValidation *types.Validation) {
|
func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, seenValidation *types.Validation) {
|
||||||
height := block.Height
|
height := block.Height
|
||||||
if height != bs.height+1 {
|
if height != bs.height+1 {
|
||||||
|
@ -155,15 +152,15 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s
|
||||||
bs.db.Set(calcBlockMetaKey(height), metaBytes)
|
bs.db.Set(calcBlockMetaKey(height), metaBytes)
|
||||||
|
|
||||||
// Save block parts
|
// Save block parts
|
||||||
for i := uint(0); i < blockParts.Total(); i++ {
|
for i := 0; i < blockParts.Total(); i++ {
|
||||||
bs.saveBlockPart(height, i, blockParts.GetPart(i))
|
bs.saveBlockPart(height, i, blockParts.GetPart(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save block validation (duplicate and separate from the Block)
|
// Save block validation (duplicate and separate from the Block)
|
||||||
blockValidationBytes := binary.BinaryBytes(block.Validation)
|
blockValidationBytes := binary.BinaryBytes(block.LastValidation)
|
||||||
bs.db.Set(calcBlockValidationKey(height), blockValidationBytes)
|
bs.db.Set(calcBlockValidationKey(height-1), blockValidationBytes)
|
||||||
|
|
||||||
// Save seen validation (seen +2/3 commits)
|
// Save seen validation (seen +2/3 precommits for block)
|
||||||
seenValidationBytes := binary.BinaryBytes(seenValidation)
|
seenValidationBytes := binary.BinaryBytes(seenValidation)
|
||||||
bs.db.Set(calcSeenValidationKey(height), seenValidationBytes)
|
bs.db.Set(calcSeenValidationKey(height), seenValidationBytes)
|
||||||
|
|
||||||
|
@ -174,7 +171,7 @@ func (bs *BlockStore) SaveBlock(block *types.Block, blockParts *types.PartSet, s
|
||||||
bs.height = height
|
bs.height = height
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bs *BlockStore) saveBlockPart(height uint, index uint, part *types.Part) {
|
func (bs *BlockStore) saveBlockPart(height int, index int, part *types.Part) {
|
||||||
if height != bs.height+1 {
|
if height != bs.height+1 {
|
||||||
panic(Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height))
|
panic(Fmt("BlockStore can only save contiguous blocks. Wanted %v, got %v", bs.height+1, height))
|
||||||
}
|
}
|
||||||
|
@ -184,19 +181,19 @@ func (bs *BlockStore) saveBlockPart(height uint, index uint, part *types.Part) {
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
func calcBlockMetaKey(height uint) []byte {
|
func calcBlockMetaKey(height int) []byte {
|
||||||
return []byte(fmt.Sprintf("H:%v", height))
|
return []byte(fmt.Sprintf("H:%v", height))
|
||||||
}
|
}
|
||||||
|
|
||||||
func calcBlockPartKey(height uint, partIndex uint) []byte {
|
func calcBlockPartKey(height int, partIndex int) []byte {
|
||||||
return []byte(fmt.Sprintf("P:%v:%v", height, partIndex))
|
return []byte(fmt.Sprintf("P:%v:%v", height, partIndex))
|
||||||
}
|
}
|
||||||
|
|
||||||
func calcBlockValidationKey(height uint) []byte {
|
func calcBlockValidationKey(height int) []byte {
|
||||||
return []byte(fmt.Sprintf("V:%v", height))
|
return []byte(fmt.Sprintf("V:%v", height))
|
||||||
}
|
}
|
||||||
|
|
||||||
func calcSeenValidationKey(height uint) []byte {
|
func calcSeenValidationKey(height int) []byte {
|
||||||
return []byte(fmt.Sprintf("SV:%v", height))
|
return []byte(fmt.Sprintf("SV:%v", height))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,7 +202,7 @@ func calcSeenValidationKey(height uint) []byte {
|
||||||
var blockStoreKey = []byte("blockStore")
|
var blockStoreKey = []byte("blockStore")
|
||||||
|
|
||||||
type BlockStoreStateJSON struct {
|
type BlockStoreStateJSON struct {
|
||||||
Height uint
|
Height int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bsj BlockStoreStateJSON) Save(db dbm.DB) {
|
func (bsj BlockStoreStateJSON) Save(db dbm.DB) {
|
||||||
|
|
|
@ -20,7 +20,7 @@ import (
|
||||||
type BarakOptions struct {
|
type BarakOptions struct {
|
||||||
Validators []Validator
|
Validators []Validator
|
||||||
ListenAddress string
|
ListenAddress string
|
||||||
StartNonce uint64
|
StartNonce int64
|
||||||
Registries []string
|
Registries []string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +74,7 @@ func NewBarakFromOptions(opt *BarakOptions) *Barak {
|
||||||
type Barak struct {
|
type Barak struct {
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
pid int
|
pid int
|
||||||
nonce uint64
|
nonce int64
|
||||||
processes map[string]*pcm.Process
|
processes map[string]*pcm.Process
|
||||||
validators []Validator
|
validators []Validator
|
||||||
listeners []net.Listener
|
listeners []net.Listener
|
||||||
|
@ -82,7 +82,7 @@ type Barak struct {
|
||||||
registries []string
|
registries []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBarak(rootDir string, nonce uint64, validators []Validator) *Barak {
|
func NewBarak(rootDir string, nonce int64, validators []Validator) *Barak {
|
||||||
return &Barak{
|
return &Barak{
|
||||||
pid: os.Getpid(),
|
pid: os.Getpid(),
|
||||||
nonce: nonce,
|
nonce: nonce,
|
||||||
|
@ -243,7 +243,7 @@ func (brk *Barak) WritePidFile() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (brk *Barak) CheckIncrNonce(newNonce uint64) error {
|
func (brk *Barak) CheckIncrNonce(newNonce int64) error {
|
||||||
brk.mtx.Lock()
|
brk.mtx.Lock()
|
||||||
defer brk.mtx.Unlock()
|
defer brk.mtx.Unlock()
|
||||||
if brk.nonce+1 != newNonce {
|
if brk.nonce+1 != newNonce {
|
||||||
|
|
|
@ -11,7 +11,7 @@ type AuthCommand struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type NoncedCommand struct {
|
type NoncedCommand struct {
|
||||||
Nonce uint64
|
Nonce int64
|
||||||
Command
|
Command
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ import (
|
||||||
|
|
||||||
type ResponseStatus struct {
|
type ResponseStatus struct {
|
||||||
Pid int
|
Pid int
|
||||||
Nonce uint64
|
Nonce int64
|
||||||
Validators []Validator
|
Validators []Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,6 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
VotingPower uint64
|
VotingPower int64
|
||||||
PubKey acm.PubKey
|
PubKey acm.PubKey
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,8 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func validate(signBytes []byte, validators []Validator, signatures []acm.Signature) bool {
|
func validate(signBytes []byte, validators []Validator, signatures []acm.Signature) bool {
|
||||||
var signedPower uint64
|
var signedPower int64
|
||||||
var totalPower uint64
|
var totalPower int64
|
||||||
for i, val := range validators {
|
for i, val := range validators {
|
||||||
if val.PubKey.VerifyBytes(signBytes, signatures[i]) {
|
if val.PubKey.VerifyBytes(signBytes, signatures[i]) {
|
||||||
signedPower += val.VotingPower
|
signedPower += val.VotingPower
|
||||||
|
|
|
@ -104,7 +104,7 @@ func DownloadFile(privKey acm.PrivKey, remote string, command btypes.CommandServ
|
||||||
|
|
||||||
// Utility method to get nonce from the remote.
|
// Utility method to get nonce from the remote.
|
||||||
// The next command should include the returned nonce+1 as nonce.
|
// The next command should include the returned nonce+1 as nonce.
|
||||||
func GetNonce(remote string) (uint64, error) {
|
func GetNonce(remote string) (int64, error) {
|
||||||
response, err := GetStatus(remote)
|
response, err := GetStatus(remote)
|
||||||
return response.Nonce, err
|
return response.Nonce, err
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ func GetStatus(remote string) (response btypes.ResponseStatus, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Each developer runs this
|
// Each developer runs this
|
||||||
func SignCommand(privKey acm.PrivKey, nonce uint64, command btypes.Command) ([]byte, acm.Signature) {
|
func SignCommand(privKey acm.PrivKey, nonce int64, command btypes.Command) ([]byte, acm.Signature) {
|
||||||
noncedCommand := btypes.NoncedCommand{
|
noncedCommand := btypes.NoncedCommand{
|
||||||
Nonce: nonce,
|
Nonce: nonce,
|
||||||
Command: command,
|
Command: command,
|
||||||
|
|
|
@ -32,13 +32,17 @@ func getByteSliceFromHex(prompt string) []byte {
|
||||||
return bytes
|
return bytes
|
||||||
}
|
}
|
||||||
|
|
||||||
func getUint64(prompt string) uint64 {
|
func getInt(prompt string) int {
|
||||||
input := getString(prompt)
|
input := getString(prompt)
|
||||||
i, err := strconv.Atoi(input)
|
i, err := strconv.Atoi(input)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
Exit(Fmt("Not a valid uint64 amount: %v\nError: %v\n", input, err))
|
Exit(Fmt("Not a valid int64 amount: %v\nError: %v\n", input, err))
|
||||||
}
|
}
|
||||||
return uint64(i)
|
return i
|
||||||
|
}
|
||||||
|
|
||||||
|
func getInt64(prompt string) int64 {
|
||||||
|
return int64(getInt(prompt))
|
||||||
}
|
}
|
||||||
|
|
||||||
func gen_tx() {
|
func gen_tx() {
|
||||||
|
@ -68,16 +72,16 @@ func gen_tx() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the amount to send from src account
|
// Get the amount to send from src account
|
||||||
srcSendAmount := getUint64(Fmt("Enter amount to send from %X (total: %v): ", srcAccountAddress, srcAccountBalanceStr))
|
srcSendAmount := getInt64(Fmt("Enter amount to send from %X (total: %v): ", srcAccountAddress, srcAccountBalanceStr))
|
||||||
|
|
||||||
// Get the next sequence of src account
|
// Get the next sequence of src account
|
||||||
srcSendSequence := uint(getUint64(Fmt("Enter next sequence for %X (guess: %v): ", srcAccountAddress, srcAccountSequenceStr)))
|
srcSendSequence := getInt(Fmt("Enter next sequence for %X (guess: %v): ", srcAccountAddress, srcAccountSequenceStr))
|
||||||
|
|
||||||
// Get dest address
|
// Get dest address
|
||||||
dstAddress := getByteSliceFromHex("Enter destination address: ")
|
dstAddress := getByteSliceFromHex("Enter destination address: ")
|
||||||
|
|
||||||
// Get the amount to send to dst account
|
// Get the amount to send to dst account
|
||||||
dstSendAmount := getUint64(Fmt("Enter amount to send to %X: ", dstAddress))
|
dstSendAmount := getInt64(Fmt("Enter amount to send to %X: ", dstAddress))
|
||||||
|
|
||||||
// Construct SendTx
|
// Construct SendTx
|
||||||
tx := &types.SendTx{
|
tx := &types.SendTx{
|
||||||
|
|
|
@ -21,6 +21,7 @@ Commands:
|
||||||
gen_validator Generate new validator keypair
|
gen_validator Generate new validator keypair
|
||||||
gen_tx Generate new transaction
|
gen_tx Generate new transaction
|
||||||
probe_upnp Test UPnP functionality
|
probe_upnp Test UPnP functionality
|
||||||
|
version Show version info
|
||||||
`)
|
`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -43,6 +44,8 @@ Commands:
|
||||||
probe_upnp()
|
probe_upnp()
|
||||||
case "unsafe_reset_priv_validator":
|
case "unsafe_reset_priv_validator":
|
||||||
reset_priv_validator()
|
reset_priv_validator()
|
||||||
|
case "version":
|
||||||
|
fmt.Println(config.GetString("version"))
|
||||||
default:
|
default:
|
||||||
fmt.Printf("Unknown command %v\n", args[0])
|
fmt.Printf("Unknown command %v\n", args[0])
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,18 +9,22 @@ import (
|
||||||
|
|
||||||
type BitArray struct {
|
type BitArray struct {
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
Bits uint `json:"bits"` // NOTE: persisted via reflect, must be exported
|
Bits int `json:"bits"` // NOTE: persisted via reflect, must be exported
|
||||||
Elems []uint64 `json:"elems"` // NOTE: persisted via reflect, must be exported
|
Elems []uint64 `json:"elems"` // NOTE: persisted via reflect, must be exported
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBitArray(bits uint) *BitArray {
|
// There is no BitArray whose Size is 0. Use nil instead.
|
||||||
|
func NewBitArray(bits int) *BitArray {
|
||||||
|
if bits == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return &BitArray{
|
return &BitArray{
|
||||||
Bits: bits,
|
Bits: bits,
|
||||||
Elems: make([]uint64, (bits+63)/64),
|
Elems: make([]uint64, (bits+63)/64),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bA *BitArray) Size() uint {
|
func (bA *BitArray) Size() int {
|
||||||
if bA == nil {
|
if bA == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -28,7 +32,7 @@ func (bA *BitArray) Size() uint {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: behavior is undefined if i >= bA.Bits
|
// NOTE: behavior is undefined if i >= bA.Bits
|
||||||
func (bA *BitArray) GetIndex(i uint) bool {
|
func (bA *BitArray) GetIndex(i int) bool {
|
||||||
if bA == nil {
|
if bA == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -37,15 +41,15 @@ func (bA *BitArray) GetIndex(i uint) bool {
|
||||||
return bA.getIndex(i)
|
return bA.getIndex(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bA *BitArray) getIndex(i uint) bool {
|
func (bA *BitArray) getIndex(i int) bool {
|
||||||
if i >= bA.Bits {
|
if i >= bA.Bits {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return bA.Elems[i/64]&(uint64(1)<<(i%64)) > 0
|
return bA.Elems[i/64]&(uint64(1)<<uint(i%64)) > 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: behavior is undefined if i >= bA.Bits
|
// NOTE: behavior is undefined if i >= bA.Bits
|
||||||
func (bA *BitArray) SetIndex(i uint, v bool) bool {
|
func (bA *BitArray) SetIndex(i int, v bool) bool {
|
||||||
if bA == nil {
|
if bA == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -54,14 +58,14 @@ func (bA *BitArray) SetIndex(i uint, v bool) bool {
|
||||||
return bA.setIndex(i, v)
|
return bA.setIndex(i, v)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bA *BitArray) setIndex(i uint, v bool) bool {
|
func (bA *BitArray) setIndex(i int, v bool) bool {
|
||||||
if i >= bA.Bits {
|
if i >= bA.Bits {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if v {
|
if v {
|
||||||
bA.Elems[i/64] |= (uint64(1) << (i % 64))
|
bA.Elems[i/64] |= (uint64(1) << uint(i%64))
|
||||||
} else {
|
} else {
|
||||||
bA.Elems[i/64] &= ^(uint64(1) << (i % 64))
|
bA.Elems[i/64] &= ^(uint64(1) << uint(i%64))
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -84,7 +88,7 @@ func (bA *BitArray) copy() *BitArray {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bA *BitArray) copyBits(bits uint) *BitArray {
|
func (bA *BitArray) copyBits(bits int) *BitArray {
|
||||||
c := make([]uint64, (bits+63)/64)
|
c := make([]uint64, (bits+63)/64)
|
||||||
copy(c, bA.Elems)
|
copy(c, bA.Elems)
|
||||||
return &BitArray{
|
return &BitArray{
|
||||||
|
@ -100,7 +104,7 @@ func (bA *BitArray) Or(o *BitArray) *BitArray {
|
||||||
}
|
}
|
||||||
bA.mtx.Lock()
|
bA.mtx.Lock()
|
||||||
defer bA.mtx.Unlock()
|
defer bA.mtx.Unlock()
|
||||||
c := bA.copyBits(MaxUint(bA.Bits, o.Bits))
|
c := bA.copyBits(MaxInt(bA.Bits, o.Bits))
|
||||||
for i := 0; i < len(c.Elems); i++ {
|
for i := 0; i < len(c.Elems); i++ {
|
||||||
c.Elems[i] |= o.Elems[i]
|
c.Elems[i] |= o.Elems[i]
|
||||||
}
|
}
|
||||||
|
@ -118,7 +122,7 @@ func (bA *BitArray) And(o *BitArray) *BitArray {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bA *BitArray) and(o *BitArray) *BitArray {
|
func (bA *BitArray) and(o *BitArray) *BitArray {
|
||||||
c := bA.copyBits(MinUint(bA.Bits, o.Bits))
|
c := bA.copyBits(MinInt(bA.Bits, o.Bits))
|
||||||
for i := 0; i < len(c.Elems); i++ {
|
for i := 0; i < len(c.Elems); i++ {
|
||||||
c.Elems[i] &= o.Elems[i]
|
c.Elems[i] &= o.Elems[i]
|
||||||
}
|
}
|
||||||
|
@ -149,7 +153,7 @@ func (bA *BitArray) Sub(o *BitArray) *BitArray {
|
||||||
for i := 0; i < len(o.Elems)-1; i++ {
|
for i := 0; i < len(o.Elems)-1; i++ {
|
||||||
c.Elems[i] &= ^c.Elems[i]
|
c.Elems[i] &= ^c.Elems[i]
|
||||||
}
|
}
|
||||||
i := uint(len(o.Elems) - 1)
|
i := len(o.Elems) - 1
|
||||||
if i >= 0 {
|
if i >= 0 {
|
||||||
for idx := i * 64; idx < o.Bits; idx++ {
|
for idx := i * 64; idx < o.Bits; idx++ {
|
||||||
c.setIndex(idx, c.getIndex(idx) && !o.GetIndex(idx))
|
c.setIndex(idx, c.getIndex(idx) && !o.GetIndex(idx))
|
||||||
|
@ -168,10 +172,6 @@ func (bA *BitArray) IsFull() bool {
|
||||||
bA.mtx.Lock()
|
bA.mtx.Lock()
|
||||||
defer bA.mtx.Unlock()
|
defer bA.mtx.Unlock()
|
||||||
|
|
||||||
if bA.Bits == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check all elements except the last
|
// Check all elements except the last
|
||||||
for _, elem := range bA.Elems[:len(bA.Elems)-1] {
|
for _, elem := range bA.Elems[:len(bA.Elems)-1] {
|
||||||
if (^elem) != 0 {
|
if (^elem) != 0 {
|
||||||
|
@ -182,10 +182,10 @@ func (bA *BitArray) IsFull() bool {
|
||||||
// Check that the last element has (lastElemBits) 1's
|
// Check that the last element has (lastElemBits) 1's
|
||||||
lastElemBits := (bA.Bits+63)%64 + 1
|
lastElemBits := (bA.Bits+63)%64 + 1
|
||||||
lastElem := bA.Elems[len(bA.Elems)-1]
|
lastElem := bA.Elems[len(bA.Elems)-1]
|
||||||
return (lastElem+1)&((uint64(1)<<lastElemBits)-1) == 0
|
return (lastElem+1)&((uint64(1)<<uint(lastElemBits))-1) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (bA *BitArray) PickRandom() (uint, bool) {
|
func (bA *BitArray) PickRandom() (int, bool) {
|
||||||
if bA == nil {
|
if bA == nil {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
@ -205,14 +205,14 @@ func (bA *BitArray) PickRandom() (uint, bool) {
|
||||||
for j := 0; j < 64; j++ {
|
for j := 0; j < 64; j++ {
|
||||||
bitIdx := ((j + randBitStart) % 64)
|
bitIdx := ((j + randBitStart) % 64)
|
||||||
if (bA.Elems[elemIdx] & (uint64(1) << uint(bitIdx))) > 0 {
|
if (bA.Elems[elemIdx] & (uint64(1) << uint(bitIdx))) > 0 {
|
||||||
return 64*uint(elemIdx) + uint(bitIdx), true
|
return 64*elemIdx + bitIdx, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
panic("should not happen")
|
panic("should not happen")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Special case for last elem, to ignore straggler bits
|
// Special case for last elem, to ignore straggler bits
|
||||||
elemBits := int(bA.Bits) % 64
|
elemBits := bA.Bits % 64
|
||||||
if elemBits == 0 {
|
if elemBits == 0 {
|
||||||
elemBits = 64
|
elemBits = 64
|
||||||
}
|
}
|
||||||
|
@ -220,7 +220,7 @@ func (bA *BitArray) PickRandom() (uint, bool) {
|
||||||
for j := 0; j < elemBits; j++ {
|
for j := 0; j < elemBits; j++ {
|
||||||
bitIdx := ((j + randBitStart) % elemBits)
|
bitIdx := ((j + randBitStart) % elemBits)
|
||||||
if (bA.Elems[elemIdx] & (uint64(1) << uint(bitIdx))) > 0 {
|
if (bA.Elems[elemIdx] & (uint64(1) << uint(bitIdx))) > 0 {
|
||||||
return 64*uint(elemIdx) + uint(bitIdx), true
|
return 64*elemIdx + bitIdx, true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,7 +250,7 @@ func (bA *BitArray) stringIndented(indent string) string {
|
||||||
|
|
||||||
lines := []string{}
|
lines := []string{}
|
||||||
bits := ""
|
bits := ""
|
||||||
for i := uint(0); i < bA.Bits; i++ {
|
for i := 0; i < bA.Bits; i++ {
|
||||||
if bA.getIndex(i) {
|
if bA.getIndex(i) {
|
||||||
bits += "X"
|
bits += "X"
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -4,15 +4,15 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func randBitArray(bits uint) (*BitArray, []byte) {
|
func randBitArray(bits int) (*BitArray, []byte) {
|
||||||
src := RandBytes(int((bits + 7) / 8))
|
src := RandBytes((bits + 7) / 8)
|
||||||
bA := NewBitArray(bits)
|
bA := NewBitArray(bits)
|
||||||
for i := uint(0); i < uint(len(src)); i++ {
|
for i := 0; i < len(src); i++ {
|
||||||
for j := uint(0); j < 8; j++ {
|
for j := 0; j < 8; j++ {
|
||||||
if i*8+j >= bits {
|
if i*8+j >= bits {
|
||||||
return bA, src
|
return bA, src
|
||||||
}
|
}
|
||||||
setBit := src[i]&(1<<j) > 0
|
setBit := src[i]&(1<<uint(j)) > 0
|
||||||
bA.SetIndex(i*8+j, setBit)
|
bA.SetIndex(i*8+j, setBit)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ func TestAnd(t *testing.T) {
|
||||||
if len(bA3.Elems) != len(bA2.Elems) {
|
if len(bA3.Elems) != len(bA2.Elems) {
|
||||||
t.Error("Expected min elems length")
|
t.Error("Expected min elems length")
|
||||||
}
|
}
|
||||||
for i := uint(0); i < bA3.Bits; i++ {
|
for i := 0; i < bA3.Bits; i++ {
|
||||||
expected := bA1.GetIndex(i) && bA2.GetIndex(i)
|
expected := bA1.GetIndex(i) && bA2.GetIndex(i)
|
||||||
if bA3.GetIndex(i) != expected {
|
if bA3.GetIndex(i) != expected {
|
||||||
t.Error("Wrong bit from bA3", i, bA1.GetIndex(i), bA2.GetIndex(i), bA3.GetIndex(i))
|
t.Error("Wrong bit from bA3", i, bA1.GetIndex(i), bA2.GetIndex(i), bA3.GetIndex(i))
|
||||||
|
@ -51,7 +51,7 @@ func TestOr(t *testing.T) {
|
||||||
if len(bA3.Elems) != len(bA1.Elems) {
|
if len(bA3.Elems) != len(bA1.Elems) {
|
||||||
t.Error("Expected max elems length")
|
t.Error("Expected max elems length")
|
||||||
}
|
}
|
||||||
for i := uint(0); i < bA3.Bits; i++ {
|
for i := 0; i < bA3.Bits; i++ {
|
||||||
expected := bA1.GetIndex(i) || bA2.GetIndex(i)
|
expected := bA1.GetIndex(i) || bA2.GetIndex(i)
|
||||||
if bA3.GetIndex(i) != expected {
|
if bA3.GetIndex(i) != expected {
|
||||||
t.Error("Wrong bit from bA3", i, bA1.GetIndex(i), bA2.GetIndex(i), bA3.GetIndex(i))
|
t.Error("Wrong bit from bA3", i, bA1.GetIndex(i), bA2.GetIndex(i), bA3.GetIndex(i))
|
||||||
|
@ -71,7 +71,7 @@ func TestSub1(t *testing.T) {
|
||||||
if len(bA3.Elems) != len(bA1.Elems) {
|
if len(bA3.Elems) != len(bA1.Elems) {
|
||||||
t.Error("Expected bA1 elems length")
|
t.Error("Expected bA1 elems length")
|
||||||
}
|
}
|
||||||
for i := uint(0); i < bA3.Bits; i++ {
|
for i := 0; i < bA3.Bits; i++ {
|
||||||
expected := bA1.GetIndex(i)
|
expected := bA1.GetIndex(i)
|
||||||
if bA2.GetIndex(i) {
|
if bA2.GetIndex(i) {
|
||||||
expected = false
|
expected = false
|
||||||
|
@ -94,7 +94,7 @@ func TestSub2(t *testing.T) {
|
||||||
if len(bA3.Elems) != len(bA1.Elems) {
|
if len(bA3.Elems) != len(bA1.Elems) {
|
||||||
t.Error("Expected bA1 elems length")
|
t.Error("Expected bA1 elems length")
|
||||||
}
|
}
|
||||||
for i := uint(0); i < bA3.Bits; i++ {
|
for i := 0; i < bA3.Bits; i++ {
|
||||||
expected := bA1.GetIndex(i)
|
expected := bA1.GetIndex(i)
|
||||||
if i < bA2.Bits && bA2.GetIndex(i) {
|
if i < bA2.Bits && bA2.GetIndex(i) {
|
||||||
expected = false
|
expected = false
|
||||||
|
@ -108,12 +108,12 @@ func TestSub2(t *testing.T) {
|
||||||
func TestPickRandom(t *testing.T) {
|
func TestPickRandom(t *testing.T) {
|
||||||
for idx := 0; idx < 123; idx++ {
|
for idx := 0; idx < 123; idx++ {
|
||||||
bA1 := NewBitArray(123)
|
bA1 := NewBitArray(123)
|
||||||
bA1.SetIndex(uint(idx), true)
|
bA1.SetIndex(idx, true)
|
||||||
index, ok := bA1.PickRandom()
|
index, ok := bA1.PickRandom()
|
||||||
if !ok {
|
if !ok {
|
||||||
t.Fatal("Expected to pick element but got none")
|
t.Fatal("Expected to pick element but got none")
|
||||||
}
|
}
|
||||||
if index != uint(idx) {
|
if index != idx {
|
||||||
t.Fatalf("Expected to pick element at %v but got wrong index", idx)
|
t.Fatalf("Expected to pick element at %v but got wrong index", idx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,3 +37,19 @@ func PutUint64BE(dest []byte, i uint64) {
|
||||||
func GetUint64BE(src []byte) uint64 {
|
func GetUint64BE(src []byte) uint64 {
|
||||||
return binary.BigEndian.Uint64(src)
|
return binary.BigEndian.Uint64(src)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func PutInt64LE(dest []byte, i int64) {
|
||||||
|
binary.LittleEndian.PutUint64(dest, uint64(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInt64LE(src []byte) int64 {
|
||||||
|
return int64(binary.LittleEndian.Uint64(src))
|
||||||
|
}
|
||||||
|
|
||||||
|
func PutInt64BE(dest []byte, i int64) {
|
||||||
|
binary.BigEndian.PutUint64(dest, uint64(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInt64BE(src []byte) int64 {
|
||||||
|
return int64(binary.BigEndian.Uint64(src))
|
||||||
|
}
|
||||||
|
|
|
@ -62,6 +62,18 @@ func RandUint() uint {
|
||||||
return uint(rand.Int())
|
return uint(rand.Int())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RandInt16() int16 {
|
||||||
|
return int16(rand.Uint32() & (1<<16 - 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandInt32() int32 {
|
||||||
|
return int32(rand.Uint32())
|
||||||
|
}
|
||||||
|
|
||||||
|
func RandInt64() int64 {
|
||||||
|
return int64(rand.Uint32())<<32 + int64(rand.Uint32())
|
||||||
|
}
|
||||||
|
|
||||||
func RandInt() int {
|
func RandInt() int {
|
||||||
return rand.Int()
|
return rand.Int()
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,9 +28,9 @@ func (w Word256) Compare(other Word256) int {
|
||||||
return bytes.Compare(w[:], other[:])
|
return bytes.Compare(w[:], other[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func Uint64ToWord256(i uint64) Word256 {
|
func Int64ToWord256(i int64) Word256 {
|
||||||
buf := [8]byte{}
|
buf := [8]byte{}
|
||||||
PutUint64BE(buf[:], i)
|
PutInt64BE(buf[:], i)
|
||||||
return LeftPadWord256(buf[:])
|
return LeftPadWord256(buf[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,9 +44,9 @@ func LeftPadWord256(bz []byte) (word Word256) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func Uint64FromWord256(word Word256) uint64 {
|
func Int64FromWord256(word Word256) int64 {
|
||||||
buf := word.Postfix(8)
|
buf := word.Postfix(8)
|
||||||
return GetUint64BE(buf)
|
return GetInt64BE(buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
|
@ -57,8 +57,8 @@ func GetConfig(rootDir string) cfg.Config {
|
||||||
if mapConfig.IsSet("version") {
|
if mapConfig.IsSet("version") {
|
||||||
Exit("Cannot set 'version' via config.toml")
|
Exit("Cannot set 'version' via config.toml")
|
||||||
}
|
}
|
||||||
mapConfig.SetDefault("chain_id", "tendermint_testnet_5")
|
mapConfig.SetDefault("chain_id", "tendermint_testnet_6")
|
||||||
mapConfig.SetDefault("version", "0.3.0") // JAE: changed merkle tree persistence format for merkle proofs.
|
mapConfig.SetDefault("version", "0.4.0") // JAE: async consensus!
|
||||||
mapConfig.SetDefault("genesis_file", rootDir+"/genesis.json")
|
mapConfig.SetDefault("genesis_file", rootDir+"/genesis.json")
|
||||||
mapConfig.SetDefault("moniker", "anonymous")
|
mapConfig.SetDefault("moniker", "anonymous")
|
||||||
mapConfig.SetDefault("node_laddr", "0.0.0.0:46656")
|
mapConfig.SetDefault("node_laddr", "0.0.0.0:46656")
|
||||||
|
|
|
@ -67,7 +67,7 @@ func GetConfig(rootDir string) cfg.Config {
|
||||||
Exit("Cannot set 'version' via config.toml")
|
Exit("Cannot set 'version' via config.toml")
|
||||||
}
|
}
|
||||||
mapConfig.SetDefault("chain_id", "tendermint_test")
|
mapConfig.SetDefault("chain_id", "tendermint_test")
|
||||||
mapConfig.SetDefault("version", "0.3.0")
|
mapConfig.SetDefault("version", "0.4.0")
|
||||||
mapConfig.SetDefault("genesis_file", rootDir+"/genesis.json")
|
mapConfig.SetDefault("genesis_file", rootDir+"/genesis.json")
|
||||||
mapConfig.SetDefault("moniker", "anonymous")
|
mapConfig.SetDefault("moniker", "anonymous")
|
||||||
mapConfig.SetDefault("node_laddr", "0.0.0.0:36656")
|
mapConfig.SetDefault("node_laddr", "0.0.0.0:36656")
|
||||||
|
|
|
@ -0,0 +1,180 @@
|
||||||
|
package consensus
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
. "github.com/tendermint/tendermint/common"
|
||||||
|
sm "github.com/tendermint/tendermint/state"
|
||||||
|
"github.com/tendermint/tendermint/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RoundVoteSet struct {
|
||||||
|
Prevotes *VoteSet
|
||||||
|
Precommits *VoteSet
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Keeps track of all VoteSets from round 0 to round 'round'.
|
||||||
|
|
||||||
|
Also keeps track of up to one RoundVoteSet greater than
|
||||||
|
'round' from each peer, to facilitate catchup syncing of commits.
|
||||||
|
|
||||||
|
A commit is +2/3 precommits for a block at a round,
|
||||||
|
but which round is not known in advance, so when a peer
|
||||||
|
provides a precommit for a round greater than mtx.round,
|
||||||
|
we create a new entry in roundVoteSets but also remember the
|
||||||
|
peer to prevent abuse.
|
||||||
|
*/
|
||||||
|
type HeightVoteSet struct {
|
||||||
|
height int
|
||||||
|
valSet *sm.ValidatorSet
|
||||||
|
|
||||||
|
mtx sync.Mutex
|
||||||
|
round int // max tracked round
|
||||||
|
roundVoteSets map[int]RoundVoteSet // keys: [0...round]
|
||||||
|
peerCatchupRounds map[string]int // keys: peer.Key; values: round
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewHeightVoteSet(height int, valSet *sm.ValidatorSet) *HeightVoteSet {
|
||||||
|
hvs := &HeightVoteSet{
|
||||||
|
height: height,
|
||||||
|
valSet: valSet,
|
||||||
|
roundVoteSets: make(map[int]RoundVoteSet),
|
||||||
|
peerCatchupRounds: make(map[string]int),
|
||||||
|
}
|
||||||
|
hvs.addRound(0)
|
||||||
|
hvs.round = 0
|
||||||
|
return hvs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hvs *HeightVoteSet) Height() int {
|
||||||
|
return hvs.height
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hvs *HeightVoteSet) Round() int {
|
||||||
|
hvs.mtx.Lock()
|
||||||
|
defer hvs.mtx.Unlock()
|
||||||
|
return hvs.round
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create more RoundVoteSets up to round.
|
||||||
|
func (hvs *HeightVoteSet) SetRound(round int) {
|
||||||
|
hvs.mtx.Lock()
|
||||||
|
defer hvs.mtx.Unlock()
|
||||||
|
if hvs.round != 0 && (round < hvs.round+1) {
|
||||||
|
panic("SetRound() must increment hvs.round")
|
||||||
|
}
|
||||||
|
for r := hvs.round + 1; r <= round; r++ {
|
||||||
|
if _, ok := hvs.roundVoteSets[r]; ok {
|
||||||
|
continue // Already exists because peerCatchupRounds.
|
||||||
|
}
|
||||||
|
hvs.addRound(round)
|
||||||
|
}
|
||||||
|
hvs.round = round
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hvs *HeightVoteSet) addRound(round int) {
|
||||||
|
if _, ok := hvs.roundVoteSets[round]; ok {
|
||||||
|
panic("addRound() for an existing round")
|
||||||
|
}
|
||||||
|
prevotes := NewVoteSet(hvs.height, round, types.VoteTypePrevote, hvs.valSet)
|
||||||
|
precommits := NewVoteSet(hvs.height, round, types.VoteTypePrecommit, hvs.valSet)
|
||||||
|
hvs.roundVoteSets[round] = RoundVoteSet{
|
||||||
|
Prevotes: prevotes,
|
||||||
|
Precommits: precommits,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Duplicate votes return added=false, err=nil.
|
||||||
|
// By convention, peerKey is "" if origin is self.
|
||||||
|
func (hvs *HeightVoteSet) AddByAddress(address []byte, vote *types.Vote, peerKey string) (added bool, index int, err error) {
|
||||||
|
hvs.mtx.Lock()
|
||||||
|
defer hvs.mtx.Unlock()
|
||||||
|
voteSet := hvs.getVoteSet(vote.Round, vote.Type)
|
||||||
|
if voteSet == nil {
|
||||||
|
if _, ok := hvs.peerCatchupRounds[peerKey]; !ok {
|
||||||
|
hvs.addRound(vote.Round)
|
||||||
|
hvs.peerCatchupRounds[peerKey] = vote.Round
|
||||||
|
} else {
|
||||||
|
// Peer has sent a vote that does not match our round,
|
||||||
|
// for more than one round. Bad peer!
|
||||||
|
// TODO punish peer.
|
||||||
|
log.Warn("Deal with peer giving votes from unwanted rounds")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
added, index, err = voteSet.AddByAddress(address, vote)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hvs *HeightVoteSet) Prevotes(round int) *VoteSet {
|
||||||
|
hvs.mtx.Lock()
|
||||||
|
defer hvs.mtx.Unlock()
|
||||||
|
return hvs.getVoteSet(round, types.VoteTypePrevote)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hvs *HeightVoteSet) Precommits(round int) *VoteSet {
|
||||||
|
hvs.mtx.Lock()
|
||||||
|
defer hvs.mtx.Unlock()
|
||||||
|
return hvs.getVoteSet(round, types.VoteTypePrecommit)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Last round that has +2/3 prevotes for a particular block or nik.
|
||||||
|
// Returns -1 if no such round exists.
|
||||||
|
func (hvs *HeightVoteSet) POLRound() int {
|
||||||
|
hvs.mtx.Lock()
|
||||||
|
defer hvs.mtx.Unlock()
|
||||||
|
for r := hvs.round; r >= 0; r-- {
|
||||||
|
if hvs.getVoteSet(r, types.VoteTypePrevote).HasTwoThirdsMajority() {
|
||||||
|
return r
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hvs *HeightVoteSet) getVoteSet(round int, type_ byte) *VoteSet {
|
||||||
|
rvs, ok := hvs.roundVoteSets[round]
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
switch type_ {
|
||||||
|
case types.VoteTypePrevote:
|
||||||
|
return rvs.Prevotes
|
||||||
|
case types.VoteTypePrecommit:
|
||||||
|
return rvs.Precommits
|
||||||
|
default:
|
||||||
|
panic(Fmt("Unexpected vote type %X", type_))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hvs *HeightVoteSet) String() string {
|
||||||
|
return hvs.StringIndented("")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hvs *HeightVoteSet) StringIndented(indent string) string {
|
||||||
|
vsStrings := make([]string, 0, (len(hvs.roundVoteSets)+1)*2)
|
||||||
|
// rounds 0 ~ hvs.round inclusive
|
||||||
|
for round := 0; round <= hvs.round; round++ {
|
||||||
|
voteSetString := hvs.roundVoteSets[round].Prevotes.StringShort()
|
||||||
|
vsStrings = append(vsStrings, voteSetString)
|
||||||
|
voteSetString = hvs.roundVoteSets[round].Precommits.StringShort()
|
||||||
|
vsStrings = append(vsStrings, voteSetString)
|
||||||
|
}
|
||||||
|
// all other peer catchup rounds
|
||||||
|
for round, roundVoteSet := range hvs.roundVoteSets {
|
||||||
|
if round <= hvs.round {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
voteSetString := roundVoteSet.Prevotes.StringShort()
|
||||||
|
vsStrings = append(vsStrings, voteSetString)
|
||||||
|
voteSetString = roundVoteSet.Precommits.StringShort()
|
||||||
|
vsStrings = append(vsStrings, voteSetString)
|
||||||
|
}
|
||||||
|
return Fmt(`HeightVoteSet{H:%v R:0~%v
|
||||||
|
%s %v
|
||||||
|
%s}`,
|
||||||
|
hvs.height, hvs.round,
|
||||||
|
indent, strings.Join(vsStrings, "\n"+indent+" "),
|
||||||
|
indent)
|
||||||
|
}
|
101
consensus/pol.go
101
consensus/pol.go
|
@ -1,101 +0,0 @@
|
||||||
package consensus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/account"
|
|
||||||
"github.com/tendermint/tendermint/binary"
|
|
||||||
. "github.com/tendermint/tendermint/common"
|
|
||||||
sm "github.com/tendermint/tendermint/state"
|
|
||||||
"github.com/tendermint/tendermint/types"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Each signature of a POL (proof-of-lock, see whitepaper) is
|
|
||||||
// either a prevote or a commit.
|
|
||||||
// Commits require an additional round which is strictly less than
|
|
||||||
// the POL round. Prevote rounds are equal to the POL round.
|
|
||||||
type POLVoteSignature struct {
|
|
||||||
Round uint `json:"round"`
|
|
||||||
Signature account.SignatureEd25519 `json:"signature"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Proof of lock.
|
|
||||||
// +2/3 of validators' prevotes for a given blockhash (or nil)
|
|
||||||
type POL struct {
|
|
||||||
Height uint `json:"height"`
|
|
||||||
Round uint `json:"round"`
|
|
||||||
BlockHash []byte `json:"block_hash"` // Could be nil, which makes this a proof of unlock.
|
|
||||||
BlockParts types.PartSetHeader `json:"block_parts"` // When BlockHash is nil, this is zero.
|
|
||||||
Votes []POLVoteSignature `json:"votes"` // Prevote and commit signatures in ValidatorSet order.
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns whether +2/3 have prevoted/committed for BlockHash.
|
|
||||||
func (pol *POL) Verify(valSet *sm.ValidatorSet) error {
|
|
||||||
|
|
||||||
if uint(len(pol.Votes)) != valSet.Size() {
|
|
||||||
return fmt.Errorf("Invalid POL votes count: Expected %v, got %v",
|
|
||||||
valSet.Size(), len(pol.Votes))
|
|
||||||
}
|
|
||||||
|
|
||||||
talliedVotingPower := uint64(0)
|
|
||||||
prevoteDoc := account.SignBytes(config.GetString("chain_id"), &types.Vote{
|
|
||||||
Height: pol.Height, Round: pol.Round, Type: types.VoteTypePrevote,
|
|
||||||
BlockHash: pol.BlockHash,
|
|
||||||
BlockParts: pol.BlockParts,
|
|
||||||
})
|
|
||||||
seenValidators := map[string]struct{}{}
|
|
||||||
|
|
||||||
for idx, vote := range pol.Votes {
|
|
||||||
// vote may be zero, in which case skip.
|
|
||||||
if vote.Signature.IsZero() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
voteDoc := prevoteDoc
|
|
||||||
_, val := valSet.GetByIndex(uint(idx))
|
|
||||||
|
|
||||||
// Commit vote?
|
|
||||||
if vote.Round < pol.Round {
|
|
||||||
voteDoc = account.SignBytes(config.GetString("chain_id"), &types.Vote{
|
|
||||||
Height: pol.Height, Round: vote.Round, Type: types.VoteTypeCommit,
|
|
||||||
BlockHash: pol.BlockHash,
|
|
||||||
BlockParts: pol.BlockParts,
|
|
||||||
})
|
|
||||||
} else if vote.Round > pol.Round {
|
|
||||||
return fmt.Errorf("Invalid commit round %v for POL %v", vote.Round, pol)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate
|
|
||||||
if _, seen := seenValidators[string(val.Address)]; seen {
|
|
||||||
return fmt.Errorf("Duplicate validator for vote %v for POL %v", vote, pol)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !val.PubKey.VerifyBytes(voteDoc, vote.Signature) {
|
|
||||||
return fmt.Errorf("Invalid signature for vote %v for POL %v", vote, pol)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tally
|
|
||||||
seenValidators[string(val.Address)] = struct{}{}
|
|
||||||
talliedVotingPower += val.VotingPower
|
|
||||||
}
|
|
||||||
|
|
||||||
if talliedVotingPower > valSet.TotalVotingPower()*2/3 {
|
|
||||||
return nil
|
|
||||||
} else {
|
|
||||||
return fmt.Errorf("Invalid POL, insufficient voting power %v, needed %v",
|
|
||||||
talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pol *POL) StringShort() string {
|
|
||||||
if pol == nil {
|
|
||||||
return "nil-POL"
|
|
||||||
} else {
|
|
||||||
return fmt.Sprintf("POL{H:%v R:%v BH:%X}", pol.Height, pol.Round,
|
|
||||||
Fingerprint(pol.BlockHash), pol.BlockParts)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (pol *POL) MakePartSet() *types.PartSet {
|
|
||||||
return types.NewPartSetFromData(binary.BinaryBytes(pol))
|
|
||||||
}
|
|
|
@ -1,213 +0,0 @@
|
||||||
package consensus
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/tendermint/tendermint/binary"
|
|
||||||
. "github.com/tendermint/tendermint/common"
|
|
||||||
_ "github.com/tendermint/tendermint/config/tendermint_test"
|
|
||||||
sm "github.com/tendermint/tendermint/state"
|
|
||||||
"github.com/tendermint/tendermint/types"
|
|
||||||
|
|
||||||
"bytes"
|
|
||||||
"testing"
|
|
||||||
)
|
|
||||||
|
|
||||||
// NOTE: see consensus/test.go for common test methods.
|
|
||||||
|
|
||||||
// Convenience method.
|
|
||||||
// Signs the vote and sets the POL's vote at the desired index
|
|
||||||
// Returns the POLVoteSignature pointer, so you can modify it afterwards.
|
|
||||||
func signAddPOLVoteSignature(val *sm.PrivValidator, valSet *sm.ValidatorSet, vote *types.Vote, pol *POL) *POLVoteSignature {
|
|
||||||
vote = vote.Copy()
|
|
||||||
err := val.SignVote(config.GetString("chain_id"), vote)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
idx, _ := valSet.GetByAddress(val.Address) // now we have the index
|
|
||||||
pol.Votes[idx] = POLVoteSignature{vote.Round, vote.Signature}
|
|
||||||
return &pol.Votes[idx]
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVerifyVotes(t *testing.T) {
|
|
||||||
height, round := uint(1), uint(0)
|
|
||||||
_, valSet, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
|
||||||
|
|
||||||
// Make a POL with -2/3 votes.
|
|
||||||
blockHash := RandBytes(32)
|
|
||||||
pol := &POL{
|
|
||||||
Height: height, Round: round, BlockHash: blockHash,
|
|
||||||
Votes: make([]POLVoteSignature, valSet.Size()),
|
|
||||||
}
|
|
||||||
voteProto := &types.Vote{
|
|
||||||
Height: height, Round: round, Type: types.VoteTypePrevote, BlockHash: blockHash,
|
|
||||||
}
|
|
||||||
for i := 0; i < 6; i++ {
|
|
||||||
signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that validation fails.
|
|
||||||
if err := pol.Verify(valSet); err == nil {
|
|
||||||
t.Errorf("Expected POL.Verify() to fail, not enough votes.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Insert another vote to make +2/3
|
|
||||||
signAddPOLVoteSignature(privValidators[7], valSet, voteProto, pol)
|
|
||||||
|
|
||||||
// Check that validation succeeds.
|
|
||||||
if err := pol.Verify(valSet); err != nil {
|
|
||||||
t.Errorf("POL.Verify() failed: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVerifyInvalidVote(t *testing.T) {
|
|
||||||
height, round := uint(1), uint(0)
|
|
||||||
_, valSet, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
|
||||||
|
|
||||||
// Make a POL with +2/3 votes with the wrong signature.
|
|
||||||
blockHash := RandBytes(32)
|
|
||||||
pol := &POL{
|
|
||||||
Height: height, Round: round, BlockHash: blockHash,
|
|
||||||
Votes: make([]POLVoteSignature, valSet.Size()),
|
|
||||||
}
|
|
||||||
voteProto := &types.Vote{
|
|
||||||
Height: height, Round: round, Type: types.VoteTypePrevote, BlockHash: blockHash,
|
|
||||||
}
|
|
||||||
for i := 0; i < 7; i++ {
|
|
||||||
polVoteSig := signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol)
|
|
||||||
polVoteSig.Signature[0] += byte(0x01) // mutated!
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that validation fails.
|
|
||||||
if err := pol.Verify(valSet); err == nil {
|
|
||||||
t.Errorf("Expected POL.Verify() to fail, wrong signatures.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVerifyCommits(t *testing.T) {
|
|
||||||
height, round := uint(1), uint(2)
|
|
||||||
_, valSet, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
|
||||||
|
|
||||||
// Make a POL with +2/3 votes.
|
|
||||||
blockHash := RandBytes(32)
|
|
||||||
pol := &POL{
|
|
||||||
Height: height, Round: round, BlockHash: blockHash,
|
|
||||||
Votes: make([]POLVoteSignature, valSet.Size()),
|
|
||||||
}
|
|
||||||
voteProto := &types.Vote{
|
|
||||||
Height: height, Round: round - 1, Type: types.VoteTypeCommit, BlockHash: blockHash,
|
|
||||||
}
|
|
||||||
for i := 0; i < 7; i++ {
|
|
||||||
signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that validation succeeds.
|
|
||||||
if err := pol.Verify(valSet); err != nil {
|
|
||||||
t.Errorf("POL.Verify() failed: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVerifyInvalidCommits(t *testing.T) {
|
|
||||||
height, round := uint(1), uint(2)
|
|
||||||
_, valSet, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
|
||||||
|
|
||||||
// Make a POL with +2/3 votes with the wrong signature.
|
|
||||||
blockHash := RandBytes(32)
|
|
||||||
pol := &POL{
|
|
||||||
Height: height, Round: round, BlockHash: blockHash,
|
|
||||||
Votes: make([]POLVoteSignature, valSet.Size()),
|
|
||||||
}
|
|
||||||
voteProto := &types.Vote{
|
|
||||||
Height: height, Round: round - 1, Type: types.VoteTypeCommit, BlockHash: blockHash,
|
|
||||||
}
|
|
||||||
for i := 0; i < 7; i++ {
|
|
||||||
polVoteSig := signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol)
|
|
||||||
polVoteSig.Signature[0] += byte(0x01)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that validation fails.
|
|
||||||
if err := pol.Verify(valSet); err == nil {
|
|
||||||
t.Errorf("Expected POL.Verify() to fail, wrong signatures.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVerifyInvalidCommitRounds(t *testing.T) {
|
|
||||||
height, round := uint(1), uint(2)
|
|
||||||
_, valSet, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
|
||||||
|
|
||||||
// Make a POL with +2/3 commits for the current round.
|
|
||||||
blockHash := RandBytes(32)
|
|
||||||
pol := &POL{
|
|
||||||
Height: height, Round: round, BlockHash: blockHash,
|
|
||||||
Votes: make([]POLVoteSignature, valSet.Size()),
|
|
||||||
}
|
|
||||||
voteProto := &types.Vote{
|
|
||||||
Height: height, Round: round, Type: types.VoteTypeCommit, BlockHash: blockHash,
|
|
||||||
}
|
|
||||||
for i := 0; i < 7; i++ {
|
|
||||||
signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that validation fails.
|
|
||||||
if err := pol.Verify(valSet); err == nil {
|
|
||||||
t.Errorf("Expected POL.Verify() to fail, same round.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestVerifyInvalidCommitRounds2(t *testing.T) {
|
|
||||||
height, round := uint(1), uint(2)
|
|
||||||
_, valSet, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
|
||||||
|
|
||||||
// Make a POL with +2/3 commits for future round.
|
|
||||||
blockHash := RandBytes(32)
|
|
||||||
pol := &POL{
|
|
||||||
Height: height, Round: round, BlockHash: blockHash,
|
|
||||||
Votes: make([]POLVoteSignature, valSet.Size()),
|
|
||||||
}
|
|
||||||
voteProto := &types.Vote{
|
|
||||||
Height: height, Round: round + 1, Type: types.VoteTypeCommit, BlockHash: blockHash,
|
|
||||||
}
|
|
||||||
for i := 0; i < 7; i++ {
|
|
||||||
polVoteSig := signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol)
|
|
||||||
polVoteSig.Round += 1 // mutate round
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that validation fails.
|
|
||||||
if err := pol.Verify(valSet); err == nil {
|
|
||||||
t.Errorf("Expected POL.Verify() to fail, future round.")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReadWrite(t *testing.T) {
|
|
||||||
height, round := uint(1), uint(2)
|
|
||||||
_, valSet, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
|
||||||
|
|
||||||
// Make a POL with +2/3 votes.
|
|
||||||
blockHash := RandBytes(32)
|
|
||||||
pol := &POL{
|
|
||||||
Height: height, Round: round, BlockHash: blockHash,
|
|
||||||
Votes: make([]POLVoteSignature, valSet.Size()),
|
|
||||||
}
|
|
||||||
voteProto := &types.Vote{
|
|
||||||
Height: height, Round: round, Type: types.VoteTypePrevote, BlockHash: blockHash,
|
|
||||||
}
|
|
||||||
for i := 0; i < 7; i++ {
|
|
||||||
signAddPOLVoteSignature(privValidators[i], valSet, voteProto, pol)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write it to a buffer.
|
|
||||||
buf, n, err := new(bytes.Buffer), new(int64), new(error)
|
|
||||||
binary.WriteBinary(pol, buf, n, err)
|
|
||||||
if *err != nil {
|
|
||||||
t.Fatalf("Failed to write POL: %v", *err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read from buffer.
|
|
||||||
pol2 := binary.ReadBinary(&POL{}, buf, n, err).(*POL)
|
|
||||||
if *err != nil {
|
|
||||||
t.Fatalf("Failed to read POL: %v", *err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that validation succeeds.
|
|
||||||
if err := pol2.Verify(valSet); err != nil {
|
|
||||||
t.Errorf("POL.Verify() failed: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -49,8 +49,8 @@ type ConsensusReactor struct {
|
||||||
|
|
||||||
func NewConsensusReactor(consensusState *ConsensusState, blockStore *bc.BlockStore, sync bool) *ConsensusReactor {
|
func NewConsensusReactor(consensusState *ConsensusState, blockStore *bc.BlockStore, sync bool) *ConsensusReactor {
|
||||||
conR := &ConsensusReactor{
|
conR := &ConsensusReactor{
|
||||||
blockStore: blockStore,
|
|
||||||
quit: make(chan struct{}),
|
quit: make(chan struct{}),
|
||||||
|
blockStore: blockStore,
|
||||||
conS: consensusState,
|
conS: consensusState,
|
||||||
sync: sync,
|
sync: sync,
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ func (conR *ConsensusReactor) AddPeer(peer *p2p.Peer) {
|
||||||
go conR.gossipVotesRoutine(peer, peerState)
|
go conR.gossipVotesRoutine(peer, peerState)
|
||||||
|
|
||||||
// Send our state to peer.
|
// Send our state to peer.
|
||||||
conR.sendNewRoundStep(peer)
|
conR.sendNewRoundStepMessage(peer)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implements Reactor
|
// Implements Reactor
|
||||||
|
@ -164,18 +164,11 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte
|
||||||
case *ProposalMessage:
|
case *ProposalMessage:
|
||||||
ps.SetHasProposal(msg.Proposal)
|
ps.SetHasProposal(msg.Proposal)
|
||||||
err = conR.conS.SetProposal(msg.Proposal)
|
err = conR.conS.SetProposal(msg.Proposal)
|
||||||
|
case *ProposalPOLMessage:
|
||||||
case *PartMessage:
|
ps.ApplyProposalPOLMessage(msg)
|
||||||
if msg.Type == partTypeProposalBlock {
|
case *BlockPartMessage:
|
||||||
ps.SetHasProposalBlockPart(msg.Height, msg.Round, msg.Part.Proof.Index)
|
ps.SetHasProposalBlockPart(msg.Height, msg.Round, msg.Part.Proof.Index)
|
||||||
_, err = conR.conS.AddProposalBlockPart(msg.Height, msg.Round, msg.Part)
|
_, err = conR.conS.AddProposalBlockPart(msg.Height, msg.Part)
|
||||||
} else if msg.Type == partTypeProposalPOL {
|
|
||||||
ps.SetHasProposalPOLPart(msg.Height, msg.Round, msg.Part.Proof.Index)
|
|
||||||
_, err = conR.conS.AddProposalPOLPart(msg.Height, msg.Round, msg.Part)
|
|
||||||
} else {
|
|
||||||
log.Warn(Fmt("Unknown part type %v", msg.Type))
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
default:
|
||||||
log.Warn(Fmt("Unknown message type %v", reflect.TypeOf(msg)))
|
log.Warn(Fmt("Unknown message type %v", reflect.TypeOf(msg)))
|
||||||
}
|
}
|
||||||
|
@ -184,18 +177,22 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte
|
||||||
switch msg := msg_.(type) {
|
switch msg := msg_.(type) {
|
||||||
case *VoteMessage:
|
case *VoteMessage:
|
||||||
vote := msg.Vote
|
vote := msg.Vote
|
||||||
if rs.Height != vote.Height {
|
var validators *sm.ValidatorSet
|
||||||
if rs.Height == vote.Height+1 {
|
if rs.Height == vote.Height {
|
||||||
if rs.Step == RoundStepNewHeight && vote.Type == types.VoteTypeCommit {
|
validators = rs.Validators
|
||||||
goto VOTE_PASS // *ducks*
|
} else if rs.Height == vote.Height+1 {
|
||||||
}
|
if !(rs.Step == RoundStepNewHeight && vote.Type == types.VoteTypePrecommit) {
|
||||||
|
return // Wrong height, not a LastCommit straggler commit.
|
||||||
}
|
}
|
||||||
|
validators = rs.LastValidators
|
||||||
|
} else {
|
||||||
return // Wrong height. Not necessarily a bad peer.
|
return // Wrong height. Not necessarily a bad peer.
|
||||||
}
|
}
|
||||||
VOTE_PASS:
|
|
||||||
validatorIndex := msg.ValidatorIndex
|
// We have vote/validators. Height may not be rs.Height
|
||||||
address, _ := rs.Validators.GetByIndex(validatorIndex)
|
|
||||||
added, index, err := conR.conS.AddVote(address, vote)
|
address, _ := validators.GetByIndex(msg.ValidatorIndex)
|
||||||
|
added, index, err := conR.conS.AddVote(address, vote, peer.Key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// If conflicting sig, broadcast evidence tx for slashing. Else punish peer.
|
// If conflicting sig, broadcast evidence tx for slashing. Else punish peer.
|
||||||
if errDupe, ok := err.(*types.ErrVoteConflictingSignature); ok {
|
if errDupe, ok := err.(*types.ErrVoteConflictingSignature); ok {
|
||||||
|
@ -209,21 +206,17 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte
|
||||||
} else {
|
} else {
|
||||||
// Probably an invalid signature. Bad peer.
|
// Probably an invalid signature. Bad peer.
|
||||||
log.Warn("Error attempting to add vote", "error", err)
|
log.Warn("Error attempting to add vote", "error", err)
|
||||||
|
|
||||||
// TODO: punish peer
|
// TODO: punish peer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Initialize Prevotes/Precommits/Commits if needed
|
ps.EnsureVoteBitArrays(rs.Height, rs.Validators.Size(), nil)
|
||||||
ps.EnsureVoteBitArrays(rs.Height, rs.Validators.Size())
|
ps.EnsureVoteBitArrays(rs.Height-1, rs.LastCommit.Size(), nil)
|
||||||
ps.SetHasVote(vote, index)
|
ps.SetHasVote(vote, index)
|
||||||
if added {
|
if added {
|
||||||
msg := &HasVoteMessage{
|
// If rs.Height == vote.Height && rs.Round < vote.Round,
|
||||||
Height: vote.Height,
|
// the peer is sending us CatchupCommit precommits.
|
||||||
Round: vote.Round,
|
// We could make note of this and help filter in broadcastHasVoteMessage().
|
||||||
Type: vote.Type,
|
conR.broadcastHasVoteMessage(vote, index)
|
||||||
Index: index,
|
|
||||||
}
|
|
||||||
conR.sw.Broadcast(StateChannel, msg)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -238,6 +231,32 @@ func (conR *ConsensusReactor) Receive(chId byte, peer *p2p.Peer, msgBytes []byte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Broadcasts HasVoteMessage to peers that care.
|
||||||
|
func (conR *ConsensusReactor) broadcastHasVoteMessage(vote *types.Vote, index int) {
|
||||||
|
msg := &HasVoteMessage{
|
||||||
|
Height: vote.Height,
|
||||||
|
Round: vote.Round,
|
||||||
|
Type: vote.Type,
|
||||||
|
Index: index,
|
||||||
|
}
|
||||||
|
conR.sw.Broadcast(StateChannel, msg)
|
||||||
|
/*
|
||||||
|
// TODO: Make this broadcast more selective.
|
||||||
|
for _, peer := range conR.sw.Peers().List() {
|
||||||
|
ps := peer.Data.Get(PeerStateKey).(*PeerState)
|
||||||
|
prs := ps.GetRoundState()
|
||||||
|
if prs.Height == vote.Height {
|
||||||
|
// TODO: Also filter on round?
|
||||||
|
peer.TrySend(StateChannel, msg)
|
||||||
|
} else {
|
||||||
|
// Height doesn't match
|
||||||
|
// TODO: check a field, maybe CatchupCommitRound?
|
||||||
|
// TODO: But that requires changing the struct field comment.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
// Sets our private validator account for signing votes.
|
// Sets our private validator account for signing votes.
|
||||||
func (conR *ConsensusReactor) SetPrivValidator(priv *sm.PrivValidator) {
|
func (conR *ConsensusReactor) SetPrivValidator(priv *sm.PrivValidator) {
|
||||||
conR.conS.SetPrivValidator(priv)
|
conR.conS.SetPrivValidator(priv)
|
||||||
|
@ -247,7 +266,6 @@ func (conR *ConsensusReactor) SetPrivValidator(priv *sm.PrivValidator) {
|
||||||
// reset the state, turn off fast sync, start the consensus-state-machine
|
// reset the state, turn off fast sync, start the consensus-state-machine
|
||||||
func (conR *ConsensusReactor) SwitchToConsensus(state *sm.State) {
|
func (conR *ConsensusReactor) SwitchToConsensus(state *sm.State) {
|
||||||
conR.conS.updateToState(state, false)
|
conR.conS.updateToState(state, false)
|
||||||
conR.conS.newStepCh <- conR.conS.getRoundState()
|
|
||||||
conR.sync = false
|
conR.sync = false
|
||||||
conR.conS.Start()
|
conR.conS.Start()
|
||||||
}
|
}
|
||||||
|
@ -261,26 +279,20 @@ func (conR *ConsensusReactor) SetFireable(evsw events.Fireable) {
|
||||||
//--------------------------------------
|
//--------------------------------------
|
||||||
|
|
||||||
func makeRoundStepMessages(rs *RoundState) (nrsMsg *NewRoundStepMessage, csMsg *CommitStepMessage) {
|
func makeRoundStepMessages(rs *RoundState) (nrsMsg *NewRoundStepMessage, csMsg *CommitStepMessage) {
|
||||||
// Get seconds since beginning of height.
|
|
||||||
timeElapsed := time.Now().Sub(rs.StartTime)
|
|
||||||
|
|
||||||
// Broadcast NewRoundStepMessage
|
|
||||||
nrsMsg = &NewRoundStepMessage{
|
nrsMsg = &NewRoundStepMessage{
|
||||||
Height: rs.Height,
|
Height: rs.Height,
|
||||||
Round: rs.Round,
|
Round: rs.Round,
|
||||||
Step: rs.Step,
|
Step: rs.Step,
|
||||||
SecondsSinceStartTime: uint(timeElapsed.Seconds()),
|
SecondsSinceStartTime: int(time.Now().Sub(rs.StartTime).Seconds()),
|
||||||
|
LastCommitRound: rs.LastCommit.Round(),
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the step is commit, then also broadcast a CommitStepMessage.
|
|
||||||
if rs.Step == RoundStepCommit {
|
if rs.Step == RoundStepCommit {
|
||||||
csMsg = &CommitStepMessage{
|
csMsg = &CommitStepMessage{
|
||||||
Height: rs.Height,
|
Height: rs.Height,
|
||||||
BlockParts: rs.ProposalBlockParts.Header(),
|
BlockPartsHeader: rs.ProposalBlockParts.Header(),
|
||||||
BlockBitArray: rs.ProposalBlockParts.BitArray(),
|
BlockParts: rs.ProposalBlockParts.BitArray(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -306,7 +318,7 @@ func (conR *ConsensusReactor) broadcastNewRoundStepRoutine() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (conR *ConsensusReactor) sendNewRoundStep(peer *p2p.Peer) {
|
func (conR *ConsensusReactor) sendNewRoundStepMessage(peer *p2p.Peer) {
|
||||||
rs := conR.conS.GetRoundState()
|
rs := conR.conS.GetRoundState()
|
||||||
nrsMsg, csMsg := makeRoundStepMessages(rs)
|
nrsMsg, csMsg := makeRoundStepMessages(rs)
|
||||||
if nrsMsg != nil {
|
if nrsMsg != nil {
|
||||||
|
@ -330,33 +342,30 @@ OUTER_LOOP:
|
||||||
prs := ps.GetRoundState()
|
prs := ps.GetRoundState()
|
||||||
|
|
||||||
// Send proposal Block parts?
|
// Send proposal Block parts?
|
||||||
// NOTE: if we or peer is at RoundStepCommit*, the round
|
if rs.ProposalBlockParts.HasHeader(prs.ProposalBlockPartsHeader) {
|
||||||
// won't necessarily match, but that's OK.
|
|
||||||
if rs.ProposalBlockParts.HasHeader(prs.ProposalBlockParts) {
|
|
||||||
//log.Debug("ProposalBlockParts matched", "blockParts", prs.ProposalBlockParts)
|
//log.Debug("ProposalBlockParts matched", "blockParts", prs.ProposalBlockParts)
|
||||||
if index, ok := rs.ProposalBlockParts.BitArray().Sub(prs.ProposalBlockBitArray.Copy()).PickRandom(); ok {
|
if index, ok := rs.ProposalBlockParts.BitArray().Sub(prs.ProposalBlockParts.Copy()).PickRandom(); ok {
|
||||||
part := rs.ProposalBlockParts.GetPart(index)
|
part := rs.ProposalBlockParts.GetPart(index)
|
||||||
msg := &PartMessage{
|
msg := &BlockPartMessage{
|
||||||
Height: rs.Height,
|
Height: rs.Height, // This tells peer that this part applies to us.
|
||||||
Round: rs.Round,
|
Round: rs.Round, // This tells peer that this part applies to us.
|
||||||
Type: partTypeProposalBlock,
|
|
||||||
Part: part,
|
Part: part,
|
||||||
}
|
}
|
||||||
peer.Send(DataChannel, msg)
|
peer.Send(DataChannel, msg)
|
||||||
ps.SetHasProposalBlockPart(rs.Height, rs.Round, index)
|
ps.SetHasProposalBlockPart(prs.Height, prs.Round, index)
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the peer is on a previous height, help catch up.
|
// If the peer is on a previous height, help catch up.
|
||||||
if 0 < prs.Height && prs.Height < rs.Height {
|
if (0 < prs.Height) && (prs.Height < rs.Height) {
|
||||||
//log.Debug("Data catchup", "height", rs.Height, "peerHeight", prs.Height, "peerProposalBlockBitArray", prs.ProposalBlockBitArray)
|
//log.Debug("Data catchup", "height", rs.Height, "peerHeight", prs.Height, "peerProposalBlockParts", prs.ProposalBlockParts)
|
||||||
if index, ok := prs.ProposalBlockBitArray.Not().PickRandom(); ok {
|
if index, ok := prs.ProposalBlockParts.Not().PickRandom(); ok {
|
||||||
// Ensure that the peer's PartSetHeader is correct
|
// Ensure that the peer's PartSetHeader is correct
|
||||||
blockMeta := conR.blockStore.LoadBlockMeta(prs.Height)
|
blockMeta := conR.blockStore.LoadBlockMeta(prs.Height)
|
||||||
if !blockMeta.Parts.Equals(prs.ProposalBlockParts) {
|
if !blockMeta.PartsHeader.Equals(prs.ProposalBlockPartsHeader) {
|
||||||
log.Debug("Peer ProposalBlockParts mismatch, sleeping",
|
log.Debug("Peer ProposalBlockPartsHeader mismatch, sleeping",
|
||||||
"peerHeight", prs.Height, "blockParts", blockMeta.Parts, "peerBlockParts", prs.ProposalBlockParts)
|
"peerHeight", prs.Height, "blockPartsHeader", blockMeta.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader)
|
||||||
time.Sleep(peerGossipSleepDuration)
|
time.Sleep(peerGossipSleepDuration)
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
|
@ -364,15 +373,14 @@ OUTER_LOOP:
|
||||||
part := conR.blockStore.LoadBlockPart(prs.Height, index)
|
part := conR.blockStore.LoadBlockPart(prs.Height, index)
|
||||||
if part == nil {
|
if part == nil {
|
||||||
log.Warn("Could not load part", "index", index,
|
log.Warn("Could not load part", "index", index,
|
||||||
"peerHeight", prs.Height, "blockParts", blockMeta.Parts, "peerBlockParts", prs.ProposalBlockParts)
|
"peerHeight", prs.Height, "blockPartsHeader", blockMeta.PartsHeader, "peerBlockPartsHeader", prs.ProposalBlockPartsHeader)
|
||||||
time.Sleep(peerGossipSleepDuration)
|
time.Sleep(peerGossipSleepDuration)
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
// Send the part
|
// Send the part
|
||||||
msg := &PartMessage{
|
msg := &BlockPartMessage{
|
||||||
Height: prs.Height,
|
Height: prs.Height, // Not our height, so it doesn't matter.
|
||||||
Round: prs.Round,
|
Round: prs.Round, // Not our height, so it doesn't matter.
|
||||||
Type: partTypeProposalBlock,
|
|
||||||
Part: part,
|
Part: part,
|
||||||
}
|
}
|
||||||
peer.Send(DataChannel, msg)
|
peer.Send(DataChannel, msg)
|
||||||
|
@ -386,33 +394,38 @@ OUTER_LOOP:
|
||||||
}
|
}
|
||||||
|
|
||||||
// If height and round don't match, sleep.
|
// If height and round don't match, sleep.
|
||||||
if rs.Height != prs.Height || rs.Round != prs.Round {
|
if (rs.Height != prs.Height) || (rs.Round != prs.Round) {
|
||||||
//log.Debug("Peer Height|Round mismatch, sleeping", "peerHeight", prs.Height, "peerRound", prs.Round, "peer", peer)
|
//log.Debug("Peer Height|Round mismatch, sleeping", "peerHeight", prs.Height, "peerRound", prs.Round, "peer", peer)
|
||||||
time.Sleep(peerGossipSleepDuration)
|
time.Sleep(peerGossipSleepDuration)
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send proposal?
|
// By here, height and round match.
|
||||||
if rs.Proposal != nil && !prs.Proposal {
|
// Proposal block parts were already matched and sent if any were wanted.
|
||||||
msg := &ProposalMessage{Proposal: rs.Proposal}
|
// (These can match on hash so the round doesn't matter)
|
||||||
peer.Send(DataChannel, msg)
|
// Now consider sending other things, like the Proposal itself.
|
||||||
ps.SetHasProposal(rs.Proposal)
|
|
||||||
continue OUTER_LOOP
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send proposal POL parts?
|
// Send Proposal && ProposalPOL BitArray?
|
||||||
if rs.ProposalPOLParts.HasHeader(prs.ProposalPOLParts) {
|
if rs.Proposal != nil && !prs.Proposal {
|
||||||
if index, ok := rs.ProposalPOLParts.BitArray().Sub(prs.ProposalPOLBitArray.Copy()).PickRandom(); ok {
|
// Proposal
|
||||||
msg := &PartMessage{
|
{
|
||||||
Height: rs.Height,
|
msg := &ProposalMessage{Proposal: rs.Proposal}
|
||||||
Round: rs.Round,
|
peer.Send(DataChannel, msg)
|
||||||
Type: partTypeProposalPOL,
|
ps.SetHasProposal(rs.Proposal)
|
||||||
Part: rs.ProposalPOLParts.GetPart(index),
|
}
|
||||||
|
// ProposalPOL.
|
||||||
|
// Peer must receive ProposalMessage first.
|
||||||
|
// rs.Proposal was validated, so rs.Proposal.POLRound <= rs.Round,
|
||||||
|
// so we definitely have rs.Votes.Prevotes(rs.Proposal.POLRound).
|
||||||
|
if 0 <= rs.Proposal.POLRound {
|
||||||
|
msg := &ProposalPOLMessage{
|
||||||
|
Height: rs.Height,
|
||||||
|
ProposalPOLRound: rs.Proposal.POLRound,
|
||||||
|
ProposalPOL: rs.Votes.Prevotes(rs.Proposal.POLRound).BitArray(),
|
||||||
}
|
}
|
||||||
peer.Send(DataChannel, msg)
|
peer.Send(DataChannel, msg)
|
||||||
ps.SetHasProposalPOLPart(rs.Height, rs.Round, index)
|
|
||||||
continue OUTER_LOOP
|
|
||||||
}
|
}
|
||||||
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing to do. Sleep.
|
// Nothing to do. Sleep.
|
||||||
|
@ -443,18 +456,23 @@ OUTER_LOOP:
|
||||||
sleeping = 0
|
sleeping = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prsVoteSet: a pointer to a VoteSet field of prs.
|
||||||
// Returns true when useful work was done.
|
// Returns true when useful work was done.
|
||||||
trySendVote := func(height uint, voteSet *VoteSet, peerVoteSet *BitArray) (sent bool) {
|
trySendVote := func(voteSet *VoteSet, prsVoteSet **BitArray) (sent bool) {
|
||||||
if voteSet == nil {
|
if voteSet == nil {
|
||||||
return false
|
return false
|
||||||
} else if peerVoteSet == nil {
|
}
|
||||||
ps.EnsureVoteBitArrays(height, voteSet.Size())
|
if *prsVoteSet == nil {
|
||||||
return true
|
ps.EnsureVoteBitArrays(voteSet.Height(), voteSet.Size(), prs)
|
||||||
|
// We could return true here (useful work was done)
|
||||||
|
// or, we can continue since prsVoteSet is no longer nil.
|
||||||
|
if *prsVoteSet == nil {
|
||||||
|
panic("prsVoteSet should not be nil after ps.EnsureVoteBitArrays")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// TODO: give priority to our vote.
|
// TODO: give priority to our vote.
|
||||||
if index, ok := voteSet.BitArray().Sub(peerVoteSet.Copy()).PickRandom(); ok {
|
if index, ok := voteSet.BitArray().Sub((*prsVoteSet).Copy()).PickRandom(); ok {
|
||||||
vote := voteSet.GetByIndex(index)
|
vote := voteSet.GetByIndex(index)
|
||||||
// NOTE: vote may be a commit.
|
|
||||||
msg := &VoteMessage{index, vote}
|
msg := &VoteMessage{index, vote}
|
||||||
peer.Send(VoteChannel, msg)
|
peer.Send(VoteChannel, msg)
|
||||||
ps.SetHasVote(vote, index)
|
ps.SetHasVote(vote, index)
|
||||||
|
@ -463,106 +481,99 @@ OUTER_LOOP:
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prsVoteSet: a pointer to a VoteSet field of prs.
|
||||||
// Returns true when useful work was done.
|
// Returns true when useful work was done.
|
||||||
trySendCommitFromValidation := func(blockMeta *types.BlockMeta, validation *types.Validation, peerVoteSet *BitArray) (sent bool) {
|
trySendPrecommitFromValidation := func(validation *types.Validation, prsVoteSet **BitArray) (sent bool) {
|
||||||
if validation == nil {
|
if validation == nil {
|
||||||
return false
|
return false
|
||||||
} else if peerVoteSet == nil {
|
} else if *prsVoteSet == nil {
|
||||||
ps.EnsureVoteBitArrays(blockMeta.Header.Height, uint(len(validation.Commits)))
|
ps.EnsureVoteBitArrays(validation.Height(), len(validation.Precommits), prs)
|
||||||
return true
|
// We could return true here (useful work was done)
|
||||||
}
|
// or, we can continue since prsVoteSet is no longer nil.
|
||||||
if index, ok := validation.BitArray().Sub(prs.Commits.Copy()).PickRandom(); ok {
|
if *prsVoteSet == nil {
|
||||||
commit := validation.Commits[index]
|
panic("prsVoteSet should not be nil after ps.EnsureVoteBitArrays")
|
||||||
log.Debug("Picked commit to send", "index", index, "commit", commit)
|
|
||||||
// Reconstruct vote.
|
|
||||||
vote := &types.Vote{
|
|
||||||
Height: prs.Height,
|
|
||||||
Round: commit.Round,
|
|
||||||
Type: types.VoteTypeCommit,
|
|
||||||
BlockHash: blockMeta.Hash,
|
|
||||||
BlockParts: blockMeta.Parts,
|
|
||||||
Signature: commit.Signature,
|
|
||||||
}
|
}
|
||||||
msg := &VoteMessage{index, vote}
|
}
|
||||||
|
if index, ok := validation.BitArray().Sub((*prsVoteSet).Copy()).PickRandom(); ok {
|
||||||
|
precommit := validation.Precommits[index]
|
||||||
|
log.Debug("Picked precommit to send", "index", index, "precommit", precommit)
|
||||||
|
msg := &VoteMessage{index, precommit}
|
||||||
peer.Send(VoteChannel, msg)
|
peer.Send(VoteChannel, msg)
|
||||||
ps.SetHasVote(vote, index)
|
ps.SetHasVote(precommit, index)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// If height matches, then send LastCommits, Prevotes, Precommits, or Commits.
|
// If height matches, then send LastCommit, Prevotes, Precommits.
|
||||||
if rs.Height == prs.Height {
|
if rs.Height == prs.Height {
|
||||||
|
// If there are lastCommits to send...
|
||||||
// If there are lastcommits to send...
|
if prs.Step == RoundStepNewHeight {
|
||||||
if prs.Round == 0 && prs.Step == RoundStepNewHeight {
|
if trySendVote(rs.LastCommit, &prs.LastCommit) {
|
||||||
if trySendVote(rs.Height-1, rs.LastCommits, prs.LastCommits) {
|
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are prevotes to send...
|
// If there are prevotes to send...
|
||||||
if rs.Round == prs.Round && prs.Step <= RoundStepPrevote {
|
if rs.Round == prs.Round && prs.Step <= RoundStepPrevote {
|
||||||
if trySendVote(rs.Height, rs.Prevotes, prs.Prevotes) {
|
if trySendVote(rs.Votes.Prevotes(rs.Round), &prs.Prevotes) {
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are precommits to send...
|
// If there are precommits to send...
|
||||||
if rs.Round == prs.Round && prs.Step <= RoundStepPrecommit {
|
if rs.Round == prs.Round && prs.Step <= RoundStepPrecommit {
|
||||||
if trySendVote(rs.Height, rs.Precommits, prs.Precommits) {
|
if trySendVote(rs.Votes.Precommits(rs.Round), &prs.Precommits) {
|
||||||
continue OUTER_LOOP
|
continue OUTER_LOOP
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// If there are prevotes to send for the last round...
|
||||||
|
if rs.Round == prs.Round+1 && prs.Step <= RoundStepPrevote {
|
||||||
|
if trySendVote(rs.Votes.Prevotes(prs.Round), &prs.Prevotes) {
|
||||||
|
continue OUTER_LOOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If there are precommits to send for the last round...
|
||||||
|
if rs.Round == prs.Round+1 && prs.Step <= RoundStepPrecommit {
|
||||||
|
if trySendVote(rs.Votes.Precommits(prs.Round), &prs.Precommits) {
|
||||||
|
continue OUTER_LOOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If there are POLPrevotes to send...
|
||||||
|
if 0 <= prs.ProposalPOLRound {
|
||||||
|
if polPrevotes := rs.Votes.Prevotes(prs.ProposalPOLRound); polPrevotes != nil {
|
||||||
|
if trySendVote(polPrevotes, &prs.ProposalPOL) {
|
||||||
|
continue OUTER_LOOP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If there are any commits to send...
|
// Special catchup logic.
|
||||||
if trySendVote(rs.Height, rs.Commits, prs.Commits) {
|
// If peer is lagging by height 1, send LastCommit.
|
||||||
continue OUTER_LOOP
|
if prs.Height != 0 && prs.Height == rs.Height-1 {
|
||||||
|
if prs.Round == rs.LastCommit.Round() {
|
||||||
|
// NOTE: We prefer to use prs.Precommits if
|
||||||
|
// prs.Round matches prs.CatchupCommitRound.
|
||||||
|
if trySendVote(rs.LastCommit, &prs.Precommits) {
|
||||||
|
continue OUTER_LOOP
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ps.EnsureCatchupCommitRound(prs.Height, rs.LastCommit.Round())
|
||||||
|
if trySendVote(rs.LastCommit, &prs.CatchupCommit) {
|
||||||
|
continue OUTER_LOOP
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Catchup logic
|
// Catchup logic
|
||||||
if prs.Height != 0 && !prs.HasAllCatchupCommits {
|
// If peer is lagging by more than 1, send Validation.
|
||||||
|
if prs.Height != 0 && prs.Height <= rs.Height-2 {
|
||||||
// If peer is lagging by height 1, match our LastCommits or SeenValidation to peer's Commits.
|
// Load the block validation for prs.Height,
|
||||||
if rs.Height == prs.Height+1 && rs.LastCommits.Size() > 0 {
|
// which contains precommit signatures for prs.Height.
|
||||||
// If there are lastcommits to send...
|
validation := conR.blockStore.LoadBlockValidation(prs.Height)
|
||||||
if trySendVote(prs.Height, rs.LastCommits, prs.Commits) {
|
log.Debug("Loaded BlockValidation for catch-up", "height", prs.Height, "validation", validation)
|
||||||
continue OUTER_LOOP
|
ps.EnsureCatchupCommitRound(prs.Height, validation.Round())
|
||||||
} else {
|
if trySendPrecommitFromValidation(validation, &prs.CatchupCommit) {
|
||||||
ps.SetHasAllCatchupCommits(prs.Height)
|
continue OUTER_LOOP
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Or, if peer is lagging by 1 and we don't have LastCommits, send SeenValidation.
|
|
||||||
if rs.Height == prs.Height+1 && rs.LastCommits.Size() == 0 {
|
|
||||||
// Load the blockMeta for block at prs.Height
|
|
||||||
blockMeta := conR.blockStore.LoadBlockMeta(prs.Height)
|
|
||||||
// Load the seen validation for prs.Height
|
|
||||||
validation := conR.blockStore.LoadSeenValidation(prs.Height)
|
|
||||||
log.Debug("Loaded SeenValidation for catch-up", "height", prs.Height, "blockMeta", blockMeta, "validation", validation)
|
|
||||||
|
|
||||||
if trySendCommitFromValidation(blockMeta, validation, prs.Commits) {
|
|
||||||
continue OUTER_LOOP
|
|
||||||
} else {
|
|
||||||
ps.SetHasAllCatchupCommits(prs.Height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If peer is lagging by more than 1, send Validation.
|
|
||||||
if rs.Height >= prs.Height+2 {
|
|
||||||
// Load the blockMeta for block at prs.Height
|
|
||||||
blockMeta := conR.blockStore.LoadBlockMeta(prs.Height)
|
|
||||||
// Load the block validation for prs.Height+1,
|
|
||||||
// which contains commit signatures for prs.Height.
|
|
||||||
validation := conR.blockStore.LoadBlockValidation(prs.Height + 1)
|
|
||||||
log.Debug("Loaded BlockValidation for catch-up", "height", prs.Height+1, "blockMeta", blockMeta, "validation", validation)
|
|
||||||
|
|
||||||
if trySendCommitFromValidation(blockMeta, validation, prs.Commits) {
|
|
||||||
continue OUTER_LOOP
|
|
||||||
} else {
|
|
||||||
ps.SetHasAllCatchupCommits(prs.Height)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -570,9 +581,8 @@ OUTER_LOOP:
|
||||||
// We sent nothing. Sleep...
|
// We sent nothing. Sleep...
|
||||||
sleeping = 1
|
sleeping = 1
|
||||||
log.Debug("No votes to send, sleeping", "peer", peer,
|
log.Debug("No votes to send, sleeping", "peer", peer,
|
||||||
"localPV", rs.Prevotes.BitArray(), "peerPV", prs.Prevotes,
|
"localPV", rs.Votes.Prevotes(rs.Round).BitArray(), "peerPV", prs.Prevotes,
|
||||||
"localPC", rs.Precommits.BitArray(), "peerPC", prs.Precommits,
|
"localPC", rs.Votes.Precommits(rs.Round).BitArray(), "peerPC", prs.Precommits)
|
||||||
"localCM", rs.Commits.BitArray(), "peerCM", prs.Commits)
|
|
||||||
} else if sleeping == 2 {
|
} else if sleeping == 2 {
|
||||||
// Continued sleep...
|
// Continued sleep...
|
||||||
sleeping = 1
|
sleeping = 1
|
||||||
|
@ -587,20 +597,21 @@ OUTER_LOOP:
|
||||||
|
|
||||||
// Read only when returned by PeerState.GetRoundState().
|
// Read only when returned by PeerState.GetRoundState().
|
||||||
type PeerRoundState struct {
|
type PeerRoundState struct {
|
||||||
Height uint // Height peer is at
|
Height int // Height peer is at
|
||||||
Round uint // Round peer is at
|
Round int // Round peer is at
|
||||||
Step RoundStepType // Step peer is at
|
Step RoundStepType // Step peer is at
|
||||||
StartTime time.Time // Estimated start of round 0 at this height
|
StartTime time.Time // Estimated start of round 0 at this height
|
||||||
Proposal bool // True if peer has proposal for this round
|
Proposal bool // True if peer has proposal for this round
|
||||||
ProposalBlockParts types.PartSetHeader //
|
ProposalBlockPartsHeader types.PartSetHeader //
|
||||||
ProposalBlockBitArray *BitArray // True bit -> has part
|
ProposalBlockParts *BitArray //
|
||||||
ProposalPOLParts types.PartSetHeader //
|
ProposalPOLRound int // -1 if none
|
||||||
ProposalPOLBitArray *BitArray // True bit -> has part
|
ProposalPOL *BitArray // nil until ProposalPOLMessage received.
|
||||||
Prevotes *BitArray // All votes peer has for this round
|
Prevotes *BitArray // All votes peer has for this round
|
||||||
Precommits *BitArray // All precommits peer has for this round
|
Precommits *BitArray // All precommits peer has for this round
|
||||||
Commits *BitArray // All commits peer has for this height
|
LastCommitRound int // Round of commit for last height.
|
||||||
LastCommits *BitArray // All commits peer has for last height
|
LastCommit *BitArray // All commit precommits of commit for last height.
|
||||||
HasAllCatchupCommits bool // Used for catch-up
|
CatchupCommitRound int // Round that we believe commit round is.
|
||||||
|
CatchupCommit *BitArray // All commit precommits peer has for this height
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -643,13 +654,13 @@ func (ps *PeerState) SetHasProposal(proposal *Proposal) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ps.Proposal = true
|
ps.Proposal = true
|
||||||
ps.ProposalBlockParts = proposal.BlockParts
|
ps.ProposalBlockPartsHeader = proposal.BlockPartsHeader
|
||||||
ps.ProposalBlockBitArray = NewBitArray(uint(proposal.BlockParts.Total))
|
ps.ProposalBlockParts = NewBitArray(proposal.BlockPartsHeader.Total)
|
||||||
ps.ProposalPOLParts = proposal.POLParts
|
ps.ProposalPOLRound = proposal.POLRound
|
||||||
ps.ProposalPOLBitArray = NewBitArray(uint(proposal.POLParts.Total))
|
ps.ProposalPOL = nil // Nil until ProposalPOLMessage received.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PeerState) SetHasProposalBlockPart(height uint, round uint, index uint) {
|
func (ps *PeerState) SetHasProposalBlockPart(height int, round int, index int) {
|
||||||
ps.mtx.Lock()
|
ps.mtx.Lock()
|
||||||
defer ps.mtx.Unlock()
|
defer ps.mtx.Unlock()
|
||||||
|
|
||||||
|
@ -657,21 +668,13 @@ func (ps *PeerState) SetHasProposalBlockPart(height uint, round uint, index uint
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ps.ProposalBlockBitArray.SetIndex(uint(index), true)
|
ps.ProposalBlockParts.SetIndex(index, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PeerState) SetHasProposalPOLPart(height uint, round uint, index uint) {
|
// prs: If given, will also update this PeerRoundState copy.
|
||||||
ps.mtx.Lock()
|
// NOTE: It's important to make sure that numValidators actually matches
|
||||||
defer ps.mtx.Unlock()
|
// what the node sees as the number of validators for height.
|
||||||
|
func (ps *PeerState) EnsureVoteBitArrays(height int, numValidators int, prs *PeerRoundState) {
|
||||||
if ps.Height != height || ps.Round != round {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
ps.ProposalPOLBitArray.SetIndex(uint(index), true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (ps *PeerState) EnsureVoteBitArrays(height uint, numValidators uint) {
|
|
||||||
ps.mtx.Lock()
|
ps.mtx.Lock()
|
||||||
defer ps.mtx.Unlock()
|
defer ps.mtx.Unlock()
|
||||||
|
|
||||||
|
@ -682,62 +685,81 @@ func (ps *PeerState) EnsureVoteBitArrays(height uint, numValidators uint) {
|
||||||
if ps.Precommits == nil {
|
if ps.Precommits == nil {
|
||||||
ps.Precommits = NewBitArray(numValidators)
|
ps.Precommits = NewBitArray(numValidators)
|
||||||
}
|
}
|
||||||
if ps.Commits == nil {
|
if ps.CatchupCommit == nil {
|
||||||
ps.Commits = NewBitArray(numValidators)
|
ps.CatchupCommit = NewBitArray(numValidators)
|
||||||
|
}
|
||||||
|
if ps.ProposalPOL == nil {
|
||||||
|
ps.ProposalPOL = NewBitArray(numValidators)
|
||||||
}
|
}
|
||||||
} else if ps.Height == height+1 {
|
} else if ps.Height == height+1 {
|
||||||
if ps.LastCommits == nil {
|
if ps.LastCommit == nil {
|
||||||
ps.LastCommits = NewBitArray(numValidators)
|
ps.LastCommit = NewBitArray(numValidators)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Also, update prs if given.
|
||||||
|
if prs != nil {
|
||||||
|
prs.Prevotes = ps.Prevotes
|
||||||
|
prs.Precommits = ps.Precommits
|
||||||
|
prs.CatchupCommit = ps.CatchupCommit
|
||||||
|
prs.ProposalPOL = ps.ProposalPOL
|
||||||
|
prs.LastCommit = ps.LastCommit
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PeerState) SetHasVote(vote *types.Vote, index uint) {
|
func (ps *PeerState) SetHasVote(vote *types.Vote, index int) {
|
||||||
ps.mtx.Lock()
|
ps.mtx.Lock()
|
||||||
defer ps.mtx.Unlock()
|
defer ps.mtx.Unlock()
|
||||||
|
|
||||||
ps.setHasVote(vote.Height, vote.Round, vote.Type, index)
|
ps.setHasVote(vote.Height, vote.Round, vote.Type, index)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PeerState) setHasVote(height uint, round uint, type_ byte, index uint) {
|
func (ps *PeerState) setHasVote(height int, round int, type_ byte, index int) {
|
||||||
if ps.Height == height+1 && type_ == types.VoteTypeCommit {
|
if ps.Height == height+1 && ps.LastCommitRound == round && type_ == types.VoteTypePrecommit {
|
||||||
// Special case for LastCommits.
|
// Special case for LastCommit.
|
||||||
ps.LastCommits.SetIndex(index, true)
|
ps.LastCommit.SetIndex(index, true)
|
||||||
log.Debug("SetHasVote", "lastCommits", ps.LastCommits, "index", index)
|
log.Debug("setHasVote", "LastCommit", ps.LastCommit, "index", index)
|
||||||
return
|
return
|
||||||
} else if ps.Height != height {
|
} else if ps.Height != height {
|
||||||
// Does not apply.
|
// Does not apply.
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// By here, ps.Height is height.
|
||||||
switch type_ {
|
switch type_ {
|
||||||
case types.VoteTypePrevote:
|
case types.VoteTypePrevote:
|
||||||
|
if ps.ProposalPOLRound == round {
|
||||||
|
ps.ProposalPOL.SetIndex(index, true)
|
||||||
|
}
|
||||||
ps.Prevotes.SetIndex(index, true)
|
ps.Prevotes.SetIndex(index, true)
|
||||||
log.Debug("SetHasVote", "peer", ps.Key, "prevotes", ps.Prevotes, "index", index)
|
log.Debug("SetHasVote", "peer", ps.Key, "prevotes", ps.Prevotes, "index", index)
|
||||||
case types.VoteTypePrecommit:
|
case types.VoteTypePrecommit:
|
||||||
|
if ps.CatchupCommitRound == round {
|
||||||
|
ps.CatchupCommit.SetIndex(index, true)
|
||||||
|
}
|
||||||
ps.Precommits.SetIndex(index, true)
|
ps.Precommits.SetIndex(index, true)
|
||||||
log.Debug("SetHasVote", "peer", ps.Key, "precommits", ps.Precommits, "index", index)
|
log.Debug("SetHasVote", "peer", ps.Key, "precommits", ps.Precommits, "index", index)
|
||||||
case types.VoteTypeCommit:
|
|
||||||
if round < ps.Round {
|
|
||||||
ps.Prevotes.SetIndex(index, true)
|
|
||||||
ps.Precommits.SetIndex(index, true)
|
|
||||||
}
|
|
||||||
ps.Commits.SetIndex(index, true)
|
|
||||||
log.Debug("SetHasVote", "peer", ps.Key, "commits", ps.Commits, "index", index)
|
|
||||||
default:
|
default:
|
||||||
panic("Invalid vote type")
|
panic("Invalid vote type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When catching up, this helps keep track of whether
|
// NOTE: 'round' is what we know to be the commit round for height.
|
||||||
// we should send more commit votes from the block (validation) store
|
func (ps *PeerState) EnsureCatchupCommitRound(height, round int) {
|
||||||
func (ps *PeerState) SetHasAllCatchupCommits(height uint) {
|
|
||||||
ps.mtx.Lock()
|
ps.mtx.Lock()
|
||||||
defer ps.mtx.Unlock()
|
defer ps.mtx.Unlock()
|
||||||
|
|
||||||
if ps.Height == height {
|
if ps.Height != height {
|
||||||
ps.HasAllCatchupCommits = true
|
return
|
||||||
}
|
}
|
||||||
|
if ps.CatchupCommitRound != -1 && ps.CatchupCommitRound != round {
|
||||||
|
panic(Fmt("Conflicting CatchupCommitRound. Height: %v, Orig: %v, New: %v", height, ps.CatchupCommitRound, round))
|
||||||
|
}
|
||||||
|
if ps.CatchupCommitRound == round {
|
||||||
|
return // Nothing to do!
|
||||||
|
}
|
||||||
|
ps.CatchupCommitRound = round
|
||||||
|
ps.CatchupCommit = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage, rs *RoundState) {
|
func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage, rs *RoundState) {
|
||||||
|
@ -748,6 +770,8 @@ func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage, rs *Roun
|
||||||
psHeight := ps.Height
|
psHeight := ps.Height
|
||||||
psRound := ps.Round
|
psRound := ps.Round
|
||||||
//psStep := ps.Step
|
//psStep := ps.Step
|
||||||
|
psCatchupCommitRound := ps.CatchupCommitRound
|
||||||
|
psCatchupCommit := ps.CatchupCommit
|
||||||
|
|
||||||
startTime := time.Now().Add(-1 * time.Duration(msg.SecondsSinceStartTime) * time.Second)
|
startTime := time.Now().Add(-1 * time.Duration(msg.SecondsSinceStartTime) * time.Second)
|
||||||
ps.Height = msg.Height
|
ps.Height = msg.Height
|
||||||
|
@ -756,24 +780,33 @@ func (ps *PeerState) ApplyNewRoundStepMessage(msg *NewRoundStepMessage, rs *Roun
|
||||||
ps.StartTime = startTime
|
ps.StartTime = startTime
|
||||||
if psHeight != msg.Height || psRound != msg.Round {
|
if psHeight != msg.Height || psRound != msg.Round {
|
||||||
ps.Proposal = false
|
ps.Proposal = false
|
||||||
ps.ProposalBlockParts = types.PartSetHeader{}
|
ps.ProposalBlockPartsHeader = types.PartSetHeader{}
|
||||||
ps.ProposalBlockBitArray = nil
|
ps.ProposalBlockParts = nil
|
||||||
ps.ProposalPOLParts = types.PartSetHeader{}
|
ps.ProposalPOLRound = -1
|
||||||
ps.ProposalPOLBitArray = nil
|
ps.ProposalPOL = nil
|
||||||
// We'll update the BitArray capacity later.
|
// We'll update the BitArray capacity later.
|
||||||
ps.Prevotes = nil
|
ps.Prevotes = nil
|
||||||
ps.Precommits = nil
|
ps.Precommits = nil
|
||||||
}
|
}
|
||||||
|
if psHeight == msg.Height && psRound != msg.Round && msg.Round == psCatchupCommitRound {
|
||||||
|
// Peer caught up to CatchupCommitRound.
|
||||||
|
// Preserve psCatchupCommit!
|
||||||
|
// NOTE: We prefer to use prs.Precommits if
|
||||||
|
// pr.Round matches pr.CatchupCommitRound.
|
||||||
|
ps.Precommits = psCatchupCommit
|
||||||
|
}
|
||||||
if psHeight != msg.Height {
|
if psHeight != msg.Height {
|
||||||
// Shift Commits to LastCommits
|
// Shift Precommits to LastCommit.
|
||||||
if psHeight+1 == msg.Height {
|
if psHeight+1 == msg.Height && psRound == msg.LastCommitRound {
|
||||||
ps.LastCommits = ps.Commits
|
ps.LastCommitRound = msg.LastCommitRound
|
||||||
|
ps.LastCommit = ps.Precommits
|
||||||
} else {
|
} else {
|
||||||
ps.LastCommits = nil
|
ps.LastCommitRound = msg.LastCommitRound
|
||||||
|
ps.LastCommit = nil
|
||||||
}
|
}
|
||||||
// We'll update the BitArray capacity later.
|
// We'll update the BitArray capacity later.
|
||||||
ps.Commits = nil
|
ps.CatchupCommitRound = -1
|
||||||
ps.HasAllCatchupCommits = false
|
ps.CatchupCommit = nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -785,25 +818,37 @@ func (ps *PeerState) ApplyCommitStepMessage(msg *CommitStepMessage) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ps.ProposalBlockPartsHeader = msg.BlockPartsHeader
|
||||||
ps.ProposalBlockParts = msg.BlockParts
|
ps.ProposalBlockParts = msg.BlockParts
|
||||||
ps.ProposalBlockBitArray = msg.BlockBitArray
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PeerState) ApplyHasVoteMessage(msg *HasVoteMessage) {
|
func (ps *PeerState) ApplyHasVoteMessage(msg *HasVoteMessage) {
|
||||||
ps.mtx.Lock()
|
ps.mtx.Lock()
|
||||||
defer ps.mtx.Unlock()
|
defer ps.mtx.Unlock()
|
||||||
|
|
||||||
// Special case for LastCommits
|
if ps.Height != msg.Height {
|
||||||
if ps.Height == msg.Height+1 && msg.Type == types.VoteTypeCommit {
|
|
||||||
ps.LastCommits.SetIndex(msg.Index, true)
|
|
||||||
return
|
|
||||||
} else if ps.Height != msg.Height {
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
ps.setHasVote(msg.Height, msg.Round, msg.Type, msg.Index)
|
ps.setHasVote(msg.Height, msg.Round, msg.Type, msg.Index)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ps *PeerState) ApplyProposalPOLMessage(msg *ProposalPOLMessage) {
|
||||||
|
ps.mtx.Lock()
|
||||||
|
defer ps.mtx.Unlock()
|
||||||
|
|
||||||
|
if ps.Height != msg.Height {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if ps.ProposalPOLRound != msg.ProposalPOLRound {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Merge onto existing ps.ProposalPOL?
|
||||||
|
// We might have sent some prevotes in the meantime.
|
||||||
|
ps.ProposalPOL = msg.ProposalPOL
|
||||||
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Messages
|
// Messages
|
||||||
|
|
||||||
|
@ -811,9 +856,10 @@ const (
|
||||||
msgTypeNewRoundStep = byte(0x01)
|
msgTypeNewRoundStep = byte(0x01)
|
||||||
msgTypeCommitStep = byte(0x02)
|
msgTypeCommitStep = byte(0x02)
|
||||||
msgTypeProposal = byte(0x11)
|
msgTypeProposal = byte(0x11)
|
||||||
msgTypePart = byte(0x12) // both block & POL
|
msgTypeProposalPOL = byte(0x12)
|
||||||
msgTypeVote = byte(0x13)
|
msgTypeBlockPart = byte(0x13) // both block & POL
|
||||||
msgTypeHasVote = byte(0x14)
|
msgTypeVote = byte(0x14)
|
||||||
|
msgTypeHasVote = byte(0x15)
|
||||||
)
|
)
|
||||||
|
|
||||||
type ConsensusMessage interface{}
|
type ConsensusMessage interface{}
|
||||||
|
@ -823,7 +869,8 @@ var _ = binary.RegisterInterface(
|
||||||
binary.ConcreteType{&NewRoundStepMessage{}, msgTypeNewRoundStep},
|
binary.ConcreteType{&NewRoundStepMessage{}, msgTypeNewRoundStep},
|
||||||
binary.ConcreteType{&CommitStepMessage{}, msgTypeCommitStep},
|
binary.ConcreteType{&CommitStepMessage{}, msgTypeCommitStep},
|
||||||
binary.ConcreteType{&ProposalMessage{}, msgTypeProposal},
|
binary.ConcreteType{&ProposalMessage{}, msgTypeProposal},
|
||||||
binary.ConcreteType{&PartMessage{}, msgTypePart},
|
binary.ConcreteType{&ProposalPOLMessage{}, msgTypeProposalPOL},
|
||||||
|
binary.ConcreteType{&BlockPartMessage{}, msgTypeBlockPart},
|
||||||
binary.ConcreteType{&VoteMessage{}, msgTypeVote},
|
binary.ConcreteType{&VoteMessage{}, msgTypeVote},
|
||||||
binary.ConcreteType{&HasVoteMessage{}, msgTypeHasVote},
|
binary.ConcreteType{&HasVoteMessage{}, msgTypeHasVote},
|
||||||
)
|
)
|
||||||
|
@ -839,27 +886,30 @@ func DecodeMessage(bz []byte) (msgType byte, msg ConsensusMessage, err error) {
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
|
// For every height/round/step transition
|
||||||
type NewRoundStepMessage struct {
|
type NewRoundStepMessage struct {
|
||||||
Height uint
|
Height int
|
||||||
Round uint
|
Round int
|
||||||
Step RoundStepType
|
Step RoundStepType
|
||||||
SecondsSinceStartTime uint
|
SecondsSinceStartTime int
|
||||||
|
LastCommitRound int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *NewRoundStepMessage) String() string {
|
func (m *NewRoundStepMessage) String() string {
|
||||||
return fmt.Sprintf("[NewRoundStep H:%v R:%v S:%v]", m.Height, m.Round, m.Step)
|
return fmt.Sprintf("[NewRoundStep H:%v R:%v S:%v LCR:%v]",
|
||||||
|
m.Height, m.Round, m.Step, m.LastCommitRound)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
type CommitStepMessage struct {
|
type CommitStepMessage struct {
|
||||||
Height uint
|
Height int
|
||||||
BlockParts types.PartSetHeader
|
BlockPartsHeader types.PartSetHeader
|
||||||
BlockBitArray *BitArray
|
BlockParts *BitArray
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *CommitStepMessage) String() string {
|
func (m *CommitStepMessage) String() string {
|
||||||
return fmt.Sprintf("[CommitStep H:%v BP:%v BA:%v]", m.Height, m.BlockParts, m.BlockBitArray)
|
return fmt.Sprintf("[CommitStep H:%v BP:%v BA:%v]", m.Height, m.BlockPartsHeader, m.BlockParts)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
@ -874,26 +924,32 @@ func (m *ProposalMessage) String() string {
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
const (
|
type ProposalPOLMessage struct {
|
||||||
partTypeProposalBlock = byte(0x01)
|
Height int
|
||||||
partTypeProposalPOL = byte(0x02)
|
ProposalPOLRound int
|
||||||
)
|
ProposalPOL *BitArray
|
||||||
|
}
|
||||||
|
|
||||||
type PartMessage struct {
|
func (m *ProposalPOLMessage) String() string {
|
||||||
Height uint
|
return fmt.Sprintf("[ProposalPOL H:%v POLR:%v POL:%v]", m.Height, m.ProposalPOLRound, m.ProposalPOL)
|
||||||
Round uint
|
}
|
||||||
Type byte
|
|
||||||
|
//-------------------------------------
|
||||||
|
|
||||||
|
type BlockPartMessage struct {
|
||||||
|
Height int
|
||||||
|
Round int
|
||||||
Part *types.Part
|
Part *types.Part
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PartMessage) String() string {
|
func (m *BlockPartMessage) String() string {
|
||||||
return fmt.Sprintf("[Part H:%v R:%v T:%X P:%v]", m.Height, m.Round, m.Type, m.Part)
|
return fmt.Sprintf("[BlockPart H:%v R:%v P:%v]", m.Height, m.Round, m.Part)
|
||||||
}
|
}
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
type VoteMessage struct {
|
type VoteMessage struct {
|
||||||
ValidatorIndex uint
|
ValidatorIndex int
|
||||||
Vote *types.Vote
|
Vote *types.Vote
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -904,10 +960,10 @@ func (m *VoteMessage) String() string {
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
type HasVoteMessage struct {
|
type HasVoteMessage struct {
|
||||||
Height uint
|
Height int
|
||||||
Round uint
|
Round int
|
||||||
Type byte
|
Type byte
|
||||||
Index uint
|
Index int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *HasVoteMessage) String() string {
|
func (m *HasVoteMessage) String() string {
|
||||||
|
|
1417
consensus/state.go
1417
consensus/state.go
File diff suppressed because it is too large
Load Diff
|
@ -1,73 +1,26 @@
|
||||||
package consensus
|
package consensus
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
_ "github.com/tendermint/tendermint/config/tendermint_test"
|
_ "github.com/tendermint/tendermint/config/tendermint_test"
|
||||||
"github.com/tendermint/tendermint/types"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSetupRound(t *testing.T) {
|
func TestEnterProposeNoPrivValidator(t *testing.T) {
|
||||||
cs, privValidators := randConsensusState()
|
|
||||||
val0 := privValidators[0]
|
|
||||||
|
|
||||||
// Add a vote, precommit, and commit by val0.
|
|
||||||
voteTypes := []byte{types.VoteTypePrevote, types.VoteTypePrecommit, types.VoteTypeCommit}
|
|
||||||
for _, voteType := range voteTypes {
|
|
||||||
vote := &types.Vote{Height: 1, Round: 0, Type: voteType} // nil vote
|
|
||||||
err := val0.SignVote(cs.state.ChainID, vote)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error signing vote: %v", err)
|
|
||||||
}
|
|
||||||
cs.AddVote(val0.Address, vote)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure that vote appears in RoundState.
|
|
||||||
rs0 := cs.GetRoundState()
|
|
||||||
if vote := rs0.Prevotes.GetByAddress(val0.Address); vote == nil || vote.Type != types.VoteTypePrevote {
|
|
||||||
t.Errorf("Expected to find prevote but got %v", vote)
|
|
||||||
}
|
|
||||||
if vote := rs0.Precommits.GetByAddress(val0.Address); vote == nil || vote.Type != types.VoteTypePrecommit {
|
|
||||||
t.Errorf("Expected to find precommit but got %v", vote)
|
|
||||||
}
|
|
||||||
if vote := rs0.Commits.GetByAddress(val0.Address); vote == nil || vote.Type != types.VoteTypeCommit {
|
|
||||||
t.Errorf("Expected to find commit but got %v", vote)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setup round 1 (next round)
|
|
||||||
cs.SetupNewRound(1, 1)
|
|
||||||
<-cs.NewStepCh()
|
|
||||||
|
|
||||||
// Now the commit should be copied over to prevotes and precommits.
|
|
||||||
rs1 := cs.GetRoundState()
|
|
||||||
if vote := rs1.Prevotes.GetByAddress(val0.Address); vote == nil || vote.Type != types.VoteTypeCommit {
|
|
||||||
t.Errorf("Expected to find commit but got %v", vote)
|
|
||||||
}
|
|
||||||
if vote := rs1.Precommits.GetByAddress(val0.Address); vote == nil || vote.Type != types.VoteTypeCommit {
|
|
||||||
t.Errorf("Expected to find commit but got %v", vote)
|
|
||||||
}
|
|
||||||
if vote := rs1.Commits.GetByAddress(val0.Address); vote == nil || vote.Type != types.VoteTypeCommit {
|
|
||||||
t.Errorf("Expected to find commit but got %v", vote)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunActionProposeNoPrivValidator(t *testing.T) {
|
|
||||||
cs, _ := randConsensusState()
|
cs, _ := randConsensusState()
|
||||||
cs.RunActionPropose(1, 0)
|
cs.EnterPropose(1, 0)
|
||||||
rs := cs.GetRoundState()
|
rs := cs.GetRoundState()
|
||||||
if rs.Proposal != nil {
|
if rs.Proposal != nil {
|
||||||
t.Error("Expected to make no proposal, since no privValidator")
|
t.Error("Expected to make no proposal, since no privValidator")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRunActionPropose(t *testing.T) {
|
func TestEnterPropose(t *testing.T) {
|
||||||
cs, privValidators := randConsensusState()
|
cs, privValidators := randConsensusState()
|
||||||
val0 := privValidators[0]
|
val0 := privValidators[0]
|
||||||
cs.SetPrivValidator(val0)
|
cs.SetPrivValidator(val0)
|
||||||
|
|
||||||
cs.RunActionPropose(1, 0)
|
cs.EnterPropose(1, 0)
|
||||||
rs := cs.GetRoundState()
|
rs := cs.GetRoundState()
|
||||||
|
|
||||||
// Check that Proposal, ProposalBlock, ProposalBlockParts are set.
|
// Check that Proposal, ProposalBlock, ProposalBlockParts are set.
|
||||||
|
@ -82,128 +35,4 @@ func TestRunActionPropose(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkRoundState(t *testing.T, rs *RoundState,
|
// TODO write better consensus state tests
|
||||||
height uint, round uint, step RoundStepType) {
|
|
||||||
if rs.Height != height {
|
|
||||||
t.Errorf("rs.Height should be %v, got %v", height, rs.Height)
|
|
||||||
}
|
|
||||||
if rs.Round != round {
|
|
||||||
t.Errorf("rs.Round should be %v, got %v", round, rs.Round)
|
|
||||||
}
|
|
||||||
if rs.Step != step {
|
|
||||||
t.Errorf("rs.Step should be %v, got %v", step, rs.Step)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestRunActionPrecommitCommitFinalize(t *testing.T) {
|
|
||||||
cs, privValidators := randConsensusState()
|
|
||||||
val0 := privValidators[0]
|
|
||||||
cs.SetPrivValidator(val0)
|
|
||||||
|
|
||||||
cs.RunActionPrecommit(1, 0)
|
|
||||||
<-cs.NewStepCh() // TODO: test this value too.
|
|
||||||
if cs.Precommits.GetByAddress(val0.Address) != nil {
|
|
||||||
t.Errorf("RunActionPrecommit should return nil without a proposal")
|
|
||||||
}
|
|
||||||
|
|
||||||
cs.RunActionPropose(1, 0)
|
|
||||||
<-cs.NewStepCh() // TODO: test this value too.
|
|
||||||
|
|
||||||
cs.RunActionPrecommit(1, 0)
|
|
||||||
<-cs.NewStepCh() // TODO: test this value too.
|
|
||||||
if cs.Precommits.GetByAddress(val0.Address) != nil {
|
|
||||||
t.Errorf("RunActionPrecommit should return nil, not enough prevotes")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add at least +2/3 prevotes.
|
|
||||||
for i := 0; i < 7; i++ {
|
|
||||||
vote := &types.Vote{
|
|
||||||
Height: 1,
|
|
||||||
Round: 0,
|
|
||||||
Type: types.VoteTypePrevote,
|
|
||||||
BlockHash: cs.ProposalBlock.Hash(),
|
|
||||||
BlockParts: cs.ProposalBlockParts.Header(),
|
|
||||||
}
|
|
||||||
err := privValidators[i].SignVote(cs.state.ChainID, vote)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error signing vote: %v", err)
|
|
||||||
}
|
|
||||||
cs.AddVote(privValidators[i].Address, vote)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test RunActionPrecommit success:
|
|
||||||
cs.RunActionPrecommit(1, 0)
|
|
||||||
<-cs.NewStepCh() // TODO: test this value too.
|
|
||||||
if cs.Precommits.GetByAddress(val0.Address) == nil {
|
|
||||||
t.Errorf("RunActionPrecommit should have succeeded")
|
|
||||||
}
|
|
||||||
checkRoundState(t, cs.GetRoundState(), 1, 0, RoundStepPrecommit)
|
|
||||||
|
|
||||||
// Add at least +2/3 precommits.
|
|
||||||
for i := 0; i < 7; i++ {
|
|
||||||
if bytes.Equal(privValidators[i].Address, val0.Address) {
|
|
||||||
if cs.Precommits.GetByAddress(val0.Address) == nil {
|
|
||||||
t.Errorf("Proposer should already have signed a precommit vote")
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
vote := &types.Vote{
|
|
||||||
Height: 1,
|
|
||||||
Round: 0,
|
|
||||||
Type: types.VoteTypePrecommit,
|
|
||||||
BlockHash: cs.ProposalBlock.Hash(),
|
|
||||||
BlockParts: cs.ProposalBlockParts.Header(),
|
|
||||||
}
|
|
||||||
err := privValidators[i].SignVote(cs.state.ChainID, vote)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error signing vote: %v", err)
|
|
||||||
}
|
|
||||||
added, _, err := cs.AddVote(privValidators[i].Address, vote)
|
|
||||||
if !added || err != nil {
|
|
||||||
t.Errorf("Error adding precommit: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test RunActionCommit success:
|
|
||||||
cs.RunActionCommit(1)
|
|
||||||
<-cs.NewStepCh() // TODO: test this value too.
|
|
||||||
if cs.Commits.GetByAddress(val0.Address) == nil {
|
|
||||||
t.Errorf("RunActionCommit should have succeeded")
|
|
||||||
}
|
|
||||||
checkRoundState(t, cs.GetRoundState(), 1, 0, RoundStepCommit)
|
|
||||||
|
|
||||||
// cs.CommitTime should still be zero
|
|
||||||
if !cs.CommitTime.IsZero() {
|
|
||||||
t.Errorf("Expected CommitTime to yet be zero")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add at least +2/3 commits.
|
|
||||||
for i := 0; i < 7; i++ {
|
|
||||||
if bytes.Equal(privValidators[i].Address, val0.Address) {
|
|
||||||
if cs.Commits.GetByAddress(val0.Address) == nil {
|
|
||||||
t.Errorf("Proposer should already have signed a commit vote")
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
vote := &types.Vote{
|
|
||||||
Height: 1,
|
|
||||||
Round: uint(i), // Doesn't matter what round
|
|
||||||
Type: types.VoteTypeCommit,
|
|
||||||
BlockHash: cs.ProposalBlock.Hash(),
|
|
||||||
BlockParts: cs.ProposalBlockParts.Header(),
|
|
||||||
}
|
|
||||||
err := privValidators[i].SignVote(cs.state.ChainID, vote)
|
|
||||||
if err != nil {
|
|
||||||
t.Error("Error signing vote: %v", err)
|
|
||||||
}
|
|
||||||
added, _, err := cs.AddVote(privValidators[i].Address, vote)
|
|
||||||
if !added || err != nil {
|
|
||||||
t.Errorf("Error adding commit: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Test TryFinalizeCommit:
|
|
||||||
cs.TryFinalizeCommit(1)
|
|
||||||
<-cs.NewStepCh() // TODO: test this value too.
|
|
||||||
checkRoundState(t, cs.GetRoundState(), 2, 0, RoundStepNewHeight)
|
|
||||||
}
|
|
||||||
|
|
|
@ -18,7 +18,7 @@ func randConsensusState() (*ConsensusState, []*sm.PrivValidator) {
|
||||||
return cs, privValidators
|
return cs, privValidators
|
||||||
}
|
}
|
||||||
|
|
||||||
func randVoteSet(height uint, round uint, type_ byte, numValidators int, votingPower uint64) (*VoteSet, *sm.ValidatorSet, []*sm.PrivValidator) {
|
func randVoteSet(height int, round int, type_ byte, numValidators int, votingPower int64) (*VoteSet, *sm.ValidatorSet, []*sm.PrivValidator) {
|
||||||
vals := make([]*sm.Validator, numValidators)
|
vals := make([]*sm.Validator, numValidators)
|
||||||
privValidators := make([]*sm.PrivValidator, numValidators)
|
privValidators := make([]*sm.PrivValidator, numValidators)
|
||||||
for i := 0; i < numValidators; i++ {
|
for i := 0; i < numValidators; i++ {
|
||||||
|
|
|
@ -17,32 +17,31 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Proposal struct {
|
type Proposal struct {
|
||||||
Height uint `json:"height"`
|
Height int `json:"height"`
|
||||||
Round uint `json:"round"`
|
Round int `json:"round"`
|
||||||
BlockParts types.PartSetHeader `json:"block_parts"`
|
BlockPartsHeader types.PartSetHeader `json:"block_parts_header"`
|
||||||
POLParts types.PartSetHeader `json:"pol_parts"`
|
POLRound int `json:"pol_round"` // -1 if null.
|
||||||
Signature account.SignatureEd25519 `json:"signature"`
|
Signature account.SignatureEd25519 `json:"signature"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewProposal(height uint, round uint, blockParts, polParts types.PartSetHeader) *Proposal {
|
func NewProposal(height int, round int, blockPartsHeader types.PartSetHeader, polRound int) *Proposal {
|
||||||
return &Proposal{
|
return &Proposal{
|
||||||
Height: height,
|
Height: height,
|
||||||
Round: round,
|
Round: round,
|
||||||
BlockParts: blockParts,
|
BlockPartsHeader: blockPartsHeader,
|
||||||
POLParts: polParts,
|
POLRound: polRound,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proposal) String() string {
|
func (p *Proposal) String() string {
|
||||||
return fmt.Sprintf("Proposal{%v/%v %v %v %v}", p.Height, p.Round,
|
return fmt.Sprintf("Proposal{%v/%v %v %v %v}", p.Height, p.Round,
|
||||||
p.BlockParts, p.POLParts, p.Signature)
|
p.BlockPartsHeader, p.POLRound, p.Signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *Proposal) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) {
|
func (p *Proposal) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) {
|
||||||
binary.WriteTo([]byte(Fmt(`{"chain_id":"%s"`, chainID)), w, n, err)
|
binary.WriteTo([]byte(Fmt(`{"chain_id":"%s"`, chainID)), w, n, err)
|
||||||
binary.WriteTo([]byte(`,"proposal":{"block_parts":`), w, n, err)
|
binary.WriteTo([]byte(`,"proposal":{"block_parts_header":`), w, n, err)
|
||||||
p.BlockParts.WriteSignBytes(w, n, err)
|
p.BlockPartsHeader.WriteSignBytes(w, n, err)
|
||||||
binary.WriteTo([]byte(Fmt(`,"height":%v,"pol_parts":`, p.Height)), w, n, err)
|
binary.WriteTo([]byte(Fmt(`,"height":%v,"pol_round":%v`, p.Height, p.POLRound)), w, n, err)
|
||||||
p.POLParts.WriteSignBytes(w, n, err)
|
|
||||||
binary.WriteTo([]byte(Fmt(`,"round":%v}}`, p.Round)), w, n, err)
|
binary.WriteTo([]byte(Fmt(`,"round":%v}}`, p.Round)), w, n, err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,15 +11,16 @@ import (
|
||||||
|
|
||||||
func TestProposalSignable(t *testing.T) {
|
func TestProposalSignable(t *testing.T) {
|
||||||
proposal := &Proposal{
|
proposal := &Proposal{
|
||||||
Height: 12345,
|
Height: 12345,
|
||||||
Round: 23456,
|
Round: 23456,
|
||||||
BlockParts: types.PartSetHeader{111, []byte("blockparts")},
|
BlockPartsHeader: types.PartSetHeader{111, []byte("blockparts")},
|
||||||
POLParts: types.PartSetHeader{222, []byte("polparts")},
|
POLRound: -1,
|
||||||
Signature: nil,
|
Signature: nil,
|
||||||
}
|
}
|
||||||
signBytes := account.SignBytes(config.GetString("chain_id"), proposal)
|
signBytes := account.SignBytes(config.GetString("chain_id"), proposal)
|
||||||
signStr := string(signBytes)
|
signStr := string(signBytes)
|
||||||
expected := Fmt(`{"chain_id":"%s","proposal":{"block_parts":{"hash":"626C6F636B7061727473","total":111},"height":12345,"pol_parts":{"hash":"706F6C7061727473","total":222},"round":23456}}`,
|
|
||||||
|
expected := Fmt(`{"chain_id":"%s","proposal":{"block_parts_header":{"hash":"626C6F636B7061727473","total":111},"height":12345,"pol_round":-1,"round":23456}}`,
|
||||||
config.GetString("chain_id"))
|
config.GetString("chain_id"))
|
||||||
if signStr != expected {
|
if signStr != expected {
|
||||||
t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signStr)
|
t.Errorf("Got unexpected sign string for SendTx. Expected:\n%v\nGot:\n%v", expected, signStr)
|
||||||
|
|
|
@ -19,29 +19,26 @@ import (
|
||||||
// A commit of prior rounds can be added added in lieu of votes/precommits.
|
// A commit of prior rounds can be added added in lieu of votes/precommits.
|
||||||
// NOTE: Assumes that the sum total of voting power does not exceed MaxUInt64.
|
// NOTE: Assumes that the sum total of voting power does not exceed MaxUInt64.
|
||||||
type VoteSet struct {
|
type VoteSet struct {
|
||||||
height uint
|
height int
|
||||||
round uint
|
round int
|
||||||
type_ byte
|
type_ byte
|
||||||
|
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
valSet *sm.ValidatorSet
|
valSet *sm.ValidatorSet
|
||||||
votes []*types.Vote // validator index -> vote
|
votes []*types.Vote // validator index -> vote
|
||||||
votesBitArray *BitArray // validator index -> has vote?
|
votesBitArray *BitArray // validator index -> has vote?
|
||||||
votesByBlock map[string]uint64 // string(blockHash)+string(blockParts) -> vote sum.
|
votesByBlock map[string]int64 // string(blockHash)+string(blockParts) -> vote sum.
|
||||||
totalVotes uint64
|
totalVotes int64
|
||||||
maj23Hash []byte
|
maj23Hash []byte
|
||||||
maj23Parts types.PartSetHeader
|
maj23Parts types.PartSetHeader
|
||||||
maj23Exists bool
|
maj23Exists bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constructs a new VoteSet struct used to accumulate votes for given height/round.
|
// Constructs a new VoteSet struct used to accumulate votes for given height/round.
|
||||||
func NewVoteSet(height uint, round uint, type_ byte, valSet *sm.ValidatorSet) *VoteSet {
|
func NewVoteSet(height int, round int, type_ byte, valSet *sm.ValidatorSet) *VoteSet {
|
||||||
if height == 0 {
|
if height == 0 {
|
||||||
panic("Cannot make VoteSet for height == 0, doesn't make sense.")
|
panic("Cannot make VoteSet for height == 0, doesn't make sense.")
|
||||||
}
|
}
|
||||||
if type_ == types.VoteTypeCommit && round != 0 {
|
|
||||||
panic("Expected round 0 for commit vote set")
|
|
||||||
}
|
|
||||||
return &VoteSet{
|
return &VoteSet{
|
||||||
height: height,
|
height: height,
|
||||||
round: round,
|
round: round,
|
||||||
|
@ -49,12 +46,12 @@ func NewVoteSet(height uint, round uint, type_ byte, valSet *sm.ValidatorSet) *V
|
||||||
valSet: valSet,
|
valSet: valSet,
|
||||||
votes: make([]*types.Vote, valSet.Size()),
|
votes: make([]*types.Vote, valSet.Size()),
|
||||||
votesBitArray: NewBitArray(valSet.Size()),
|
votesBitArray: NewBitArray(valSet.Size()),
|
||||||
votesByBlock: make(map[string]uint64),
|
votesByBlock: make(map[string]int64),
|
||||||
totalVotes: 0,
|
totalVotes: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (voteSet *VoteSet) Height() uint {
|
func (voteSet *VoteSet) Height() int {
|
||||||
if voteSet == nil {
|
if voteSet == nil {
|
||||||
return 0
|
return 0
|
||||||
} else {
|
} else {
|
||||||
|
@ -62,7 +59,15 @@ func (voteSet *VoteSet) Height() uint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (voteSet *VoteSet) Size() uint {
|
func (voteSet *VoteSet) Round() int {
|
||||||
|
if voteSet == nil {
|
||||||
|
return 0
|
||||||
|
} else {
|
||||||
|
return voteSet.round
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (voteSet *VoteSet) Size() int {
|
||||||
if voteSet == nil {
|
if voteSet == nil {
|
||||||
return 0
|
return 0
|
||||||
} else {
|
} else {
|
||||||
|
@ -70,21 +75,24 @@ func (voteSet *VoteSet) Size() uint {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// True if added, false if not.
|
// Returns added=true, index if vote was added
|
||||||
// Returns ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
|
// Otherwise returns err=ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
|
||||||
|
// Duplicate votes return added=false, err=nil.
|
||||||
// NOTE: vote should not be mutated after adding.
|
// NOTE: vote should not be mutated after adding.
|
||||||
// Returns the validator index of the vote unless error is set.
|
func (voteSet *VoteSet) AddByIndex(valIndex int, vote *types.Vote) (added bool, index int, err error) {
|
||||||
func (voteSet *VoteSet) Add(address []byte, vote *types.Vote) (bool, uint, error) {
|
|
||||||
voteSet.mtx.Lock()
|
voteSet.mtx.Lock()
|
||||||
defer voteSet.mtx.Unlock()
|
defer voteSet.mtx.Unlock()
|
||||||
|
|
||||||
// Make sure the step matches. (or that vote is commit && round < voteSet.round)
|
return voteSet.addByIndex(valIndex, vote)
|
||||||
if vote.Height != voteSet.height ||
|
}
|
||||||
(vote.Type != types.VoteTypeCommit && vote.Round != voteSet.round) ||
|
|
||||||
(vote.Type != types.VoteTypeCommit && vote.Type != voteSet.type_) ||
|
// Returns added=true, index if vote was added
|
||||||
(vote.Type == types.VoteTypeCommit && voteSet.type_ != types.VoteTypeCommit && vote.Round >= voteSet.round) {
|
// Otherwise returns err=ErrVote[UnexpectedStep|InvalidAccount|InvalidSignature|InvalidBlockHash|ConflictingSignature]
|
||||||
return false, 0, types.ErrVoteUnexpectedStep
|
// Duplicate votes return added=false, err=nil.
|
||||||
}
|
// NOTE: vote should not be mutated after adding.
|
||||||
|
func (voteSet *VoteSet) AddByAddress(address []byte, vote *types.Vote) (added bool, index int, err error) {
|
||||||
|
voteSet.mtx.Lock()
|
||||||
|
defer voteSet.mtx.Unlock()
|
||||||
|
|
||||||
// Ensure that signer is a validator.
|
// Ensure that signer is a validator.
|
||||||
valIndex, val := voteSet.valSet.GetByAddress(address)
|
valIndex, val := voteSet.valSet.GetByAddress(address)
|
||||||
|
@ -92,16 +100,34 @@ func (voteSet *VoteSet) Add(address []byte, vote *types.Vote) (bool, uint, error
|
||||||
return false, 0, types.ErrVoteInvalidAccount
|
return false, 0, types.ErrVoteInvalidAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return voteSet.addVote(val, valIndex, vote)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (voteSet *VoteSet) addByIndex(valIndex int, vote *types.Vote) (bool, int, error) {
|
||||||
|
// Ensure that signer is a validator.
|
||||||
|
_, val := voteSet.valSet.GetByIndex(valIndex)
|
||||||
|
if val == nil {
|
||||||
|
return false, 0, types.ErrVoteInvalidAccount
|
||||||
|
}
|
||||||
|
|
||||||
|
return voteSet.addVote(val, valIndex, vote)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (voteSet *VoteSet) addVote(val *sm.Validator, valIndex int, vote *types.Vote) (bool, int, error) {
|
||||||
|
|
||||||
|
// Make sure the step matches. (or that vote is commit && round < voteSet.round)
|
||||||
|
if (vote.Height != voteSet.height) ||
|
||||||
|
(vote.Round != voteSet.round) ||
|
||||||
|
(vote.Type != voteSet.type_) {
|
||||||
|
return false, 0, types.ErrVoteUnexpectedStep
|
||||||
|
}
|
||||||
|
|
||||||
// Check signature.
|
// Check signature.
|
||||||
if !val.PubKey.VerifyBytes(account.SignBytes(config.GetString("chain_id"), vote), vote.Signature) {
|
if !val.PubKey.VerifyBytes(account.SignBytes(config.GetString("chain_id"), vote), vote.Signature) {
|
||||||
// Bad signature.
|
// Bad signature.
|
||||||
return false, 0, types.ErrVoteInvalidSignature
|
return false, 0, types.ErrVoteInvalidSignature
|
||||||
}
|
}
|
||||||
|
|
||||||
return voteSet.addVote(valIndex, vote)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (voteSet *VoteSet) addVote(valIndex uint, vote *types.Vote) (bool, uint, error) {
|
|
||||||
// If vote already exists, return false.
|
// If vote already exists, return false.
|
||||||
if existingVote := voteSet.votes[valIndex]; existingVote != nil {
|
if existingVote := voteSet.votes[valIndex]; existingVote != nil {
|
||||||
if bytes.Equal(existingVote.BlockHash, vote.BlockHash) {
|
if bytes.Equal(existingVote.BlockHash, vote.BlockHash) {
|
||||||
|
@ -115,10 +141,6 @@ func (voteSet *VoteSet) addVote(valIndex uint, vote *types.Vote) (bool, uint, er
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add vote.
|
// Add vote.
|
||||||
_, val := voteSet.valSet.GetByIndex(valIndex)
|
|
||||||
if val == nil {
|
|
||||||
panic(fmt.Sprintf("Missing validator for index %v", valIndex))
|
|
||||||
}
|
|
||||||
voteSet.votes[valIndex] = vote
|
voteSet.votes[valIndex] = vote
|
||||||
voteSet.votesBitArray.SetIndex(valIndex, true)
|
voteSet.votesBitArray.SetIndex(valIndex, true)
|
||||||
blockKey := string(vote.BlockHash) + string(binary.BinaryBytes(vote.BlockParts))
|
blockKey := string(vote.BlockHash) + string(binary.BinaryBytes(vote.BlockParts))
|
||||||
|
@ -137,18 +159,6 @@ func (voteSet *VoteSet) addVote(valIndex uint, vote *types.Vote) (bool, uint, er
|
||||||
return true, valIndex, nil
|
return true, valIndex, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assumes that commits VoteSet is valid.
|
|
||||||
func (voteSet *VoteSet) AddFromCommits(commits *VoteSet) {
|
|
||||||
for valIndex, commit := range commits.votes {
|
|
||||||
if commit == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if commit.Round < voteSet.round {
|
|
||||||
voteSet.addVote(uint(valIndex), commit)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (voteSet *VoteSet) BitArray() *BitArray {
|
func (voteSet *VoteSet) BitArray() *BitArray {
|
||||||
if voteSet == nil {
|
if voteSet == nil {
|
||||||
return nil
|
return nil
|
||||||
|
@ -158,7 +168,7 @@ func (voteSet *VoteSet) BitArray() *BitArray {
|
||||||
return voteSet.votesBitArray.Copy()
|
return voteSet.votesBitArray.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (voteSet *VoteSet) GetByIndex(valIndex uint) *types.Vote {
|
func (voteSet *VoteSet) GetByIndex(valIndex int) *types.Vote {
|
||||||
voteSet.mtx.Lock()
|
voteSet.mtx.Lock()
|
||||||
defer voteSet.mtx.Unlock()
|
defer voteSet.mtx.Unlock()
|
||||||
return voteSet.votes[valIndex]
|
return voteSet.votes[valIndex]
|
||||||
|
@ -183,6 +193,15 @@ func (voteSet *VoteSet) HasTwoThirdsMajority() bool {
|
||||||
return voteSet.maj23Exists
|
return voteSet.maj23Exists
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (voteSet *VoteSet) HasTwoThirdsAny() bool {
|
||||||
|
if voteSet == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
voteSet.mtx.Lock()
|
||||||
|
defer voteSet.mtx.Unlock()
|
||||||
|
return voteSet.totalVotes > voteSet.valSet.TotalVotingPower()*2/3
|
||||||
|
}
|
||||||
|
|
||||||
// Returns either a blockhash (or nil) that received +2/3 majority.
|
// Returns either a blockhash (or nil) that received +2/3 majority.
|
||||||
// If there exists no such majority, returns (nil, false).
|
// If there exists no such majority, returns (nil, false).
|
||||||
func (voteSet *VoteSet) TwoThirdsMajority() (hash []byte, parts types.PartSetHeader, ok bool) {
|
func (voteSet *VoteSet) TwoThirdsMajority() (hash []byte, parts types.PartSetHeader, ok bool) {
|
||||||
|
@ -195,70 +214,10 @@ func (voteSet *VoteSet) TwoThirdsMajority() (hash []byte, parts types.PartSetHea
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (voteSet *VoteSet) MakePOL() *POL {
|
|
||||||
if voteSet.type_ != types.VoteTypePrevote {
|
|
||||||
panic("Cannot MakePOL() unless VoteSet.Type is types.VoteTypePrevote")
|
|
||||||
}
|
|
||||||
voteSet.mtx.Lock()
|
|
||||||
defer voteSet.mtx.Unlock()
|
|
||||||
if !voteSet.maj23Exists {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
pol := &POL{
|
|
||||||
Height: voteSet.height,
|
|
||||||
Round: voteSet.round,
|
|
||||||
BlockHash: voteSet.maj23Hash,
|
|
||||||
BlockParts: voteSet.maj23Parts,
|
|
||||||
Votes: make([]POLVoteSignature, voteSet.valSet.Size()),
|
|
||||||
}
|
|
||||||
for valIndex, vote := range voteSet.votes {
|
|
||||||
if vote == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !bytes.Equal(vote.BlockHash, voteSet.maj23Hash) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if !vote.BlockParts.Equals(voteSet.maj23Parts) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
pol.Votes[valIndex] = POLVoteSignature{
|
|
||||||
Round: vote.Round,
|
|
||||||
Signature: vote.Signature,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return pol
|
|
||||||
}
|
|
||||||
|
|
||||||
func (voteSet *VoteSet) MakeValidation() *types.Validation {
|
|
||||||
if voteSet.type_ != types.VoteTypeCommit {
|
|
||||||
panic("Cannot MakeValidation() unless VoteSet.Type is types.VoteTypeCommit")
|
|
||||||
}
|
|
||||||
voteSet.mtx.Lock()
|
|
||||||
defer voteSet.mtx.Unlock()
|
|
||||||
if len(voteSet.maj23Hash) == 0 {
|
|
||||||
panic("Cannot MakeValidation() unless a blockhash has +2/3")
|
|
||||||
}
|
|
||||||
commits := make([]types.Commit, voteSet.valSet.Size())
|
|
||||||
voteSet.valSet.Iterate(func(valIndex uint, val *sm.Validator) bool {
|
|
||||||
vote := voteSet.votes[valIndex]
|
|
||||||
if vote == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !bytes.Equal(vote.BlockHash, voteSet.maj23Hash) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
if !vote.BlockParts.Equals(voteSet.maj23Parts) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
commits[valIndex] = types.Commit{val.Address, vote.Round, vote.Signature}
|
|
||||||
return false
|
|
||||||
})
|
|
||||||
return &types.Validation{
|
|
||||||
Commits: commits,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (voteSet *VoteSet) String() string {
|
func (voteSet *VoteSet) String() string {
|
||||||
|
if voteSet == nil {
|
||||||
|
return "nil-VoteSet"
|
||||||
|
}
|
||||||
return voteSet.StringIndented("")
|
return voteSet.StringIndented("")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,3 +250,35 @@ func (voteSet *VoteSet) StringShort() string {
|
||||||
return fmt.Sprintf(`VoteSet{H:%v R:%v T:%v +2/3:%v %v}`,
|
return fmt.Sprintf(`VoteSet{H:%v R:%v T:%v +2/3:%v %v}`,
|
||||||
voteSet.height, voteSet.round, voteSet.type_, voteSet.maj23Exists, voteSet.votesBitArray)
|
voteSet.height, voteSet.round, voteSet.type_, voteSet.maj23Exists, voteSet.votesBitArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//--------------------------------------------------------------------------------
|
||||||
|
// Validation
|
||||||
|
|
||||||
|
func (voteSet *VoteSet) MakeValidation() *types.Validation {
|
||||||
|
if voteSet.type_ != types.VoteTypePrecommit {
|
||||||
|
panic("Cannot MakeValidation() unless VoteSet.Type is types.VoteTypePrecommit")
|
||||||
|
}
|
||||||
|
voteSet.mtx.Lock()
|
||||||
|
defer voteSet.mtx.Unlock()
|
||||||
|
if len(voteSet.maj23Hash) == 0 {
|
||||||
|
panic("Cannot MakeValidation() unless a blockhash has +2/3")
|
||||||
|
}
|
||||||
|
precommits := make([]*types.Vote, voteSet.valSet.Size())
|
||||||
|
voteSet.valSet.Iterate(func(valIndex int, val *sm.Validator) bool {
|
||||||
|
vote := voteSet.votes[valIndex]
|
||||||
|
if vote == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !bytes.Equal(vote.BlockHash, voteSet.maj23Hash) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !vote.BlockParts.Equals(voteSet.maj23Parts) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
precommits[valIndex] = vote
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
return &types.Validation{
|
||||||
|
Precommits: precommits,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,14 +15,14 @@ import (
|
||||||
// NOTE: see consensus/test.go for common test methods.
|
// NOTE: see consensus/test.go for common test methods.
|
||||||
|
|
||||||
// Convenience: Return new vote with different height
|
// Convenience: Return new vote with different height
|
||||||
func withHeight(vote *types.Vote, height uint) *types.Vote {
|
func withHeight(vote *types.Vote, height int) *types.Vote {
|
||||||
vote = vote.Copy()
|
vote = vote.Copy()
|
||||||
vote.Height = height
|
vote.Height = height
|
||||||
return vote
|
return vote
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convenience: Return new vote with different round
|
// Convenience: Return new vote with different round
|
||||||
func withRound(vote *types.Vote, round uint) *types.Vote {
|
func withRound(vote *types.Vote, round int) *types.Vote {
|
||||||
vote = vote.Copy()
|
vote = vote.Copy()
|
||||||
vote.Round = round
|
vote.Round = round
|
||||||
return vote
|
return vote
|
||||||
|
@ -51,12 +51,12 @@ func withBlockParts(vote *types.Vote, blockParts types.PartSetHeader) *types.Vot
|
||||||
|
|
||||||
func signAddVote(privVal *sm.PrivValidator, vote *types.Vote, voteSet *VoteSet) (bool, error) {
|
func signAddVote(privVal *sm.PrivValidator, vote *types.Vote, voteSet *VoteSet) (bool, error) {
|
||||||
privVal.SignVoteUnsafe(config.GetString("chain_id"), vote)
|
privVal.SignVoteUnsafe(config.GetString("chain_id"), vote)
|
||||||
added, _, err := voteSet.Add(privVal.Address, vote)
|
added, _, err := voteSet.AddByAddress(privVal.Address, vote)
|
||||||
return added, err
|
return added, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddVote(t *testing.T) {
|
func TestAddVote(t *testing.T) {
|
||||||
height, round := uint(1), uint(0)
|
height, round := 1, 0
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
voteSet, _, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
||||||
val0 := privValidators[0]
|
val0 := privValidators[0]
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ func TestAddVote(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test2_3Majority(t *testing.T) {
|
func Test2_3Majority(t *testing.T) {
|
||||||
height, round := uint(1), uint(0)
|
height, round := 1, 0
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
voteSet, _, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
||||||
|
|
||||||
vote := &types.Vote{Height: height, Round: round, Type: types.VoteTypePrevote, BlockHash: nil}
|
vote := &types.Vote{Height: height, Round: round, Type: types.VoteTypePrevote, BlockHash: nil}
|
||||||
|
@ -123,11 +123,11 @@ func Test2_3Majority(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test2_3MajorityRedux(t *testing.T) {
|
func Test2_3MajorityRedux(t *testing.T) {
|
||||||
height, round := uint(1), uint(0)
|
height, round := 1, 0
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 100, 1)
|
voteSet, _, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 100, 1)
|
||||||
|
|
||||||
blockHash := CRandBytes(32)
|
blockHash := CRandBytes(32)
|
||||||
blockPartsTotal := uint(123)
|
blockPartsTotal := 123
|
||||||
blockParts := types.PartSetHeader{blockPartsTotal, CRandBytes(32)}
|
blockParts := types.PartSetHeader{blockPartsTotal, CRandBytes(32)}
|
||||||
|
|
||||||
vote := &types.Vote{Height: height, Round: round, Type: types.VoteTypePrevote, BlockHash: blockHash, BlockParts: blockParts}
|
vote := &types.Vote{Height: height, Round: round, Type: types.VoteTypePrevote, BlockHash: blockHash, BlockParts: blockParts}
|
||||||
|
@ -190,104 +190,47 @@ func Test2_3MajorityRedux(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBadVotes(t *testing.T) {
|
func TestBadVotes(t *testing.T) {
|
||||||
height, round := uint(1), uint(0)
|
height, round := 1, 0
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
voteSet, _, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
||||||
|
|
||||||
// val0 votes for nil.
|
// val0 votes for nil.
|
||||||
vote := &types.Vote{Height: height, Round: round, Type: types.VoteTypePrevote, BlockHash: nil}
|
vote := &types.Vote{Height: height, Round: round, Type: types.VoteTypePrevote, BlockHash: nil}
|
||||||
added, err := signAddVote(privValidators[0], vote, voteSet)
|
added, err := signAddVote(privValidators[0], vote, voteSet)
|
||||||
if !added || err != nil {
|
if !added || err != nil {
|
||||||
t.Errorf("Expected Add() to succeed")
|
t.Errorf("Expected VoteSet.Add to succeed")
|
||||||
}
|
}
|
||||||
|
|
||||||
// val0 votes again for some block.
|
// val0 votes again for some block.
|
||||||
added, err = signAddVote(privValidators[0], withBlockHash(vote, RandBytes(32)), voteSet)
|
added, err = signAddVote(privValidators[0], withBlockHash(vote, RandBytes(32)), voteSet)
|
||||||
if added || err == nil {
|
if added || err == nil {
|
||||||
t.Errorf("Expected Add() to fail, dupeout.")
|
t.Errorf("Expected VoteSet.Add to fail, dupeout.")
|
||||||
}
|
}
|
||||||
|
|
||||||
// val1 votes on another height
|
// val1 votes on another height
|
||||||
added, err = signAddVote(privValidators[1], withHeight(vote, height+1), voteSet)
|
added, err = signAddVote(privValidators[1], withHeight(vote, height+1), voteSet)
|
||||||
if added {
|
if added {
|
||||||
t.Errorf("Expected Add() to fail, wrong height")
|
t.Errorf("Expected VoteSet.Add to fail, wrong height")
|
||||||
}
|
}
|
||||||
|
|
||||||
// val2 votes on another round
|
// val2 votes on another round
|
||||||
added, err = signAddVote(privValidators[2], withRound(vote, round+1), voteSet)
|
added, err = signAddVote(privValidators[2], withRound(vote, round+1), voteSet)
|
||||||
if added {
|
if added {
|
||||||
t.Errorf("Expected Add() to fail, wrong round")
|
t.Errorf("Expected VoteSet.Add to fail, wrong round")
|
||||||
}
|
}
|
||||||
|
|
||||||
// val3 votes of another type.
|
// val3 votes of another type.
|
||||||
added, err = signAddVote(privValidators[3], withType(vote, types.VoteTypePrecommit), voteSet)
|
added, err = signAddVote(privValidators[3], withType(vote, types.VoteTypePrecommit), voteSet)
|
||||||
if added {
|
if added {
|
||||||
t.Errorf("Expected Add() to fail, wrong type")
|
t.Errorf("Expected VoteSet.Add to fail, wrong type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAddCommitsToPrevoteVotes(t *testing.T) {
|
|
||||||
height, round := uint(2), uint(5)
|
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, types.VoteTypePrevote, 10, 1)
|
|
||||||
|
|
||||||
// val0, val1, val2, val3, val4, val5 vote for nil.
|
|
||||||
vote := &types.Vote{Height: height, Round: round, Type: types.VoteTypePrevote, BlockHash: nil}
|
|
||||||
for i := 0; i < 6; i++ {
|
|
||||||
signAddVote(privValidators[i], vote, voteSet)
|
|
||||||
}
|
|
||||||
hash, header, ok := voteSet.TwoThirdsMajority()
|
|
||||||
if hash != nil || !header.IsZero() || ok {
|
|
||||||
t.Errorf("There should be no 2/3 majority")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to add a commit from val6 at a previous height
|
|
||||||
vote = &types.Vote{Height: height - 1, Round: round, Type: types.VoteTypeCommit, BlockHash: nil}
|
|
||||||
added, _ := signAddVote(privValidators[6], vote, voteSet)
|
|
||||||
if added {
|
|
||||||
t.Errorf("Expected Add() to fail, wrong height.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to add a commit from val6 at a later round
|
|
||||||
vote = &types.Vote{Height: height, Round: round + 1, Type: types.VoteTypeCommit, BlockHash: nil}
|
|
||||||
added, _ = signAddVote(privValidators[6], vote, voteSet)
|
|
||||||
if added {
|
|
||||||
t.Errorf("Expected Add() to fail, cannot add future round vote.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Attempt to add a commit from val6 for currrent height/round.
|
|
||||||
vote = &types.Vote{Height: height, Round: round, Type: types.VoteTypeCommit, BlockHash: nil}
|
|
||||||
added, err := signAddVote(privValidators[6], vote, voteSet)
|
|
||||||
if added || err == nil {
|
|
||||||
t.Errorf("Expected Add() to fail, only prior round commits can be added.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add commit from val6 at a previous round
|
|
||||||
vote = &types.Vote{Height: height, Round: round - 1, Type: types.VoteTypeCommit, BlockHash: nil}
|
|
||||||
added, err = signAddVote(privValidators[6], vote, voteSet)
|
|
||||||
if !added || err != nil {
|
|
||||||
t.Errorf("Expected Add() to succeed, commit for prior rounds are relevant.")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Also add commit from val7 for previous round.
|
|
||||||
vote = &types.Vote{Height: height, Round: round - 2, Type: types.VoteTypeCommit, BlockHash: nil}
|
|
||||||
added, err = signAddVote(privValidators[7], vote, voteSet)
|
|
||||||
if !added || err != nil {
|
|
||||||
t.Errorf("Expected Add() to succeed. err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// We should have 2/3 majority
|
|
||||||
hash, header, ok = voteSet.TwoThirdsMajority()
|
|
||||||
if hash != nil || !header.IsZero() || !ok {
|
|
||||||
t.Errorf("There should be 2/3 majority for nil")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestMakeValidation(t *testing.T) {
|
func TestMakeValidation(t *testing.T) {
|
||||||
height, round := uint(1), uint(0)
|
height, round := 1, 0
|
||||||
voteSet, _, privValidators := randVoteSet(height, round, types.VoteTypeCommit, 10, 1)
|
voteSet, _, privValidators := randVoteSet(height, round, types.VoteTypePrecommit, 10, 1)
|
||||||
blockHash, blockParts := CRandBytes(32), types.PartSetHeader{123, CRandBytes(32)}
|
blockHash, blockParts := CRandBytes(32), types.PartSetHeader{123, CRandBytes(32)}
|
||||||
|
|
||||||
vote := &types.Vote{Height: height, Round: round, Type: types.VoteTypeCommit,
|
vote := &types.Vote{Height: height, Round: round, Type: types.VoteTypePrecommit,
|
||||||
BlockHash: blockHash, BlockParts: blockParts}
|
BlockHash: blockHash, BlockParts: blockParts}
|
||||||
|
|
||||||
// 6 out of 10 voted for some block.
|
// 6 out of 10 voted for some block.
|
||||||
|
@ -313,11 +256,11 @@ func TestMakeValidation(t *testing.T) {
|
||||||
validation := voteSet.MakeValidation()
|
validation := voteSet.MakeValidation()
|
||||||
|
|
||||||
// Validation should have 10 elements
|
// Validation should have 10 elements
|
||||||
if len(validation.Commits) != 10 {
|
if len(validation.Precommits) != 10 {
|
||||||
t.Errorf("Validation Commits should have the same number of commits as validators")
|
t.Errorf("Validation Precommits should have the same number of precommits as validators")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure that Validation commits are ordered.
|
// Ensure that Validation precommits are ordered.
|
||||||
if err := validation.ValidateBasic(); err != nil {
|
if err := validation.ValidateBasic(); err != nil {
|
||||||
t.Errorf("Error in Validation.ValidateBasic(): %v", err)
|
t.Errorf("Error in Validation.ValidateBasic(): %v", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,8 +33,8 @@ type Node struct {
|
||||||
|
|
||||||
LastSeen time.Time
|
LastSeen time.Time
|
||||||
ChainID string
|
ChainID string
|
||||||
BlockHeight uint
|
BlockHeight int
|
||||||
BlockHistory map[uint]time.Time // when we saw each block
|
BlockHistory map[int]time.Time // when we saw each block
|
||||||
NetInfo *rpctypes.ResponseNetInfo
|
NetInfo *rpctypes.ResponseNetInfo
|
||||||
|
|
||||||
Validator bool
|
Validator bool
|
||||||
|
|
|
@ -13,8 +13,8 @@ import (
|
||||||
type IAVLNode struct {
|
type IAVLNode struct {
|
||||||
key interface{}
|
key interface{}
|
||||||
value interface{}
|
value interface{}
|
||||||
height uint8
|
height int8
|
||||||
size uint
|
size int
|
||||||
hash []byte
|
hash []byte
|
||||||
leftHash []byte
|
leftHash []byte
|
||||||
leftNode *IAVLNode
|
leftNode *IAVLNode
|
||||||
|
@ -38,8 +38,8 @@ func ReadIAVLNode(t *IAVLTree, r io.Reader, n *int64, err *error) *IAVLNode {
|
||||||
node := &IAVLNode{}
|
node := &IAVLNode{}
|
||||||
|
|
||||||
// node header
|
// node header
|
||||||
node.height = binary.ReadUint8(r, n, err)
|
node.height = binary.ReadInt8(r, n, err)
|
||||||
node.size = binary.ReadUvarint(r, n, err)
|
node.size = binary.ReadVarint(r, n, err)
|
||||||
node.key = decodeByteSlice(t.keyCodec, r, n, err)
|
node.key = decodeByteSlice(t.keyCodec, r, n, err)
|
||||||
|
|
||||||
if node.height == 0 {
|
if node.height == 0 {
|
||||||
|
@ -88,7 +88,7 @@ func (node *IAVLNode) has(t *IAVLTree, key interface{}) (has bool) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *IAVLNode) get(t *IAVLTree, key interface{}) (index uint, value interface{}) {
|
func (node *IAVLNode) get(t *IAVLTree, key interface{}) (index int, value interface{}) {
|
||||||
if node.height == 0 {
|
if node.height == 0 {
|
||||||
if t.keyCodec.Compare(node.key, key) == 0 {
|
if t.keyCodec.Compare(node.key, key) == 0 {
|
||||||
return 0, node.value
|
return 0, node.value
|
||||||
|
@ -107,7 +107,7 @@ func (node *IAVLNode) get(t *IAVLTree, key interface{}) (index uint, value inter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (node *IAVLNode) getByIndex(t *IAVLTree, index uint) (key interface{}, value interface{}) {
|
func (node *IAVLNode) getByIndex(t *IAVLTree, index int) (key interface{}, value interface{}) {
|
||||||
if node.height == 0 {
|
if node.height == 0 {
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
return node.key, node.value
|
return node.key, node.value
|
||||||
|
@ -127,7 +127,7 @@ func (node *IAVLNode) getByIndex(t *IAVLTree, index uint) (key interface{}, valu
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: sets hashes recursively
|
// NOTE: sets hashes recursively
|
||||||
func (node *IAVLNode) hashWithCount(t *IAVLTree) ([]byte, uint) {
|
func (node *IAVLNode) hashWithCount(t *IAVLTree) ([]byte, int) {
|
||||||
if node.hash != nil {
|
if node.hash != nil {
|
||||||
return node.hash, 0
|
return node.hash, 0
|
||||||
}
|
}
|
||||||
|
@ -147,10 +147,10 @@ func (node *IAVLNode) hashWithCount(t *IAVLTree) ([]byte, uint) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE: sets hashes recursively
|
// NOTE: sets hashes recursively
|
||||||
func (node *IAVLNode) writeHashBytes(t *IAVLTree, w io.Writer) (n int64, hashCount uint, err error) {
|
func (node *IAVLNode) writeHashBytes(t *IAVLTree, w io.Writer) (n int64, hashCount int, err error) {
|
||||||
// height & size
|
// height & size
|
||||||
binary.WriteUint8(node.height, w, &n, &err)
|
binary.WriteInt8(node.height, w, &n, &err)
|
||||||
binary.WriteUvarint(node.size, w, &n, &err)
|
binary.WriteVarint(node.size, w, &n, &err)
|
||||||
// key is not written for inner nodes, unlike writePersistBytes
|
// key is not written for inner nodes, unlike writePersistBytes
|
||||||
|
|
||||||
if node.height == 0 {
|
if node.height == 0 {
|
||||||
|
@ -210,8 +210,8 @@ func (node *IAVLNode) save(t *IAVLTree) []byte {
|
||||||
// NOTE: sets hashes recursively
|
// NOTE: sets hashes recursively
|
||||||
func (node *IAVLNode) writePersistBytes(t *IAVLTree, w io.Writer) (n int64, err error) {
|
func (node *IAVLNode) writePersistBytes(t *IAVLTree, w io.Writer) (n int64, err error) {
|
||||||
// node header
|
// node header
|
||||||
binary.WriteUint8(node.height, w, &n, &err)
|
binary.WriteInt8(node.height, w, &n, &err)
|
||||||
binary.WriteUvarint(node.size, w, &n, &err)
|
binary.WriteVarint(node.size, w, &n, &err)
|
||||||
// key (unlike writeHashBytes, key is written for inner nodes)
|
// key (unlike writeHashBytes, key is written for inner nodes)
|
||||||
encodeByteSlice(node.key, t.keyCodec, w, &n, &err)
|
encodeByteSlice(node.key, t.keyCodec, w, &n, &err)
|
||||||
|
|
||||||
|
@ -365,7 +365,7 @@ func (node *IAVLNode) rotateLeft(t *IAVLTree) *IAVLNode {
|
||||||
|
|
||||||
// NOTE: mutates height and size
|
// NOTE: mutates height and size
|
||||||
func (node *IAVLNode) calcHeightAndSize(t *IAVLTree) {
|
func (node *IAVLNode) calcHeightAndSize(t *IAVLTree) {
|
||||||
node.height = maxUint8(node.getLeftNode(t).height, node.getRightNode(t).height) + 1
|
node.height = maxInt8(node.getLeftNode(t).height, node.getRightNode(t).height) + 1
|
||||||
node.size = node.getLeftNode(t).size + node.getRightNode(t).size
|
node.size = node.getLeftNode(t).size + node.getRightNode(t).size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,8 +35,8 @@ func (proof *IAVLProof) Verify(keyBytes, valueBytes, rootHash []byte) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
type IAVLProofInnerNode struct {
|
type IAVLProofInnerNode struct {
|
||||||
Height uint8
|
Height int8
|
||||||
Size uint
|
Size int
|
||||||
Left []byte
|
Left []byte
|
||||||
Right []byte
|
Right []byte
|
||||||
}
|
}
|
||||||
|
@ -45,8 +45,8 @@ func (branch IAVLProofInnerNode) Hash(childHash []byte) []byte {
|
||||||
hasher := sha256.New()
|
hasher := sha256.New()
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
n, err := int64(0), error(nil)
|
n, err := int64(0), error(nil)
|
||||||
binary.WriteUint8(branch.Height, buf, &n, &err)
|
binary.WriteInt8(branch.Height, buf, &n, &err)
|
||||||
binary.WriteUvarint(branch.Size, buf, &n, &err)
|
binary.WriteVarint(branch.Size, buf, &n, &err)
|
||||||
if branch.Left == nil {
|
if branch.Left == nil {
|
||||||
binary.WriteByteSlice(childHash, buf, &n, &err)
|
binary.WriteByteSlice(childHash, buf, &n, &err)
|
||||||
binary.WriteByteSlice(branch.Right, buf, &n, &err)
|
binary.WriteByteSlice(branch.Right, buf, &n, &err)
|
||||||
|
@ -71,8 +71,8 @@ func (leaf IAVLProofLeafNode) Hash() []byte {
|
||||||
hasher := sha256.New()
|
hasher := sha256.New()
|
||||||
buf := new(bytes.Buffer)
|
buf := new(bytes.Buffer)
|
||||||
n, err := int64(0), error(nil)
|
n, err := int64(0), error(nil)
|
||||||
binary.WriteUint8(0, buf, &n, &err)
|
binary.WriteInt8(0, buf, &n, &err)
|
||||||
binary.WriteUvarint(1, buf, &n, &err)
|
binary.WriteVarint(1, buf, &n, &err)
|
||||||
binary.WriteByteSlice(leaf.KeyBytes, buf, &n, &err)
|
binary.WriteByteSlice(leaf.KeyBytes, buf, &n, &err)
|
||||||
binary.WriteByteSlice(leaf.ValueBytes, buf, &n, &err)
|
binary.WriteByteSlice(leaf.ValueBytes, buf, &n, &err)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -60,7 +60,7 @@ func P(n *IAVLNode) string {
|
||||||
|
|
||||||
func TestUnit(t *testing.T) {
|
func TestUnit(t *testing.T) {
|
||||||
|
|
||||||
expectHash := func(tree *IAVLTree, hashCount uint) {
|
expectHash := func(tree *IAVLTree, hashCount int) {
|
||||||
// ensure number of new hash calculations is as expected.
|
// ensure number of new hash calculations is as expected.
|
||||||
hash, count := tree.HashWithCount()
|
hash, count := tree.HashWithCount()
|
||||||
if count != hashCount {
|
if count != hashCount {
|
||||||
|
@ -78,7 +78,7 @@ func TestUnit(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
expectSet := func(tree *IAVLTree, i int, repr string, hashCount uint) {
|
expectSet := func(tree *IAVLTree, i int, repr string, hashCount int) {
|
||||||
origNode := tree.root
|
origNode := tree.root
|
||||||
updated := tree.Set(i, "")
|
updated := tree.Set(i, "")
|
||||||
// ensure node was added & structure is as expected.
|
// ensure node was added & structure is as expected.
|
||||||
|
@ -91,7 +91,7 @@ func TestUnit(t *testing.T) {
|
||||||
tree.root = origNode
|
tree.root = origNode
|
||||||
}
|
}
|
||||||
|
|
||||||
expectRemove := func(tree *IAVLTree, i int, repr string, hashCount uint) {
|
expectRemove := func(tree *IAVLTree, i int, repr string, hashCount int) {
|
||||||
origNode := tree.root
|
origNode := tree.root
|
||||||
value, removed := tree.Remove(i)
|
value, removed := tree.Remove(i)
|
||||||
// ensure node was added & structure is as expected.
|
// ensure node was added & structure is as expected.
|
||||||
|
@ -168,7 +168,7 @@ func TestIntegration(t *testing.T) {
|
||||||
if !updated {
|
if !updated {
|
||||||
t.Error("should have been updated")
|
t.Error("should have been updated")
|
||||||
}
|
}
|
||||||
if tree.Size() != uint(i+1) {
|
if tree.Size() != i+1 {
|
||||||
t.Error("size was wrong", tree.Size(), i+1)
|
t.Error("size was wrong", tree.Size(), i+1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -203,7 +203,7 @@ func TestIntegration(t *testing.T) {
|
||||||
t.Error("wrong value")
|
t.Error("wrong value")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if tree.Size() != uint(len(records)-(i+1)) {
|
if tree.Size() != len(records)-(i+1) {
|
||||||
t.Error("size was wrong", tree.Size(), (len(records) - (i + 1)))
|
t.Error("size was wrong", tree.Size(), (len(records) - (i + 1)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -318,7 +318,7 @@ func BenchmarkImmutableAvlTree(b *testing.B) {
|
||||||
// 23000ns/op, 43000ops/s
|
// 23000ns/op, 43000ops/s
|
||||||
// for i := 0; i < 10000000; i++ {
|
// for i := 0; i < 10000000; i++ {
|
||||||
for i := 0; i < 1000000; i++ {
|
for i := 0; i < 1000000; i++ {
|
||||||
t.Set(RandUint64(), "")
|
t.Set(RandInt64(), "")
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Println("ok, starting")
|
fmt.Println("ok, starting")
|
||||||
|
@ -327,7 +327,7 @@ func BenchmarkImmutableAvlTree(b *testing.B) {
|
||||||
|
|
||||||
b.StartTimer()
|
b.StartTimer()
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
ri := RandUint64()
|
ri := RandInt64()
|
||||||
t.Set(ri, "")
|
t.Set(ri, "")
|
||||||
t.Remove(ri)
|
t.Remove(ri)
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,14 +68,14 @@ func (t *IAVLTree) Copy() Tree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *IAVLTree) Size() uint {
|
func (t *IAVLTree) Size() int {
|
||||||
if t.root == nil {
|
if t.root == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return t.root.size
|
return t.root.size
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *IAVLTree) Height() uint8 {
|
func (t *IAVLTree) Height() int8 {
|
||||||
if t.root == nil {
|
if t.root == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -106,7 +106,7 @@ func (t *IAVLTree) Hash() []byte {
|
||||||
return hash
|
return hash
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *IAVLTree) HashWithCount() ([]byte, uint) {
|
func (t *IAVLTree) HashWithCount() ([]byte, int) {
|
||||||
if t.root == nil {
|
if t.root == nil {
|
||||||
return nil, 0
|
return nil, 0
|
||||||
}
|
}
|
||||||
|
@ -130,14 +130,14 @@ func (t *IAVLTree) Load(hash []byte) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *IAVLTree) Get(key interface{}) (index uint, value interface{}) {
|
func (t *IAVLTree) Get(key interface{}) (index int, value interface{}) {
|
||||||
if t.root == nil {
|
if t.root == nil {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
return t.root.get(t, key)
|
return t.root.get(t, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *IAVLTree) GetByIndex(index uint) (key interface{}, value interface{}) {
|
func (t *IAVLTree) GetByIndex(index int) (key interface{}, value interface{}) {
|
||||||
if t.root == nil {
|
if t.root == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -90,8 +90,8 @@ func SimpleHashFromHashables(items []Hashable) []byte {
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
|
|
||||||
type SimpleProof struct {
|
type SimpleProof struct {
|
||||||
Index uint `json:"index"`
|
Index int `json:"index"`
|
||||||
Total uint `json:"total"`
|
Total int `json:"total"`
|
||||||
LeafHash []byte `json:"leaf_hash"`
|
LeafHash []byte `json:"leaf_hash"`
|
||||||
InnerHashes [][]byte `json:"inner_hashes"` // Hashes from leaf's sibling to a root's child.
|
InnerHashes [][]byte `json:"inner_hashes"` // Hashes from leaf's sibling to a root's child.
|
||||||
RootHash []byte `json:"root_hash"`
|
RootHash []byte `json:"root_hash"`
|
||||||
|
@ -103,8 +103,8 @@ func SimpleProofsFromHashables(items []Hashable) (proofs []*SimpleProof) {
|
||||||
proofs = make([]*SimpleProof, len(items))
|
proofs = make([]*SimpleProof, len(items))
|
||||||
for i, trail := range trails {
|
for i, trail := range trails {
|
||||||
proofs[i] = &SimpleProof{
|
proofs[i] = &SimpleProof{
|
||||||
Index: uint(i),
|
Index: i,
|
||||||
Total: uint(len(items)),
|
Total: len(items),
|
||||||
LeafHash: trail.Hash,
|
LeafHash: trail.Hash,
|
||||||
InnerHashes: trail.FlattenInnerHashes(),
|
InnerHashes: trail.FlattenInnerHashes(),
|
||||||
RootHash: root.Hash,
|
RootHash: root.Hash,
|
||||||
|
@ -154,7 +154,7 @@ func (sp *SimpleProof) StringIndented(indent string) string {
|
||||||
|
|
||||||
// Use the leafHash and innerHashes to get the root merkle hash.
|
// Use the leafHash and innerHashes to get the root merkle hash.
|
||||||
// If the length of the innerHashes slice isn't exactly correct, the result is nil.
|
// If the length of the innerHashes slice isn't exactly correct, the result is nil.
|
||||||
func computeHashFromInnerHashes(index uint, total uint, leafHash []byte, innerHashes [][]byte) []byte {
|
func computeHashFromInnerHashes(index int, total int, leafHash []byte, innerHashes [][]byte) []byte {
|
||||||
// Recursive impl.
|
// Recursive impl.
|
||||||
if index >= total {
|
if index >= total {
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -15,10 +15,10 @@ func (tI testItem) Hash() []byte {
|
||||||
|
|
||||||
func TestSimpleProof(t *testing.T) {
|
func TestSimpleProof(t *testing.T) {
|
||||||
|
|
||||||
numItems := uint(100)
|
numItems := 100
|
||||||
|
|
||||||
items := make([]Hashable, numItems)
|
items := make([]Hashable, numItems)
|
||||||
for i := uint(0); i < numItems; i++ {
|
for i := 0; i < numItems; i++ {
|
||||||
items[i] = testItem(RandBytes(32))
|
items[i] = testItem(RandBytes(32))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
package merkle
|
package merkle
|
||||||
|
|
||||||
type Tree interface {
|
type Tree interface {
|
||||||
Size() (size uint)
|
Size() (size int)
|
||||||
Height() (height uint8)
|
Height() (height int8)
|
||||||
Has(key interface{}) (has bool)
|
Has(key interface{}) (has bool)
|
||||||
Get(key interface{}) (index uint, value interface{})
|
Get(key interface{}) (index int, value interface{})
|
||||||
GetByIndex(index uint) (key interface{}, value interface{})
|
GetByIndex(index int) (key interface{}, value interface{})
|
||||||
Set(key interface{}, value interface{}) (updated bool)
|
Set(key interface{}, value interface{}) (updated bool)
|
||||||
Remove(key interface{}) (value interface{}, removed bool)
|
Remove(key interface{}) (value interface{}, removed bool)
|
||||||
HashWithCount() (hash []byte, count uint)
|
HashWithCount() (hash []byte, count int)
|
||||||
Hash() (hash []byte)
|
Hash() (hash []byte)
|
||||||
Save() (hash []byte)
|
Save() (hash []byte)
|
||||||
Load(hash []byte)
|
Load(hash []byte)
|
||||||
|
|
|
@ -35,7 +35,7 @@ func printIAVLNode(node *IAVLNode, indent int) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func maxUint8(a, b uint8) uint8 {
|
func maxInt8(a, b int8) int8 {
|
||||||
if a > b {
|
if a > b {
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
|
|
@ -715,7 +715,7 @@ func groupKey(na *NetAddress) string {
|
||||||
type knownAddress struct {
|
type knownAddress struct {
|
||||||
Addr *NetAddress
|
Addr *NetAddress
|
||||||
Src *NetAddress
|
Src *NetAddress
|
||||||
Attempts uint32
|
Attempts int32
|
||||||
LastAttempt time.Time
|
LastAttempt time.Time
|
||||||
LastSuccess time.Time
|
LastSuccess time.Time
|
||||||
BucketType byte
|
BucketType byte
|
||||||
|
|
|
@ -403,7 +403,7 @@ FOR_LOOP:
|
||||||
log.Debug("Receive Pong")
|
log.Debug("Receive Pong")
|
||||||
case packetTypeMsg:
|
case packetTypeMsg:
|
||||||
pkt, n, err := msgPacket{}, new(int64), new(error)
|
pkt, n, err := msgPacket{}, new(int64), new(error)
|
||||||
binary.ReadBinary(&pkt, c.bufReader, n, err)
|
binary.ReadBinaryPtr(&pkt, c.bufReader, n, err)
|
||||||
c.recvMonitor.Update(int(*n))
|
c.recvMonitor.Update(int(*n))
|
||||||
if *err != nil {
|
if *err != nil {
|
||||||
if atomic.LoadUint32(&c.stopped) != 1 {
|
if atomic.LoadUint32(&c.stopped) != 1 {
|
||||||
|
@ -441,9 +441,9 @@ FOR_LOOP:
|
||||||
|
|
||||||
type ChannelDescriptor struct {
|
type ChannelDescriptor struct {
|
||||||
Id byte
|
Id byte
|
||||||
Priority uint
|
Priority int
|
||||||
SendQueueCapacity uint
|
SendQueueCapacity int
|
||||||
RecvBufferCapacity uint
|
RecvBufferCapacity int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (chDesc *ChannelDescriptor) FillDefaults() {
|
func (chDesc *ChannelDescriptor) FillDefaults() {
|
||||||
|
@ -462,10 +462,10 @@ type Channel struct {
|
||||||
desc *ChannelDescriptor
|
desc *ChannelDescriptor
|
||||||
id byte
|
id byte
|
||||||
sendQueue chan []byte
|
sendQueue chan []byte
|
||||||
sendQueueSize uint32 // atomic.
|
sendQueueSize int32 // atomic.
|
||||||
recving []byte
|
recving []byte
|
||||||
sending []byte
|
sending []byte
|
||||||
priority uint
|
priority int
|
||||||
recentlySent int64 // exponential moving average
|
recentlySent int64 // exponential moving average
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -494,7 +494,7 @@ func (ch *Channel) sendBytes(bytes []byte) bool {
|
||||||
// timeout
|
// timeout
|
||||||
return false
|
return false
|
||||||
case ch.sendQueue <- bytes:
|
case ch.sendQueue <- bytes:
|
||||||
atomic.AddUint32(&ch.sendQueueSize, 1)
|
atomic.AddInt32(&ch.sendQueueSize, 1)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -505,7 +505,7 @@ func (ch *Channel) sendBytes(bytes []byte) bool {
|
||||||
func (ch *Channel) trySendBytes(bytes []byte) bool {
|
func (ch *Channel) trySendBytes(bytes []byte) bool {
|
||||||
select {
|
select {
|
||||||
case ch.sendQueue <- bytes:
|
case ch.sendQueue <- bytes:
|
||||||
atomic.AddUint32(&ch.sendQueueSize, 1)
|
atomic.AddInt32(&ch.sendQueueSize, 1)
|
||||||
return true
|
return true
|
||||||
default:
|
default:
|
||||||
return false
|
return false
|
||||||
|
@ -514,7 +514,7 @@ func (ch *Channel) trySendBytes(bytes []byte) bool {
|
||||||
|
|
||||||
// Goroutine-safe
|
// Goroutine-safe
|
||||||
func (ch *Channel) loadSendQueueSize() (size int) {
|
func (ch *Channel) loadSendQueueSize() (size int) {
|
||||||
return int(atomic.LoadUint32(&ch.sendQueueSize))
|
return int(atomic.LoadInt32(&ch.sendQueueSize))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Goroutine-safe
|
// Goroutine-safe
|
||||||
|
@ -545,7 +545,7 @@ func (ch *Channel) nextMsgPacket() msgPacket {
|
||||||
if len(ch.sending) <= maxMsgPacketSize {
|
if len(ch.sending) <= maxMsgPacketSize {
|
||||||
packet.EOF = byte(0x01)
|
packet.EOF = byte(0x01)
|
||||||
ch.sending = nil
|
ch.sending = nil
|
||||||
atomic.AddUint32(&ch.sendQueueSize, ^uint32(0)) // decrement sendQueueSize
|
atomic.AddInt32(&ch.sendQueueSize, -1) // decrement sendQueueSize
|
||||||
} else {
|
} else {
|
||||||
packet.EOF = byte(0x00)
|
packet.EOF = byte(0x00)
|
||||||
ch.sending = ch.sending[MinInt(maxMsgPacketSize, len(ch.sending)):]
|
ch.sending = ch.sending[MinInt(maxMsgPacketSize, len(ch.sending)):]
|
||||||
|
|
|
@ -44,7 +44,7 @@ func GetStorage(address, key []byte) (*ctypes.ResponseGetStorage, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListAccounts() (*ctypes.ResponseListAccounts, error) {
|
func ListAccounts() (*ctypes.ResponseListAccounts, error) {
|
||||||
var blockHeight uint
|
var blockHeight int
|
||||||
var accounts []*acm.Account
|
var accounts []*acm.Account
|
||||||
state := consensusState.GetState()
|
state := consensusState.GetState()
|
||||||
blockHeight = state.LastBlockHeight
|
blockHeight = state.LastBlockHeight
|
||||||
|
|
|
@ -9,14 +9,14 @@ import (
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
func BlockchainInfo(minHeight, maxHeight uint) (*ctypes.ResponseBlockchainInfo, error) {
|
func BlockchainInfo(minHeight, maxHeight int) (*ctypes.ResponseBlockchainInfo, error) {
|
||||||
if maxHeight == 0 {
|
if maxHeight == 0 {
|
||||||
maxHeight = blockStore.Height()
|
maxHeight = blockStore.Height()
|
||||||
} else {
|
} else {
|
||||||
maxHeight = MinUint(blockStore.Height(), maxHeight)
|
maxHeight = MinInt(blockStore.Height(), maxHeight)
|
||||||
}
|
}
|
||||||
if minHeight == 0 {
|
if minHeight == 0 {
|
||||||
minHeight = uint(MaxInt(1, int(maxHeight)-20))
|
minHeight = MaxInt(1, maxHeight-20)
|
||||||
}
|
}
|
||||||
log.Debug("BlockchainInfoHandler", "maxHeight", maxHeight, "minHeight", minHeight)
|
log.Debug("BlockchainInfoHandler", "maxHeight", maxHeight, "minHeight", minHeight)
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ func BlockchainInfo(minHeight, maxHeight uint) (*ctypes.ResponseBlockchainInfo,
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
func GetBlock(height uint) (*ctypes.ResponseGetBlock, error) {
|
func GetBlock(height int) (*ctypes.ResponseGetBlock, error) {
|
||||||
if height == 0 {
|
if height == 0 {
|
||||||
return nil, fmt.Errorf("height must be greater than 0")
|
return nil, fmt.Errorf("height must be greater than 0")
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,17 +8,17 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
func ListValidators() (*ctypes.ResponseListValidators, error) {
|
func ListValidators() (*ctypes.ResponseListValidators, error) {
|
||||||
var blockHeight uint
|
var blockHeight int
|
||||||
var bondedValidators []*sm.Validator
|
var bondedValidators []*sm.Validator
|
||||||
var unbondingValidators []*sm.Validator
|
var unbondingValidators []*sm.Validator
|
||||||
|
|
||||||
state := consensusState.GetState()
|
state := consensusState.GetState()
|
||||||
blockHeight = state.LastBlockHeight
|
blockHeight = state.LastBlockHeight
|
||||||
state.BondedValidators.Iterate(func(index uint, val *sm.Validator) bool {
|
state.BondedValidators.Iterate(func(index int, val *sm.Validator) bool {
|
||||||
bondedValidators = append(bondedValidators, val)
|
bondedValidators = append(bondedValidators, val)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
state.UnbondingValidators.Iterate(func(index uint, val *sm.Validator) bool {
|
state.UnbondingValidators.Iterate(func(index int, val *sm.Validator) bool {
|
||||||
unbondingValidators = append(unbondingValidators, val)
|
unbondingValidators = append(unbondingValidators, val)
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
|
|
@ -23,7 +23,7 @@ func BroadcastTx(tx types.Tx) (*ctypes.Receipt, error) {
|
||||||
if callTx, ok := tx.(*types.CallTx); ok {
|
if callTx, ok := tx.(*types.CallTx); ok {
|
||||||
if len(callTx.Address) == 0 {
|
if len(callTx.Address) == 0 {
|
||||||
createsContract = 1
|
createsContract = 1
|
||||||
contractAddr = state.NewContractAddress(callTx.Input.Address, uint64(callTx.Input.Sequence))
|
contractAddr = state.NewContractAddress(callTx.Input.Address, callTx.Input.Sequence)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &ctypes.Receipt{txHash, createsContract, contractAddr}, nil
|
return &ctypes.Receipt{txHash, createsContract, contractAddr}, nil
|
||||||
|
|
|
@ -17,7 +17,7 @@ func GetName(name string) (*types.NameRegEntry, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListNames() (*ctypes.ResponseListNames, error) {
|
func ListNames() (*ctypes.ResponseListNames, error) {
|
||||||
var blockHeight uint
|
var blockHeight int
|
||||||
var names []*types.NameRegEntry
|
var names []*types.NameRegEntry
|
||||||
state := consensusState.GetState()
|
state := consensusState.GetState()
|
||||||
blockHeight = state.LastBlockHeight
|
blockHeight = state.LastBlockHeight
|
||||||
|
|
|
@ -15,7 +15,7 @@ func toVMAccount(acc *account.Account) *vm.Account {
|
||||||
Address: LeftPadWord256(acc.Address),
|
Address: LeftPadWord256(acc.Address),
|
||||||
Balance: acc.Balance,
|
Balance: acc.Balance,
|
||||||
Code: acc.Code, // This is crazy.
|
Code: acc.Code, // This is crazy.
|
||||||
Nonce: uint64(acc.Sequence),
|
Nonce: int64(acc.Sequence),
|
||||||
StorageRoot: LeftPadWord256(acc.StorageRoot),
|
StorageRoot: LeftPadWord256(acc.StorageRoot),
|
||||||
Other: acc.PubKey,
|
Other: acc.PubKey,
|
||||||
}
|
}
|
||||||
|
@ -36,14 +36,14 @@ func Call(address, data []byte) (*ctypes.ResponseCall, error) {
|
||||||
caller := &vm.Account{Address: Zero256}
|
caller := &vm.Account{Address: Zero256}
|
||||||
txCache := state.NewTxCache(cache)
|
txCache := state.NewTxCache(cache)
|
||||||
params := vm.Params{
|
params := vm.Params{
|
||||||
BlockHeight: uint64(st.LastBlockHeight),
|
BlockHeight: int64(st.LastBlockHeight),
|
||||||
BlockHash: LeftPadWord256(st.LastBlockHash),
|
BlockHash: LeftPadWord256(st.LastBlockHash),
|
||||||
BlockTime: st.LastBlockTime.Unix(),
|
BlockTime: st.LastBlockTime.Unix(),
|
||||||
GasLimit: 10000000,
|
GasLimit: 10000000,
|
||||||
}
|
}
|
||||||
|
|
||||||
vmach := vm.NewVM(txCache, params, caller.Address, nil)
|
vmach := vm.NewVM(txCache, params, caller.Address, nil)
|
||||||
gas := uint64(1000000000)
|
gas := int64(1000000000)
|
||||||
ret, err := vmach.Call(caller, callee, callee.Code, data, 0, &gas)
|
ret, err := vmach.Call(caller, callee, callee.Code, data, 0, &gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -61,14 +61,14 @@ func CallCode(code, data []byte) (*ctypes.ResponseCall, error) {
|
||||||
caller := &vm.Account{Address: Zero256}
|
caller := &vm.Account{Address: Zero256}
|
||||||
txCache := state.NewTxCache(cache)
|
txCache := state.NewTxCache(cache)
|
||||||
params := vm.Params{
|
params := vm.Params{
|
||||||
BlockHeight: uint64(st.LastBlockHeight),
|
BlockHeight: int64(st.LastBlockHeight),
|
||||||
BlockHash: LeftPadWord256(st.LastBlockHash),
|
BlockHash: LeftPadWord256(st.LastBlockHash),
|
||||||
BlockTime: st.LastBlockTime.Unix(),
|
BlockTime: st.LastBlockTime.Unix(),
|
||||||
GasLimit: 10000000,
|
GasLimit: 10000000,
|
||||||
}
|
}
|
||||||
|
|
||||||
vmach := vm.NewVM(txCache, params, caller.Address, nil)
|
vmach := vm.NewVM(txCache, params, caller.Address, nil)
|
||||||
gas := uint64(1000000000)
|
gas := int64(1000000000)
|
||||||
ret, err := vmach.Call(caller, callee, code, data, 0, &gas)
|
ret, err := vmach.Call(caller, callee, code, data, 0, &gas)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
|
@ -13,12 +13,12 @@ type ResponseGetStorage struct {
|
||||||
|
|
||||||
type ResponseCall struct {
|
type ResponseCall struct {
|
||||||
Return []byte `json:"return"`
|
Return []byte `json:"return"`
|
||||||
GasUsed uint64 `json:"gas_used"`
|
GasUsed int64 `json:"gas_used"`
|
||||||
// TODO ...
|
// TODO ...
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResponseListAccounts struct {
|
type ResponseListAccounts struct {
|
||||||
BlockHeight uint `json:"block_height"`
|
BlockHeight int `json:"block_height"`
|
||||||
Accounts []*account.Account `json:"accounts"`
|
Accounts []*account.Account `json:"accounts"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,7 +33,7 @@ type ResponseDumpStorage struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResponseBlockchainInfo struct {
|
type ResponseBlockchainInfo struct {
|
||||||
LastHeight uint `json:"last_height"`
|
LastHeight int `json:"last_height"`
|
||||||
BlockMetas []*types.BlockMeta `json:"block_metas"`
|
BlockMetas []*types.BlockMeta `json:"block_metas"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ type ResponseStatus struct {
|
||||||
GenesisHash []byte `json:"genesis_hash"`
|
GenesisHash []byte `json:"genesis_hash"`
|
||||||
PubKey account.PubKey `json:"pub_key"`
|
PubKey account.PubKey `json:"pub_key"`
|
||||||
LatestBlockHash []byte `json:"latest_block_hash"`
|
LatestBlockHash []byte `json:"latest_block_hash"`
|
||||||
LatestBlockHeight uint `json:"latest_block_height"`
|
LatestBlockHeight int `json:"latest_block_height"`
|
||||||
LatestBlockTime int64 `json:"latest_block_time"` // nano
|
LatestBlockTime int64 `json:"latest_block_time"` // nano
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +71,7 @@ type Peer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResponseListValidators struct {
|
type ResponseListValidators struct {
|
||||||
BlockHeight uint `json:"block_height"`
|
BlockHeight int `json:"block_height"`
|
||||||
BondedValidators []*sm.Validator `json:"bonded_validators"`
|
BondedValidators []*sm.Validator `json:"bonded_validators"`
|
||||||
UnbondingValidators []*sm.Validator `json:"unbonding_validators"`
|
UnbondingValidators []*sm.Validator `json:"unbonding_validators"`
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,6 @@ type ResponseDumpConsensusState struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
type ResponseListNames struct {
|
type ResponseListNames struct {
|
||||||
BlockHeight uint `json:"block_height"`
|
BlockHeight int `json:"block_height"`
|
||||||
Names []*types.NameRegEntry `json:"names"`
|
Names []*types.NameRegEntry `json:"names"`
|
||||||
}
|
}
|
||||||
|
|
|
@ -224,7 +224,7 @@ type WSConnection struct {
|
||||||
wsConn *websocket.Conn
|
wsConn *websocket.Conn
|
||||||
writeChan chan WSResponse
|
writeChan chan WSResponse
|
||||||
quitChan chan struct{}
|
quitChan chan struct{}
|
||||||
failedSends uint
|
failedSends int
|
||||||
started uint32
|
started uint32
|
||||||
stopped uint32
|
stopped uint32
|
||||||
|
|
||||||
|
|
|
@ -51,7 +51,7 @@ func TestWSBlockchainGrowth(t *testing.T) {
|
||||||
// send a transaction and validate the events from listening for both sender and receiver
|
// send a transaction and validate the events from listening for both sender and receiver
|
||||||
func TestWSSend(t *testing.T) {
|
func TestWSSend(t *testing.T) {
|
||||||
toAddr := user[1].Address
|
toAddr := user[1].Address
|
||||||
amt := uint64(100)
|
amt := int64(100)
|
||||||
|
|
||||||
con := newWSCon(t)
|
con := newWSCon(t)
|
||||||
eidInput := types.EventStringAccInput(user[0].Address)
|
eidInput := types.EventStringAccInput(user[0].Address)
|
||||||
|
@ -79,7 +79,7 @@ func TestWSDoubleFire(t *testing.T) {
|
||||||
unsubscribe(t, con, eid)
|
unsubscribe(t, con, eid)
|
||||||
con.Close()
|
con.Close()
|
||||||
}()
|
}()
|
||||||
amt := uint64(100)
|
amt := int64(100)
|
||||||
toAddr := user[1].Address
|
toAddr := user[1].Address
|
||||||
// broadcast the transaction, wait to hear about it
|
// broadcast the transaction, wait to hear about it
|
||||||
waitForEvent(t, con, eid, true, func() {
|
waitForEvent(t, con, eid, true, func() {
|
||||||
|
@ -104,7 +104,7 @@ func TestWSCallWait(t *testing.T) {
|
||||||
unsubscribe(t, con, eid1)
|
unsubscribe(t, con, eid1)
|
||||||
con.Close()
|
con.Close()
|
||||||
}()
|
}()
|
||||||
amt, gasLim, fee := uint64(10000), uint64(1000), uint64(1000)
|
amt, gasLim, fee := int64(10000), int64(1000), int64(1000)
|
||||||
code, returnCode, returnVal := simpleContract()
|
code, returnCode, returnVal := simpleContract()
|
||||||
var contractAddr []byte
|
var contractAddr []byte
|
||||||
// wait for the contract to be created
|
// wait for the contract to be created
|
||||||
|
@ -115,7 +115,7 @@ func TestWSCallWait(t *testing.T) {
|
||||||
}, unmarshalValidateCall(amt, returnCode))
|
}, unmarshalValidateCall(amt, returnCode))
|
||||||
|
|
||||||
// susbscribe to the new contract
|
// susbscribe to the new contract
|
||||||
amt = uint64(10001)
|
amt = int64(10001)
|
||||||
eid2 := types.EventStringAccOutput(contractAddr)
|
eid2 := types.EventStringAccOutput(contractAddr)
|
||||||
subscribe(t, con, eid2)
|
subscribe(t, con, eid2)
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -134,7 +134,7 @@ func TestWSCallWait(t *testing.T) {
|
||||||
// and validate return
|
// and validate return
|
||||||
func TestWSCallNoWait(t *testing.T) {
|
func TestWSCallNoWait(t *testing.T) {
|
||||||
con := newWSCon(t)
|
con := newWSCon(t)
|
||||||
amt, gasLim, fee := uint64(10000), uint64(1000), uint64(1000)
|
amt, gasLim, fee := int64(10000), int64(1000), int64(1000)
|
||||||
code, _, returnVal := simpleContract()
|
code, _, returnVal := simpleContract()
|
||||||
|
|
||||||
tx := makeDefaultCallTx(t, wsTyp, nil, code, amt, gasLim, fee)
|
tx := makeDefaultCallTx(t, wsTyp, nil, code, amt, gasLim, fee)
|
||||||
|
@ -142,7 +142,7 @@ func TestWSCallNoWait(t *testing.T) {
|
||||||
contractAddr := receipt.ContractAddr
|
contractAddr := receipt.ContractAddr
|
||||||
|
|
||||||
// susbscribe to the new contract
|
// susbscribe to the new contract
|
||||||
amt = uint64(10001)
|
amt = int64(10001)
|
||||||
eid := types.EventStringAccOutput(contractAddr)
|
eid := types.EventStringAccOutput(contractAddr)
|
||||||
subscribe(t, con, eid)
|
subscribe(t, con, eid)
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -160,7 +160,7 @@ func TestWSCallNoWait(t *testing.T) {
|
||||||
// create two contracts, one of which calls the other
|
// create two contracts, one of which calls the other
|
||||||
func TestWSCallCall(t *testing.T) {
|
func TestWSCallCall(t *testing.T) {
|
||||||
con := newWSCon(t)
|
con := newWSCon(t)
|
||||||
amt, gasLim, fee := uint64(10000), uint64(1000), uint64(1000)
|
amt, gasLim, fee := int64(10000), int64(1000), int64(1000)
|
||||||
code, _, returnVal := simpleContract()
|
code, _, returnVal := simpleContract()
|
||||||
txid := new([]byte)
|
txid := new([]byte)
|
||||||
|
|
||||||
|
@ -175,7 +175,7 @@ func TestWSCallCall(t *testing.T) {
|
||||||
contractAddr2 := receipt.ContractAddr
|
contractAddr2 := receipt.ContractAddr
|
||||||
|
|
||||||
// susbscribe to the new contracts
|
// susbscribe to the new contracts
|
||||||
amt = uint64(10001)
|
amt = int64(10001)
|
||||||
eid1 := types.EventStringAccReceive(contractAddr1)
|
eid1 := types.EventStringAccReceive(contractAddr1)
|
||||||
subscribe(t, con, eid1)
|
subscribe(t, con, eid1)
|
||||||
defer func() {
|
defer func() {
|
||||||
|
|
|
@ -4,11 +4,9 @@ import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"strconv"
|
"strconv"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/tendermint/tendermint/account"
|
"github.com/tendermint/tendermint/account"
|
||||||
. "github.com/tendermint/tendermint/common"
|
. "github.com/tendermint/tendermint/common"
|
||||||
"github.com/tendermint/tendermint/consensus"
|
|
||||||
nm "github.com/tendermint/tendermint/node"
|
nm "github.com/tendermint/tendermint/node"
|
||||||
"github.com/tendermint/tendermint/p2p"
|
"github.com/tendermint/tendermint/p2p"
|
||||||
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
ctypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
|
@ -79,8 +77,7 @@ func init() {
|
||||||
priv.SetFile(config.GetString("priv_validator_file"))
|
priv.SetFile(config.GetString("priv_validator_file"))
|
||||||
priv.Save()
|
priv.Save()
|
||||||
|
|
||||||
consensus.RoundDuration0 = 2 * time.Second
|
// TODO: change consensus/state.go timeouts to be shorter
|
||||||
consensus.RoundDurationDelta = 1 * time.Second
|
|
||||||
|
|
||||||
// start a node
|
// start a node
|
||||||
ready := make(chan struct{})
|
ready := make(chan struct{})
|
||||||
|
@ -91,7 +88,7 @@ func init() {
|
||||||
//-------------------------------------------------------------------------------
|
//-------------------------------------------------------------------------------
|
||||||
// some default transaction functions
|
// some default transaction functions
|
||||||
|
|
||||||
func makeDefaultSendTx(t *testing.T, typ string, addr []byte, amt uint64) *types.SendTx {
|
func makeDefaultSendTx(t *testing.T, typ string, addr []byte, amt int64) *types.SendTx {
|
||||||
nonce := getNonce(t, typ, user[0].Address)
|
nonce := getNonce(t, typ, user[0].Address)
|
||||||
tx := types.NewSendTx()
|
tx := types.NewSendTx()
|
||||||
tx.AddInputWithNonce(user[0].PubKey, amt, nonce+1)
|
tx.AddInputWithNonce(user[0].PubKey, amt, nonce+1)
|
||||||
|
@ -99,20 +96,20 @@ func makeDefaultSendTx(t *testing.T, typ string, addr []byte, amt uint64) *types
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeDefaultSendTxSigned(t *testing.T, typ string, addr []byte, amt uint64) *types.SendTx {
|
func makeDefaultSendTxSigned(t *testing.T, typ string, addr []byte, amt int64) *types.SendTx {
|
||||||
tx := makeDefaultSendTx(t, typ, addr, amt)
|
tx := makeDefaultSendTx(t, typ, addr, amt)
|
||||||
tx.SignInput(chainID, 0, user[0])
|
tx.SignInput(chainID, 0, user[0])
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeDefaultCallTx(t *testing.T, typ string, addr, code []byte, amt, gasLim, fee uint64) *types.CallTx {
|
func makeDefaultCallTx(t *testing.T, typ string, addr, code []byte, amt, gasLim, fee int64) *types.CallTx {
|
||||||
nonce := getNonce(t, typ, user[0].Address)
|
nonce := getNonce(t, typ, user[0].Address)
|
||||||
tx := types.NewCallTxWithNonce(user[0].PubKey, addr, code, amt, gasLim, fee, nonce+1)
|
tx := types.NewCallTxWithNonce(user[0].PubKey, addr, code, amt, gasLim, fee, nonce+1)
|
||||||
tx.Sign(chainID, user[0])
|
tx.Sign(chainID, user[0])
|
||||||
return tx
|
return tx
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeDefaultNameTx(t *testing.T, typ string, name, value string, amt, fee uint64) *types.NameTx {
|
func makeDefaultNameTx(t *testing.T, typ string, name, value string, amt, fee int64) *types.NameTx {
|
||||||
nonce := getNonce(t, typ, user[0].Address)
|
nonce := getNonce(t, typ, user[0].Address)
|
||||||
tx := types.NewNameTxWithNonce(user[0].PubKey, name, value, amt, fee, nonce+1)
|
tx := types.NewNameTxWithNonce(user[0].PubKey, name, value, amt, fee, nonce+1)
|
||||||
tx.Sign(chainID, user[0])
|
tx.Sign(chainID, user[0])
|
||||||
|
@ -123,7 +120,7 @@ func makeDefaultNameTx(t *testing.T, typ string, name, value string, amt, fee ui
|
||||||
// rpc call wrappers (fail on err)
|
// rpc call wrappers (fail on err)
|
||||||
|
|
||||||
// get an account's nonce
|
// get an account's nonce
|
||||||
func getNonce(t *testing.T, typ string, addr []byte) uint {
|
func getNonce(t *testing.T, typ string, addr []byte) int {
|
||||||
client := clients[typ]
|
client := clients[typ]
|
||||||
ac, err := client.GetAccount(addr)
|
ac, err := client.GetAccount(addr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -45,7 +45,7 @@ func testGetAccount(t *testing.T, typ string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSignedTx(t *testing.T, typ string) {
|
func testSignedTx(t *testing.T, typ string) {
|
||||||
amt := uint64(100)
|
amt := int64(100)
|
||||||
toAddr := user[1].Address
|
toAddr := user[1].Address
|
||||||
testOneSignTx(t, typ, toAddr, amt)
|
testOneSignTx(t, typ, toAddr, amt)
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ func testSignedTx(t *testing.T, typ string) {
|
||||||
testOneSignTx(t, typ, toAddr, amt)
|
testOneSignTx(t, typ, toAddr, amt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testOneSignTx(t *testing.T, typ string, addr []byte, amt uint64) {
|
func testOneSignTx(t *testing.T, typ string, addr []byte, amt int64) {
|
||||||
tx := makeDefaultSendTx(t, typ, addr, amt)
|
tx := makeDefaultSendTx(t, typ, addr, amt)
|
||||||
tx2 := signTx(t, typ, tx, user[0])
|
tx2 := signTx(t, typ, tx, user[0])
|
||||||
tx2hash := account.HashSignBytes(chainID, tx2)
|
tx2hash := account.HashSignBytes(chainID, tx2)
|
||||||
|
@ -72,7 +72,7 @@ func testOneSignTx(t *testing.T, typ string, addr []byte, amt uint64) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func testBroadcastTx(t *testing.T, typ string) {
|
func testBroadcastTx(t *testing.T, typ string) {
|
||||||
amt := uint64(100)
|
amt := int64(100)
|
||||||
toAddr := user[1].Address
|
toAddr := user[1].Address
|
||||||
tx := makeDefaultSendTxSigned(t, typ, toAddr, amt)
|
tx := makeDefaultSendTxSigned(t, typ, toAddr, amt)
|
||||||
receipt := broadcastTx(t, typ, tx)
|
receipt := broadcastTx(t, typ, tx)
|
||||||
|
@ -106,7 +106,7 @@ func testGetStorage(t *testing.T, typ string) {
|
||||||
con.Close()
|
con.Close()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
amt, gasLim, fee := uint64(1100), uint64(1000), uint64(1000)
|
amt, gasLim, fee := int64(1100), int64(1000), int64(1000)
|
||||||
code := []byte{0x60, 0x5, 0x60, 0x1, 0x55}
|
code := []byte{0x60, 0x5, 0x60, 0x1, 0x55}
|
||||||
tx := makeDefaultCallTx(t, typ, nil, code, amt, gasLim, fee)
|
tx := makeDefaultCallTx(t, typ, nil, code, amt, gasLim, fee)
|
||||||
receipt := broadcastTx(t, typ, tx)
|
receipt := broadcastTx(t, typ, tx)
|
||||||
|
@ -161,7 +161,7 @@ func testCall(t *testing.T, typ string) {
|
||||||
client := clients[typ]
|
client := clients[typ]
|
||||||
|
|
||||||
// create the contract
|
// create the contract
|
||||||
amt, gasLim, fee := uint64(6969), uint64(1000), uint64(1000)
|
amt, gasLim, fee := int64(6969), int64(1000), int64(1000)
|
||||||
code, _, _ := simpleContract()
|
code, _, _ := simpleContract()
|
||||||
tx := makeDefaultCallTx(t, typ, nil, code, amt, gasLim, fee)
|
tx := makeDefaultCallTx(t, typ, nil, code, amt, gasLim, fee)
|
||||||
receipt := broadcastTx(t, typ, tx)
|
receipt := broadcastTx(t, typ, tx)
|
||||||
|
@ -203,8 +203,8 @@ func testNameReg(t *testing.T, typ string) {
|
||||||
// since entries ought to be unique and these run against different clients, we append the typ
|
// since entries ought to be unique and these run against different clients, we append the typ
|
||||||
name := "ye_old_domain_name_" + typ
|
name := "ye_old_domain_name_" + typ
|
||||||
data := "if not now, when"
|
data := "if not now, when"
|
||||||
fee := uint64(1000)
|
fee := int64(1000)
|
||||||
numDesiredBlocks := uint64(2)
|
numDesiredBlocks := int64(2)
|
||||||
amt := fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
amt := fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
||||||
|
|
||||||
tx := makeDefaultNameTx(t, typ, name, data, amt, fee)
|
tx := makeDefaultNameTx(t, typ, name, data, amt, fee)
|
||||||
|
@ -221,7 +221,7 @@ func testNameReg(t *testing.T, typ string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the data as the owner, make sure still there
|
// update the data as the owner, make sure still there
|
||||||
numDesiredBlocks = uint64(2)
|
numDesiredBlocks = int64(2)
|
||||||
data = "these are amongst the things I wish to bestow upon the youth of generations come: a safe supply of honey, and a better money. For what else shall they need"
|
data = "these are amongst the things I wish to bestow upon the youth of generations come: a safe supply of honey, and a better money. For what else shall they need"
|
||||||
amt = fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
amt = fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
||||||
tx = makeDefaultNameTx(t, typ, name, data, amt, fee)
|
tx = makeDefaultNameTx(t, typ, name, data, amt, fee)
|
||||||
|
|
|
@ -133,7 +133,7 @@ func unmarshalResponseNewBlock(b []byte) (*types.Block, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalValidateBlockchain(t *testing.T, con *websocket.Conn, eid string) {
|
func unmarshalValidateBlockchain(t *testing.T, con *websocket.Conn, eid string) {
|
||||||
var initBlockN uint
|
var initBlockN int
|
||||||
for i := 0; i < 2; i++ {
|
for i := 0; i < 2; i++ {
|
||||||
waitForEvent(t, con, eid, true, func() {}, func(eid string, b []byte) error {
|
waitForEvent(t, con, eid, true, func() {}, func(eid string, b []byte) error {
|
||||||
block, err := unmarshalResponseNewBlock(b)
|
block, err := unmarshalResponseNewBlock(b)
|
||||||
|
@ -143,7 +143,7 @@ func unmarshalValidateBlockchain(t *testing.T, con *websocket.Conn, eid string)
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
initBlockN = block.Header.Height
|
initBlockN = block.Header.Height
|
||||||
} else {
|
} else {
|
||||||
if block.Header.Height != initBlockN+uint(i) {
|
if block.Header.Height != initBlockN+i {
|
||||||
return fmt.Errorf("Expected block %d, got block %d", i, block.Header.Height)
|
return fmt.Errorf("Expected block %d, got block %d", i, block.Header.Height)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ func unmarshalValidateBlockchain(t *testing.T, con *websocket.Conn, eid string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalValidateSend(amt uint64, toAddr []byte) func(string, []byte) error {
|
func unmarshalValidateSend(amt int64, toAddr []byte) func(string, []byte) error {
|
||||||
return func(eid string, b []byte) error {
|
return func(eid string, b []byte) error {
|
||||||
// unmarshal and assert correctness
|
// unmarshal and assert correctness
|
||||||
var response struct {
|
var response struct {
|
||||||
|
@ -186,7 +186,7 @@ func unmarshalValidateSend(amt uint64, toAddr []byte) func(string, []byte) error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func unmarshalValidateCall(amt uint64, returnCode []byte) func(string, []byte) error {
|
func unmarshalValidateCall(amt int64, returnCode []byte) func(string, []byte) error {
|
||||||
return func(eid string, b []byte) error {
|
return func(eid string, b []byte) error {
|
||||||
// unmarshall and assert somethings
|
// unmarshall and assert somethings
|
||||||
var response struct {
|
var response struct {
|
||||||
|
|
|
@ -38,53 +38,29 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Validate block Validation.
|
// Validate block LastValidation.
|
||||||
if block.Height == 1 {
|
if block.Height == 1 {
|
||||||
if len(block.Validation.Commits) != 0 {
|
if len(block.LastValidation.Precommits) != 0 {
|
||||||
return errors.New("Block at height 1 (first block) should have no Validation commits")
|
return errors.New("Block at height 1 (first block) should have no LastValidation precommits")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if uint(len(block.Validation.Commits)) != s.LastBondedValidators.Size() {
|
if len(block.LastValidation.Precommits) != s.LastBondedValidators.Size() {
|
||||||
return errors.New(Fmt("Invalid block validation size. Expected %v, got %v",
|
return errors.New(Fmt("Invalid block validation size. Expected %v, got %v",
|
||||||
s.LastBondedValidators.Size(), len(block.Validation.Commits)))
|
s.LastBondedValidators.Size(), len(block.LastValidation.Precommits)))
|
||||||
}
|
}
|
||||||
var sumVotingPower uint64
|
err := s.LastBondedValidators.VerifyValidation(
|
||||||
s.LastBondedValidators.Iterate(func(index uint, val *Validator) bool {
|
s.ChainID, s.LastBlockHash, s.LastBlockParts, block.Height-1, block.LastValidation)
|
||||||
commit := block.Validation.Commits[index]
|
|
||||||
if commit.IsZero() {
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
vote := &types.Vote{
|
|
||||||
Height: block.Height - 1,
|
|
||||||
Round: commit.Round,
|
|
||||||
Type: types.VoteTypeCommit,
|
|
||||||
BlockHash: block.LastBlockHash,
|
|
||||||
BlockParts: block.LastBlockParts,
|
|
||||||
}
|
|
||||||
if val.PubKey.VerifyBytes(account.SignBytes(s.ChainID, vote), commit.Signature) {
|
|
||||||
sumVotingPower += val.VotingPower
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
log.Warn(Fmt("Invalid validation signature.\nval: %v\nvote: %v", val, vote))
|
|
||||||
err = errors.New("Invalid validation signature")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if sumVotingPower <= s.LastBondedValidators.TotalVotingPower()*2/3 {
|
|
||||||
return errors.New("Insufficient validation voting power")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Validator.LastCommitHeight as necessary.
|
// Update Validator.LastCommitHeight as necessary.
|
||||||
for i, commit := range block.Validation.Commits {
|
for i, precommit := range block.LastValidation.Precommits {
|
||||||
if commit.IsZero() {
|
if precommit == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, val := s.LastBondedValidators.GetByIndex(uint(i))
|
_, val := s.LastBondedValidators.GetByIndex(i)
|
||||||
if val == nil {
|
if val == nil {
|
||||||
panic(Fmt("Failed to fetch validator at index %v", i))
|
panic(Fmt("Failed to fetch validator at index %v", i))
|
||||||
}
|
}
|
||||||
|
@ -111,7 +87,7 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade
|
||||||
// Create BlockCache to cache changes to state.
|
// Create BlockCache to cache changes to state.
|
||||||
blockCache := NewBlockCache(s)
|
blockCache := NewBlockCache(s)
|
||||||
|
|
||||||
// Commit each tx
|
// Execute each tx
|
||||||
for _, tx := range block.Data.Txs {
|
for _, tx := range block.Data.Txs {
|
||||||
err := ExecTx(blockCache, tx, true, s.evc)
|
err := ExecTx(blockCache, tx, true, s.evc)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -125,7 +101,7 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade
|
||||||
// If any unbonding periods are over,
|
// If any unbonding periods are over,
|
||||||
// reward account with bonded coins.
|
// reward account with bonded coins.
|
||||||
toRelease := []*Validator{}
|
toRelease := []*Validator{}
|
||||||
s.UnbondingValidators.Iterate(func(index uint, val *Validator) bool {
|
s.UnbondingValidators.Iterate(func(index int, val *Validator) bool {
|
||||||
if val.UnbondHeight+unbondingPeriodBlocks < block.Height {
|
if val.UnbondHeight+unbondingPeriodBlocks < block.Height {
|
||||||
toRelease = append(toRelease, val)
|
toRelease = append(toRelease, val)
|
||||||
}
|
}
|
||||||
|
@ -138,8 +114,8 @@ func execBlock(s *State, block *types.Block, blockPartsHeader types.PartSetHeade
|
||||||
// If any validators haven't signed in a while,
|
// If any validators haven't signed in a while,
|
||||||
// unbond them, they have timed out.
|
// unbond them, they have timed out.
|
||||||
toTimeout := []*Validator{}
|
toTimeout := []*Validator{}
|
||||||
s.BondedValidators.Iterate(func(index uint, val *Validator) bool {
|
s.BondedValidators.Iterate(func(index int, val *Validator) bool {
|
||||||
lastActivityHeight := MaxUint(val.BondHeight, val.LastCommitHeight)
|
lastActivityHeight := MaxInt(val.BondHeight, val.LastCommitHeight)
|
||||||
if lastActivityHeight+validatorTimeoutBlocks < block.Height {
|
if lastActivityHeight+validatorTimeoutBlocks < block.Height {
|
||||||
log.Info("Validator timeout", "validator", val, "height", block.Height)
|
log.Info("Validator timeout", "validator", val, "height", block.Height)
|
||||||
toTimeout = append(toTimeout, val)
|
toTimeout = append(toTimeout, val)
|
||||||
|
@ -215,7 +191,7 @@ func checkInputPubKey(acc *account.Account, in *types.TxInput) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateInputs(accounts map[string]*account.Account, signBytes []byte, ins []*types.TxInput) (total uint64, err error) {
|
func validateInputs(accounts map[string]*account.Account, signBytes []byte, ins []*types.TxInput) (total int64, err error) {
|
||||||
for _, in := range ins {
|
for _, in := range ins {
|
||||||
acc := accounts[string(in.Address)]
|
acc := accounts[string(in.Address)]
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
|
@ -243,8 +219,8 @@ func validateInput(acc *account.Account, signBytes []byte, in *types.TxInput) (e
|
||||||
// Check sequences
|
// Check sequences
|
||||||
if acc.Sequence+1 != in.Sequence {
|
if acc.Sequence+1 != in.Sequence {
|
||||||
return types.ErrTxInvalidSequence{
|
return types.ErrTxInvalidSequence{
|
||||||
Got: uint64(in.Sequence),
|
Got: in.Sequence,
|
||||||
Expected: uint64(acc.Sequence + 1),
|
Expected: acc.Sequence + 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Check amount
|
// Check amount
|
||||||
|
@ -254,7 +230,7 @@ func validateInput(acc *account.Account, signBytes []byte, in *types.TxInput) (e
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateOutputs(outs []*types.TxOutput) (total uint64, err error) {
|
func validateOutputs(outs []*types.TxOutput) (total int64, err error) {
|
||||||
for _, out := range outs {
|
for _, out := range outs {
|
||||||
// Check TxOutput basic
|
// Check TxOutput basic
|
||||||
if err := out.ValidateBasic(); err != nil {
|
if err := out.ValidateBasic(); err != nil {
|
||||||
|
@ -295,7 +271,7 @@ func adjustByOutputs(accounts map[string]*account.Account, outs []*types.TxOutpu
|
||||||
func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Fireable) error {
|
func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Fireable) error {
|
||||||
|
|
||||||
// TODO: do something with fees
|
// TODO: do something with fees
|
||||||
fees := uint64(0)
|
fees := int64(0)
|
||||||
_s := blockCache.State() // hack to access validators and block height
|
_s := blockCache.State() // hack to access validators and block height
|
||||||
|
|
||||||
// Exec tx
|
// Exec tx
|
||||||
|
@ -386,14 +362,14 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
||||||
if runCall {
|
if runCall {
|
||||||
|
|
||||||
var (
|
var (
|
||||||
gas uint64 = tx.GasLimit
|
gas int64 = tx.GasLimit
|
||||||
err error = nil
|
err error = nil
|
||||||
caller *vm.Account = toVMAccount(inAcc)
|
caller *vm.Account = toVMAccount(inAcc)
|
||||||
callee *vm.Account = nil
|
callee *vm.Account = nil
|
||||||
code []byte = nil
|
code []byte = nil
|
||||||
txCache = NewTxCache(blockCache)
|
txCache = NewTxCache(blockCache)
|
||||||
params = vm.Params{
|
params = vm.Params{
|
||||||
BlockHeight: uint64(_s.LastBlockHeight),
|
BlockHeight: int64(_s.LastBlockHeight),
|
||||||
BlockHash: LeftPadWord256(_s.LastBlockHash),
|
BlockHash: LeftPadWord256(_s.LastBlockHash),
|
||||||
BlockTime: _s.LastBlockTime.Unix(),
|
BlockTime: _s.LastBlockTime.Unix(),
|
||||||
GasLimit: 10000000,
|
GasLimit: 10000000,
|
||||||
|
@ -514,8 +490,8 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
||||||
|
|
||||||
// let's say cost of a name for one block is len(data) + 32
|
// let's say cost of a name for one block is len(data) + 32
|
||||||
costPerBlock := types.NameCostPerBlock * types.NameCostPerByte * tx.BaseEntryCost()
|
costPerBlock := types.NameCostPerBlock * types.NameCostPerByte * tx.BaseEntryCost()
|
||||||
expiresIn := value / uint64(costPerBlock)
|
expiresIn := int(value / costPerBlock)
|
||||||
lastBlockHeight := uint64(_s.LastBlockHeight)
|
lastBlockHeight := _s.LastBlockHeight
|
||||||
|
|
||||||
log.Debug("New NameTx", "value", value, "costPerBlock", costPerBlock, "expiresIn", expiresIn, "lastBlock", lastBlockHeight)
|
log.Debug("New NameTx", "value", value, "costPerBlock", costPerBlock, "expiresIn", expiresIn, "lastBlock", lastBlockHeight)
|
||||||
|
|
||||||
|
@ -554,9 +530,9 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
||||||
} else {
|
} else {
|
||||||
// since the size of the data may have changed
|
// since the size of the data may have changed
|
||||||
// we use the total amount of "credit"
|
// we use the total amount of "credit"
|
||||||
oldCredit := (entry.Expires - lastBlockHeight) * types.BaseEntryCost(entry.Name, entry.Data)
|
oldCredit := int64(entry.Expires-lastBlockHeight) * types.BaseEntryCost(entry.Name, entry.Data)
|
||||||
credit := oldCredit + value
|
credit := oldCredit + value
|
||||||
expiresIn = credit / costPerBlock
|
expiresIn = int(credit / costPerBlock)
|
||||||
if expiresIn < types.MinNameRegistrationPeriod {
|
if expiresIn < types.MinNameRegistrationPeriod {
|
||||||
return fmt.Errorf("Names must be registered for at least %d blocks", types.MinNameRegistrationPeriod)
|
return fmt.Errorf("Names must be registered for at least %d blocks", types.MinNameRegistrationPeriod)
|
||||||
}
|
}
|
||||||
|
@ -726,21 +702,14 @@ func ExecTx(blockCache *BlockCache, tx_ types.Tx, runCall bool, evc events.Firea
|
||||||
if tx.VoteA.Height != tx.VoteB.Height {
|
if tx.VoteA.Height != tx.VoteB.Height {
|
||||||
return errors.New("DupeoutTx heights don't match")
|
return errors.New("DupeoutTx heights don't match")
|
||||||
}
|
}
|
||||||
if tx.VoteA.Type == types.VoteTypeCommit && tx.VoteA.Round < tx.VoteB.Round {
|
if tx.VoteA.Round != tx.VoteB.Round {
|
||||||
// Check special case (not an error, validator must be slashed!)
|
return errors.New("DupeoutTx rounds don't match")
|
||||||
// Validators should not sign another vote after committing.
|
}
|
||||||
} else if tx.VoteB.Type == types.VoteTypeCommit && tx.VoteB.Round < tx.VoteA.Round {
|
if tx.VoteA.Type != tx.VoteB.Type {
|
||||||
// We need to check both orderings of the votes
|
return errors.New("DupeoutTx types don't match")
|
||||||
} else {
|
}
|
||||||
if tx.VoteA.Round != tx.VoteB.Round {
|
if bytes.Equal(tx.VoteA.BlockHash, tx.VoteB.BlockHash) {
|
||||||
return errors.New("DupeoutTx rounds don't match")
|
return errors.New("DupeoutTx blockhashes shouldn't match")
|
||||||
}
|
|
||||||
if tx.VoteA.Type != tx.VoteB.Type {
|
|
||||||
return errors.New("DupeoutTx types don't match")
|
|
||||||
}
|
|
||||||
if bytes.Equal(tx.VoteA.BlockHash, tx.VoteB.BlockHash) {
|
|
||||||
return errors.New("DupeoutTx blockhashes shouldn't match")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Good! (Bad validator!)
|
// Good! (Bad validator!)
|
||||||
|
|
|
@ -14,12 +14,12 @@ import (
|
||||||
|
|
||||||
type GenesisAccount struct {
|
type GenesisAccount struct {
|
||||||
Address []byte `json:"address"`
|
Address []byte `json:"address"`
|
||||||
Amount uint64 `json:"amount"`
|
Amount int64 `json:"amount"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type GenesisValidator struct {
|
type GenesisValidator struct {
|
||||||
PubKey account.PubKeyEd25519 `json:"pub_key"`
|
PubKey account.PubKeyEd25519 `json:"pub_key"`
|
||||||
Amount uint64 `json:"amount"`
|
Amount int64 `json:"amount"`
|
||||||
UnbondTo []GenesisAccount `json:"unbond_to"`
|
UnbondTo []GenesisAccount `json:"unbond_to"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package state
|
package state
|
||||||
|
|
||||||
// TODO: This logic is crude. Should be more transactional.
|
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
@ -23,17 +21,14 @@ const (
|
||||||
stepPropose = 1
|
stepPropose = 1
|
||||||
stepPrevote = 2
|
stepPrevote = 2
|
||||||
stepPrecommit = 3
|
stepPrecommit = 3
|
||||||
stepCommit = 4
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func voteToStep(vote *types.Vote) uint8 {
|
func voteToStep(vote *types.Vote) int8 {
|
||||||
switch vote.Type {
|
switch vote.Type {
|
||||||
case types.VoteTypePrevote:
|
case types.VoteTypePrevote:
|
||||||
return stepPrevote
|
return stepPrevote
|
||||||
case types.VoteTypePrecommit:
|
case types.VoteTypePrecommit:
|
||||||
return stepPrecommit
|
return stepPrecommit
|
||||||
case types.VoteTypeCommit:
|
|
||||||
return stepCommit
|
|
||||||
default:
|
default:
|
||||||
panic("Unknown vote type")
|
panic("Unknown vote type")
|
||||||
}
|
}
|
||||||
|
@ -43,9 +38,9 @@ type PrivValidator struct {
|
||||||
Address []byte `json:"address"`
|
Address []byte `json:"address"`
|
||||||
PubKey account.PubKeyEd25519 `json:"pub_key"`
|
PubKey account.PubKeyEd25519 `json:"pub_key"`
|
||||||
PrivKey account.PrivKeyEd25519 `json:"priv_key"`
|
PrivKey account.PrivKeyEd25519 `json:"priv_key"`
|
||||||
LastHeight uint `json:"last_height"`
|
LastHeight int `json:"last_height"`
|
||||||
LastRound uint `json:"last_round"`
|
LastRound int `json:"last_round"`
|
||||||
LastStep uint8 `json:"last_step"`
|
LastStep int8 `json:"last_step"`
|
||||||
|
|
||||||
// For persistence.
|
// For persistence.
|
||||||
// Overloaded for testing.
|
// Overloaded for testing.
|
||||||
|
@ -108,7 +103,6 @@ func (privVal *PrivValidator) save() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test
|
|
||||||
func (privVal *PrivValidator) SignVote(chainID string, vote *types.Vote) error {
|
func (privVal *PrivValidator) SignVote(chainID string, vote *types.Vote) error {
|
||||||
privVal.mtx.Lock()
|
privVal.mtx.Lock()
|
||||||
defer privVal.mtx.Unlock()
|
defer privVal.mtx.Unlock()
|
||||||
|
@ -119,10 +113,6 @@ func (privVal *PrivValidator) SignVote(chainID string, vote *types.Vote) error {
|
||||||
}
|
}
|
||||||
// More cases for when the height matches
|
// More cases for when the height matches
|
||||||
if privVal.LastHeight == vote.Height {
|
if privVal.LastHeight == vote.Height {
|
||||||
// If attempting any sign after commit, panic
|
|
||||||
if privVal.LastStep == stepCommit {
|
|
||||||
return errors.New("SignVote on matching height after a commit")
|
|
||||||
}
|
|
||||||
// If round regression, panic
|
// If round regression, panic
|
||||||
if privVal.LastRound > vote.Round {
|
if privVal.LastRound > vote.Round {
|
||||||
return errors.New("Round regression in SignVote")
|
return errors.New("Round regression in SignVote")
|
||||||
|
@ -176,8 +166,8 @@ func (privVal *PrivValidator) SignRebondTx(chainID string, rebondTx *types.Rebon
|
||||||
|
|
||||||
// Persist height/round/step
|
// Persist height/round/step
|
||||||
privVal.LastHeight = rebondTx.Height
|
privVal.LastHeight = rebondTx.Height
|
||||||
privVal.LastRound = math.MaxUint64 // We can't do anything else for this rebondTx.Height.
|
privVal.LastRound = math.MaxInt64 // We can't do anything else for this rebondTx.Height.
|
||||||
privVal.LastStep = math.MaxUint8
|
privVal.LastStep = math.MaxInt8
|
||||||
privVal.save()
|
privVal.save()
|
||||||
|
|
||||||
// Sign
|
// Sign
|
||||||
|
|
|
@ -16,10 +16,10 @@ import (
|
||||||
|
|
||||||
var (
|
var (
|
||||||
stateKey = []byte("stateKey")
|
stateKey = []byte("stateKey")
|
||||||
minBondAmount = uint64(1) // TODO adjust
|
minBondAmount = int64(1) // TODO adjust
|
||||||
defaultAccountsCacheCapacity = 1000 // TODO adjust
|
defaultAccountsCacheCapacity = 1000 // TODO adjust
|
||||||
unbondingPeriodBlocks = uint(60 * 24 * 365) // TODO probably better to make it time based.
|
unbondingPeriodBlocks = int(60 * 24 * 365) // TODO probably better to make it time based.
|
||||||
validatorTimeoutBlocks = uint(10) // TODO adjust
|
validatorTimeoutBlocks = int(10) // TODO adjust
|
||||||
)
|
)
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
@ -28,7 +28,7 @@ var (
|
||||||
type State struct {
|
type State struct {
|
||||||
DB dbm.DB
|
DB dbm.DB
|
||||||
ChainID string
|
ChainID string
|
||||||
LastBlockHeight uint
|
LastBlockHeight int
|
||||||
LastBlockHash []byte
|
LastBlockHash []byte
|
||||||
LastBlockParts types.PartSetHeader
|
LastBlockParts types.PartSetHeader
|
||||||
LastBlockTime time.Time
|
LastBlockTime time.Time
|
||||||
|
@ -50,7 +50,7 @@ func LoadState(db dbm.DB) *State {
|
||||||
} else {
|
} else {
|
||||||
r, n, err := bytes.NewReader(buf), new(int64), new(error)
|
r, n, err := bytes.NewReader(buf), new(int64), new(error)
|
||||||
s.ChainID = binary.ReadString(r, n, err)
|
s.ChainID = binary.ReadString(r, n, err)
|
||||||
s.LastBlockHeight = binary.ReadUvarint(r, n, err)
|
s.LastBlockHeight = binary.ReadVarint(r, n, err)
|
||||||
s.LastBlockHash = binary.ReadByteSlice(r, n, err)
|
s.LastBlockHash = binary.ReadByteSlice(r, n, err)
|
||||||
s.LastBlockParts = binary.ReadBinary(types.PartSetHeader{}, r, n, err).(types.PartSetHeader)
|
s.LastBlockParts = binary.ReadBinary(types.PartSetHeader{}, r, n, err).(types.PartSetHeader)
|
||||||
s.LastBlockTime = binary.ReadTime(r, n, err)
|
s.LastBlockTime = binary.ReadTime(r, n, err)
|
||||||
|
@ -80,7 +80,7 @@ func (s *State) Save() {
|
||||||
s.nameReg.Save()
|
s.nameReg.Save()
|
||||||
buf, n, err := new(bytes.Buffer), new(int64), new(error)
|
buf, n, err := new(bytes.Buffer), new(int64), new(error)
|
||||||
binary.WriteString(s.ChainID, buf, n, err)
|
binary.WriteString(s.ChainID, buf, n, err)
|
||||||
binary.WriteUvarint(s.LastBlockHeight, buf, n, err)
|
binary.WriteVarint(s.LastBlockHeight, buf, n, err)
|
||||||
binary.WriteByteSlice(s.LastBlockHash, buf, n, err)
|
binary.WriteByteSlice(s.LastBlockHash, buf, n, err)
|
||||||
binary.WriteBinary(s.LastBlockParts, buf, n, err)
|
binary.WriteBinary(s.LastBlockParts, buf, n, err)
|
||||||
binary.WriteTime(s.LastBlockTime, buf, n, err)
|
binary.WriteTime(s.LastBlockTime, buf, n, err)
|
||||||
|
@ -130,7 +130,7 @@ func (s *State) Hash() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mutates the block in place and updates it with new state hash.
|
// Mutates the block in place and updates it with new state hash.
|
||||||
func (s *State) SetBlockStateHash(block *types.Block) error {
|
func (s *State) ComputeBlockStateHash(block *types.Block) error {
|
||||||
sCopy := s.Copy()
|
sCopy := s.Copy()
|
||||||
// sCopy has no event cache in it, so this won't fire events
|
// sCopy has no event cache in it, so this won't fire events
|
||||||
err := execBlock(sCopy, block, types.PartSetHeader{})
|
err := execBlock(sCopy, block, types.PartSetHeader{})
|
||||||
|
|
|
@ -71,28 +71,29 @@ func TestCopyState(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeBlock(t *testing.T, state *State, commits []types.Commit, txs []types.Tx) *types.Block {
|
func makeBlock(t *testing.T, state *State, validation *types.Validation, txs []types.Tx) *types.Block {
|
||||||
|
if validation == nil {
|
||||||
|
validation = &types.Validation{}
|
||||||
|
}
|
||||||
block := &types.Block{
|
block := &types.Block{
|
||||||
Header: &types.Header{
|
Header: &types.Header{
|
||||||
ChainID: state.ChainID,
|
ChainID: state.ChainID,
|
||||||
Height: state.LastBlockHeight + 1,
|
Height: state.LastBlockHeight + 1,
|
||||||
Time: state.LastBlockTime.Add(time.Minute),
|
Time: state.LastBlockTime.Add(time.Minute),
|
||||||
Fees: 0,
|
Fees: 0,
|
||||||
NumTxs: uint(len(txs)),
|
NumTxs: len(txs),
|
||||||
LastBlockHash: state.LastBlockHash,
|
LastBlockHash: state.LastBlockHash,
|
||||||
LastBlockParts: state.LastBlockParts,
|
LastBlockParts: state.LastBlockParts,
|
||||||
StateHash: nil,
|
StateHash: nil,
|
||||||
},
|
},
|
||||||
Validation: &types.Validation{
|
LastValidation: validation,
|
||||||
Commits: commits,
|
|
||||||
},
|
|
||||||
Data: &types.Data{
|
Data: &types.Data{
|
||||||
Txs: txs,
|
Txs: txs,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill in block StateHash
|
// Fill in block StateHash
|
||||||
err := state.SetBlockStateHash(block)
|
err := state.ComputeBlockStateHash(block)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Error("Error appending initial block:", err)
|
t.Error("Error appending initial block:", err)
|
||||||
}
|
}
|
||||||
|
@ -178,7 +179,7 @@ func TestTxSequence(t *testing.T) {
|
||||||
// Test a variety of sequence numbers for the tx.
|
// Test a variety of sequence numbers for the tx.
|
||||||
// The tx should only pass when i == 1.
|
// The tx should only pass when i == 1.
|
||||||
for i := -1; i < 3; i++ {
|
for i := -1; i < 3; i++ {
|
||||||
sequence := acc0.Sequence + uint(i)
|
sequence := acc0.Sequence + i
|
||||||
tx := types.NewSendTx()
|
tx := types.NewSendTx()
|
||||||
tx.AddInputWithNonce(acc0PubKey, 1, sequence)
|
tx.AddInputWithNonce(acc0PubKey, 1, sequence)
|
||||||
tx.AddOutput(acc1.Address, 1)
|
tx.AddOutput(acc1.Address, 1)
|
||||||
|
@ -215,15 +216,15 @@ func TestNameTxs(t *testing.T) {
|
||||||
state, privAccounts, _ := RandGenesisState(3, true, 1000, 1, true, 1000)
|
state, privAccounts, _ := RandGenesisState(3, true, 1000, 1, true, 1000)
|
||||||
|
|
||||||
types.MinNameRegistrationPeriod = 5
|
types.MinNameRegistrationPeriod = 5
|
||||||
startingBlock := uint64(state.LastBlockHeight)
|
startingBlock := state.LastBlockHeight
|
||||||
|
|
||||||
// try some bad names. these should all fail
|
// try some bad names. these should all fail
|
||||||
names := []string{"", "\n", "123#$%", "\x00", string([]byte{20, 40, 60, 80}), "baffledbythespectacleinallofthisyouseeehesaidwithouteyes", "no spaces please"}
|
names := []string{"", "\n", "123#$%", "\x00", string([]byte{20, 40, 60, 80}), "baffledbythespectacleinallofthisyouseeehesaidwithouteyes", "no spaces please"}
|
||||||
data := "something about all this just doesn't feel right."
|
data := "something about all this just doesn't feel right."
|
||||||
fee := uint64(1000)
|
fee := int64(1000)
|
||||||
numDesiredBlocks := uint64(5)
|
numDesiredBlocks := 5
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
amt := fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
amt := fee + int64(numDesiredBlocks)*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
||||||
tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
||||||
tx.Sign(state.ChainID, privAccounts[0])
|
tx.Sign(state.ChainID, privAccounts[0])
|
||||||
|
|
||||||
|
@ -236,7 +237,7 @@ func TestNameTxs(t *testing.T) {
|
||||||
name := "hold_it_chum"
|
name := "hold_it_chum"
|
||||||
datas := []string{"cold&warm", "!@#$%^&*()", "<<<>>>>", "because why would you ever need a ~ or a & or even a % in a json file? make your case and we'll talk"}
|
datas := []string{"cold&warm", "!@#$%^&*()", "<<<>>>>", "because why would you ever need a ~ or a & or even a % in a json file? make your case and we'll talk"}
|
||||||
for _, data := range datas {
|
for _, data := range datas {
|
||||||
amt := fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
amt := fee + int64(numDesiredBlocks)*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
||||||
tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
||||||
tx.Sign(state.ChainID, privAccounts[0])
|
tx.Sign(state.ChainID, privAccounts[0])
|
||||||
|
|
||||||
|
@ -245,7 +246,7 @@ func TestNameTxs(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
validateEntry := func(t *testing.T, entry *types.NameRegEntry, name, data string, addr []byte, expires uint64) {
|
validateEntry := func(t *testing.T, entry *types.NameRegEntry, name, data string, addr []byte, expires int) {
|
||||||
|
|
||||||
if entry == nil {
|
if entry == nil {
|
||||||
t.Fatalf("Could not find name %s", name)
|
t.Fatalf("Could not find name %s", name)
|
||||||
|
@ -267,7 +268,7 @@ func TestNameTxs(t *testing.T) {
|
||||||
// try a good one, check data, owner, expiry
|
// try a good one, check data, owner, expiry
|
||||||
name = "looking_good/karaoke_bar"
|
name = "looking_good/karaoke_bar"
|
||||||
data = "on this side of neptune there are 1234567890 people: first is OMNIVORE. Or is it. Ok this is pretty restrictive. No exclamations :(. Faces tho :')"
|
data = "on this side of neptune there are 1234567890 people: first is OMNIVORE. Or is it. Ok this is pretty restrictive. No exclamations :(. Faces tho :')"
|
||||||
amt := fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
amt := fee + int64(numDesiredBlocks)*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
||||||
tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
tx, _ := types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
||||||
tx.Sign(state.ChainID, privAccounts[0])
|
tx.Sign(state.ChainID, privAccounts[0])
|
||||||
if err := execTxWithState(state, tx, true); err != nil {
|
if err := execTxWithState(state, tx, true); err != nil {
|
||||||
|
@ -303,7 +304,7 @@ func TestNameTxs(t *testing.T) {
|
||||||
validateEntry(t, entry, name, data, privAccounts[0].Address, startingBlock+numDesiredBlocks*3)
|
validateEntry(t, entry, name, data, privAccounts[0].Address, startingBlock+numDesiredBlocks*3)
|
||||||
|
|
||||||
// fail to update it as non-owner
|
// fail to update it as non-owner
|
||||||
state.LastBlockHeight = uint(entry.Expires - 1)
|
state.LastBlockHeight = entry.Expires - 1
|
||||||
tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
|
tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
|
||||||
tx.Sign(state.ChainID, privAccounts[1])
|
tx.Sign(state.ChainID, privAccounts[1])
|
||||||
if err := execTxWithState(state, tx, true); err == nil {
|
if err := execTxWithState(state, tx, true); err == nil {
|
||||||
|
@ -311,27 +312,27 @@ func TestNameTxs(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// once expires, non-owner succeeds
|
// once expires, non-owner succeeds
|
||||||
state.LastBlockHeight = uint(entry.Expires)
|
state.LastBlockHeight = entry.Expires
|
||||||
tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
|
tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
|
||||||
tx.Sign(state.ChainID, privAccounts[1])
|
tx.Sign(state.ChainID, privAccounts[1])
|
||||||
if err := execTxWithState(state, tx, true); err != nil {
|
if err := execTxWithState(state, tx, true); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
entry = state.GetNameRegEntry(name)
|
entry = state.GetNameRegEntry(name)
|
||||||
validateEntry(t, entry, name, data, privAccounts[1].Address, uint64(state.LastBlockHeight)+numDesiredBlocks)
|
validateEntry(t, entry, name, data, privAccounts[1].Address, state.LastBlockHeight+numDesiredBlocks)
|
||||||
|
|
||||||
// update it as new owner, with new data (longer), but keep the expiry!
|
// update it as new owner, with new data (longer), but keep the expiry!
|
||||||
data = "In the beginning there was no thing, not even the beginning. It hadn't been here, no there, nor for that matter anywhere, not especially because it had not to even exist, let alone to not. Nothing especially odd about that."
|
data = "In the beginning there was no thing, not even the beginning. It hadn't been here, no there, nor for that matter anywhere, not especially because it had not to even exist, let alone to not. Nothing especially odd about that."
|
||||||
oldCredit := amt - fee
|
oldCredit := amt - fee
|
||||||
numDesiredBlocks = 10
|
numDesiredBlocks = 10
|
||||||
amt = fee + (numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data) - oldCredit)
|
amt = fee + (int64(numDesiredBlocks)*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data) - oldCredit)
|
||||||
tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
|
tx, _ = types.NewNameTx(state, privAccounts[1].PubKey, name, data, amt, fee)
|
||||||
tx.Sign(state.ChainID, privAccounts[1])
|
tx.Sign(state.ChainID, privAccounts[1])
|
||||||
if err := execTxWithState(state, tx, true); err != nil {
|
if err := execTxWithState(state, tx, true); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
entry = state.GetNameRegEntry(name)
|
entry = state.GetNameRegEntry(name)
|
||||||
validateEntry(t, entry, name, data, privAccounts[1].Address, uint64(state.LastBlockHeight)+numDesiredBlocks)
|
validateEntry(t, entry, name, data, privAccounts[1].Address, state.LastBlockHeight+numDesiredBlocks)
|
||||||
|
|
||||||
// test removal
|
// test removal
|
||||||
amt = fee
|
amt = fee
|
||||||
|
@ -350,15 +351,15 @@ func TestNameTxs(t *testing.T) {
|
||||||
// test removal by key1 after expiry
|
// test removal by key1 after expiry
|
||||||
name = "looking_good/karaoke_bar"
|
name = "looking_good/karaoke_bar"
|
||||||
data = "some data"
|
data = "some data"
|
||||||
amt = fee + numDesiredBlocks*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
amt = fee + int64(numDesiredBlocks)*types.NameCostPerByte*types.NameCostPerBlock*types.BaseEntryCost(name, data)
|
||||||
tx, _ = types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
tx, _ = types.NewNameTx(state, privAccounts[0].PubKey, name, data, amt, fee)
|
||||||
tx.Sign(state.ChainID, privAccounts[0])
|
tx.Sign(state.ChainID, privAccounts[0])
|
||||||
if err := execTxWithState(state, tx, true); err != nil {
|
if err := execTxWithState(state, tx, true); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
entry = state.GetNameRegEntry(name)
|
entry = state.GetNameRegEntry(name)
|
||||||
validateEntry(t, entry, name, data, privAccounts[0].Address, uint64(state.LastBlockHeight)+numDesiredBlocks)
|
validateEntry(t, entry, name, data, privAccounts[0].Address, state.LastBlockHeight+numDesiredBlocks)
|
||||||
state.LastBlockHeight = uint(entry.Expires)
|
state.LastBlockHeight = entry.Expires
|
||||||
|
|
||||||
amt = fee
|
amt = fee
|
||||||
data = ""
|
data = ""
|
||||||
|
@ -473,7 +474,7 @@ attack the network, they'll generate the longest chain and outpace attackers.
|
||||||
network itself requires minimal structure. Messages are broadcast on a best effort
|
network itself requires minimal structure. Messages are broadcast on a best effort
|
||||||
basis, and nodes can leave and rejoin the network at will, accepting the longest
|
basis, and nodes can leave and rejoin the network at will, accepting the longest
|
||||||
proof-of-work chain as proof of what happened while they were gone `
|
proof-of-work chain as proof of what happened while they were gone `
|
||||||
entryAmount := uint64(10000)
|
entryAmount := int64(10000)
|
||||||
|
|
||||||
state := state.Copy()
|
state := state.Copy()
|
||||||
tx := &types.NameTx{
|
tx := &types.NameTx{
|
||||||
|
@ -620,21 +621,19 @@ func TestAddValidator(t *testing.T) {
|
||||||
|
|
||||||
// The validation for the next block should only require 1 signature
|
// The validation for the next block should only require 1 signature
|
||||||
// (the new validator wasn't active for block0)
|
// (the new validator wasn't active for block0)
|
||||||
commit0 := &types.Vote{
|
precommit0 := &types.Vote{
|
||||||
Height: 1,
|
Height: 1,
|
||||||
Round: 0,
|
Round: 0,
|
||||||
Type: types.VoteTypeCommit,
|
Type: types.VoteTypePrecommit,
|
||||||
BlockHash: block0.Hash(),
|
BlockHash: block0.Hash(),
|
||||||
BlockParts: block0Parts.Header(),
|
BlockParts: block0Parts.Header(),
|
||||||
}
|
}
|
||||||
privValidators[0].SignVote(s0.ChainID, commit0)
|
privValidators[0].SignVote(s0.ChainID, precommit0)
|
||||||
|
|
||||||
block1 := makeBlock(t, s0,
|
block1 := makeBlock(t, s0,
|
||||||
[]types.Commit{
|
&types.Validation{
|
||||||
types.Commit{
|
Precommits: []*types.Vote{
|
||||||
Address: privValidators[0].Address,
|
precommit0,
|
||||||
Round: 0,
|
|
||||||
Signature: commit0.Signature,
|
|
||||||
},
|
},
|
||||||
}, nil,
|
}, nil,
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,27 +22,27 @@ func Tempfile(prefix string) (*os.File, string) {
|
||||||
return file, file.Name()
|
return file, file.Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
func RandAccount(randBalance bool, minBalance uint64) (*account.Account, *account.PrivAccount) {
|
func RandAccount(randBalance bool, minBalance int64) (*account.Account, *account.PrivAccount) {
|
||||||
privAccount := account.GenPrivAccount()
|
privAccount := account.GenPrivAccount()
|
||||||
acc := &account.Account{
|
acc := &account.Account{
|
||||||
Address: privAccount.PubKey.Address(),
|
Address: privAccount.PubKey.Address(),
|
||||||
PubKey: privAccount.PubKey,
|
PubKey: privAccount.PubKey,
|
||||||
Sequence: RandUint(),
|
Sequence: RandInt(),
|
||||||
Balance: minBalance,
|
Balance: minBalance,
|
||||||
}
|
}
|
||||||
if randBalance {
|
if randBalance {
|
||||||
acc.Balance += uint64(RandUint32())
|
acc.Balance += int64(RandUint32())
|
||||||
}
|
}
|
||||||
return acc, privAccount
|
return acc, privAccount
|
||||||
}
|
}
|
||||||
|
|
||||||
func RandValidator(randBonded bool, minBonded uint64) (*ValidatorInfo, *Validator, *PrivValidator) {
|
func RandValidator(randBonded bool, minBonded int64) (*ValidatorInfo, *Validator, *PrivValidator) {
|
||||||
privVal := GenPrivValidator()
|
privVal := GenPrivValidator()
|
||||||
_, tempFilePath := Tempfile("priv_validator_")
|
_, tempFilePath := Tempfile("priv_validator_")
|
||||||
privVal.SetFile(tempFilePath)
|
privVal.SetFile(tempFilePath)
|
||||||
bonded := minBonded
|
bonded := minBonded
|
||||||
if randBonded {
|
if randBonded {
|
||||||
bonded += uint64(RandUint32())
|
bonded += int64(RandUint32())
|
||||||
}
|
}
|
||||||
valInfo := &ValidatorInfo{
|
valInfo := &ValidatorInfo{
|
||||||
Address: privVal.Address,
|
Address: privVal.Address,
|
||||||
|
@ -66,7 +66,7 @@ func RandValidator(randBonded bool, minBonded uint64) (*ValidatorInfo, *Validato
|
||||||
return valInfo, val, privVal
|
return valInfo, val, privVal
|
||||||
}
|
}
|
||||||
|
|
||||||
func RandGenesisState(numAccounts int, randBalance bool, minBalance uint64, numValidators int, randBonded bool, minBonded uint64) (*State, []*account.PrivAccount, []*PrivValidator) {
|
func RandGenesisState(numAccounts int, randBalance bool, minBalance int64, numValidators int, randBonded bool, minBonded int64) (*State, []*account.PrivAccount, []*PrivValidator) {
|
||||||
db := dbm.NewMemDB()
|
db := dbm.NewMemDB()
|
||||||
accounts := make([]GenesisAccount, numAccounts)
|
accounts := make([]GenesisAccount, numAccounts)
|
||||||
privAccounts := make([]*account.PrivAccount, numAccounts)
|
privAccounts := make([]*account.PrivAccount, numAccounts)
|
||||||
|
|
|
@ -68,7 +68,7 @@ func (cache *TxCache) CreateAccount(creator *vm.Account) *vm.Account {
|
||||||
nonce := creator.Nonce
|
nonce := creator.Nonce
|
||||||
creator.Nonce += 1
|
creator.Nonce += 1
|
||||||
|
|
||||||
addr := LeftPadWord256(NewContractAddress(creator.Address.Postfix(20), nonce))
|
addr := LeftPadWord256(NewContractAddress(creator.Address.Postfix(20), int(nonce)))
|
||||||
|
|
||||||
// Create account from address.
|
// Create account from address.
|
||||||
account, removed := vmUnpack(cache.accounts[addr])
|
account, removed := vmUnpack(cache.accounts[addr])
|
||||||
|
@ -144,10 +144,10 @@ func (cache *TxCache) AddLog(log *vm.Log) {
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
// Convenience function to return address of new contract
|
// Convenience function to return address of new contract
|
||||||
func NewContractAddress(caller []byte, nonce uint64) []byte {
|
func NewContractAddress(caller []byte, nonce int) []byte {
|
||||||
temp := make([]byte, 32+8)
|
temp := make([]byte, 32+8)
|
||||||
copy(temp, caller)
|
copy(temp, caller)
|
||||||
PutUint64BE(temp[32:], nonce)
|
PutInt64BE(temp[32:], int64(nonce))
|
||||||
return sha3.Sha3(temp)[:20]
|
return sha3.Sha3(temp)[:20]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ func toVMAccount(acc *ac.Account) *vm.Account {
|
||||||
Address: LeftPadWord256(acc.Address),
|
Address: LeftPadWord256(acc.Address),
|
||||||
Balance: acc.Balance,
|
Balance: acc.Balance,
|
||||||
Code: acc.Code, // This is crazy.
|
Code: acc.Code, // This is crazy.
|
||||||
Nonce: uint64(acc.Sequence),
|
Nonce: int64(acc.Sequence),
|
||||||
StorageRoot: LeftPadWord256(acc.StorageRoot),
|
StorageRoot: LeftPadWord256(acc.StorageRoot),
|
||||||
Other: acc.PubKey,
|
Other: acc.PubKey,
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,7 @@ func toStateAccount(acc *vm.Account) *ac.Account {
|
||||||
PubKey: pubKey,
|
PubKey: pubKey,
|
||||||
Balance: acc.Balance,
|
Balance: acc.Balance,
|
||||||
Code: acc.Code,
|
Code: acc.Code,
|
||||||
Sequence: uint(acc.Nonce),
|
Sequence: int(acc.Nonce),
|
||||||
StorageRoot: storageRoot,
|
StorageRoot: storageRoot,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,11 +15,11 @@ type ValidatorInfo struct {
|
||||||
Address []byte `json:"address"`
|
Address []byte `json:"address"`
|
||||||
PubKey account.PubKeyEd25519 `json:"pub_key"`
|
PubKey account.PubKeyEd25519 `json:"pub_key"`
|
||||||
UnbondTo []*types.TxOutput `json:"unbond_to"`
|
UnbondTo []*types.TxOutput `json:"unbond_to"`
|
||||||
FirstBondHeight uint `json:"first_bond_height"`
|
FirstBondHeight int `json:"first_bond_height"`
|
||||||
FirstBondAmount uint64 `json:"first_bond_amount"`
|
FirstBondAmount int64 `json:"first_bond_amount"`
|
||||||
DestroyedHeight uint `json:"destroyed_height"` // If destroyed
|
DestroyedHeight int `json:"destroyed_height"` // If destroyed
|
||||||
DestroyedAmount uint64 `json:"destroyed_amount"` // If destroyed
|
DestroyedAmount int64 `json:"destroyed_amount"` // If destroyed
|
||||||
ReleasedHeight uint `json:"released_height"` // If released
|
ReleasedHeight int `json:"released_height"` // If released
|
||||||
}
|
}
|
||||||
|
|
||||||
func (valInfo *ValidatorInfo) Copy() *ValidatorInfo {
|
func (valInfo *ValidatorInfo) Copy() *ValidatorInfo {
|
||||||
|
@ -48,10 +48,10 @@ var ValidatorInfoCodec = binary.Codec{
|
||||||
type Validator struct {
|
type Validator struct {
|
||||||
Address []byte `json:"address"`
|
Address []byte `json:"address"`
|
||||||
PubKey account.PubKeyEd25519 `json:"pub_key"`
|
PubKey account.PubKeyEd25519 `json:"pub_key"`
|
||||||
BondHeight uint `json:"bond_height"`
|
BondHeight int `json:"bond_height"`
|
||||||
UnbondHeight uint `json:"unbond_height"`
|
UnbondHeight int `json:"unbond_height"`
|
||||||
LastCommitHeight uint `json:"last_commit_height"`
|
LastCommitHeight int `json:"last_commit_height"`
|
||||||
VotingPower uint64 `json:"voting_power"`
|
VotingPower int64 `json:"voting_power"`
|
||||||
Accum int64 `json:"accum"`
|
Accum int64 `json:"accum"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@ package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -29,7 +28,7 @@ type ValidatorSet struct {
|
||||||
|
|
||||||
// cached (unexported)
|
// cached (unexported)
|
||||||
proposer *Validator
|
proposer *Validator
|
||||||
totalVotingPower uint64
|
totalVotingPower int64
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewValidatorSet(vals []*Validator) *ValidatorSet {
|
func NewValidatorSet(vals []*Validator) *ValidatorSet {
|
||||||
|
@ -44,7 +43,7 @@ func NewValidatorSet(vals []*Validator) *ValidatorSet {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: mind the overflow when times and votingPower shares too large.
|
// TODO: mind the overflow when times and votingPower shares too large.
|
||||||
func (valSet *ValidatorSet) IncrementAccum(times uint) {
|
func (valSet *ValidatorSet) IncrementAccum(times int) {
|
||||||
// Add VotingPower * times to each validator and order into heap.
|
// Add VotingPower * times to each validator and order into heap.
|
||||||
validatorsHeap := NewHeap()
|
validatorsHeap := NewHeap()
|
||||||
for _, val := range valSet.Validators {
|
for _, val := range valSet.Validators {
|
||||||
|
@ -53,7 +52,7 @@ func (valSet *ValidatorSet) IncrementAccum(times uint) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrement the validator with most accum, times times.
|
// Decrement the validator with most accum, times times.
|
||||||
for i := uint(0); i < times; i++ {
|
for i := 0; i < times; i++ {
|
||||||
mostest := validatorsHeap.Peek().(*Validator)
|
mostest := validatorsHeap.Peek().(*Validator)
|
||||||
if i == times-1 {
|
if i == times-1 {
|
||||||
valSet.proposer = mostest
|
valSet.proposer = mostest
|
||||||
|
@ -83,27 +82,27 @@ func (valSet *ValidatorSet) HasAddress(address []byte) bool {
|
||||||
return idx != len(valSet.Validators) && bytes.Compare(valSet.Validators[idx].Address, address) == 0
|
return idx != len(valSet.Validators) && bytes.Compare(valSet.Validators[idx].Address, address) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
func (valSet *ValidatorSet) GetByAddress(address []byte) (index uint, val *Validator) {
|
func (valSet *ValidatorSet) GetByAddress(address []byte) (index int, val *Validator) {
|
||||||
idx := sort.Search(len(valSet.Validators), func(i int) bool {
|
idx := sort.Search(len(valSet.Validators), func(i int) bool {
|
||||||
return bytes.Compare(address, valSet.Validators[i].Address) <= 0
|
return bytes.Compare(address, valSet.Validators[i].Address) <= 0
|
||||||
})
|
})
|
||||||
if idx != len(valSet.Validators) && bytes.Compare(valSet.Validators[idx].Address, address) == 0 {
|
if idx != len(valSet.Validators) && bytes.Compare(valSet.Validators[idx].Address, address) == 0 {
|
||||||
return uint(idx), valSet.Validators[idx].Copy()
|
return idx, valSet.Validators[idx].Copy()
|
||||||
} else {
|
} else {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (valSet *ValidatorSet) GetByIndex(index uint) (address []byte, val *Validator) {
|
func (valSet *ValidatorSet) GetByIndex(index int) (address []byte, val *Validator) {
|
||||||
val = valSet.Validators[index]
|
val = valSet.Validators[index]
|
||||||
return val.Address, val.Copy()
|
return val.Address, val.Copy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (valSet *ValidatorSet) Size() uint {
|
func (valSet *ValidatorSet) Size() int {
|
||||||
return uint(len(valSet.Validators))
|
return len(valSet.Validators)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (valSet *ValidatorSet) TotalVotingPower() uint64 {
|
func (valSet *ValidatorSet) TotalVotingPower() int64 {
|
||||||
if valSet.totalVotingPower == 0 {
|
if valSet.totalVotingPower == 0 {
|
||||||
for _, val := range valSet.Validators {
|
for _, val := range valSet.Validators {
|
||||||
valSet.totalVotingPower += val.VotingPower
|
valSet.totalVotingPower += val.VotingPower
|
||||||
|
@ -191,9 +190,9 @@ func (valSet *ValidatorSet) Remove(address []byte) (val *Validator, removed bool
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (valSet *ValidatorSet) Iterate(fn func(index uint, val *Validator) bool) {
|
func (valSet *ValidatorSet) Iterate(fn func(index int, val *Validator) bool) {
|
||||||
for i, val := range valSet.Validators {
|
for i, val := range valSet.Validators {
|
||||||
stop := fn(uint(i), val.Copy())
|
stop := fn(i, val.Copy())
|
||||||
if stop {
|
if stop {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -201,45 +200,52 @@ func (valSet *ValidatorSet) Iterate(fn func(index uint, val *Validator) bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify that +2/3 of the set had signed the given signBytes
|
// Verify that +2/3 of the set had signed the given signBytes
|
||||||
func (valSet *ValidatorSet) VerifyValidation(chainID string, hash []byte, parts types.PartSetHeader, height uint, v *types.Validation) error {
|
func (valSet *ValidatorSet) VerifyValidation(chainID string,
|
||||||
if valSet.Size() != uint(len(v.Commits)) {
|
hash []byte, parts types.PartSetHeader, height int, v *types.Validation) error {
|
||||||
return errors.New(Fmt("Invalid validation -- wrong set size: %v vs %v",
|
if valSet.Size() != len(v.Precommits) {
|
||||||
valSet.Size(), len(v.Commits)))
|
return fmt.Errorf("Invalid validation -- wrong set size: %v vs %v", valSet.Size(), len(v.Precommits))
|
||||||
|
}
|
||||||
|
if height != v.Height() {
|
||||||
|
return fmt.Errorf("Invalid validation -- wrong height: %v vs %v", height, v.Height())
|
||||||
}
|
}
|
||||||
|
|
||||||
talliedVotingPower := uint64(0)
|
talliedVotingPower := int64(0)
|
||||||
seenValidators := map[string]struct{}{}
|
round := v.Round()
|
||||||
|
|
||||||
for idx, commit := range v.Commits {
|
for idx, precommit := range v.Precommits {
|
||||||
// may be zero, in which case skip.
|
// may be nil if validator skipped.
|
||||||
if commit.Signature.IsZero() {
|
if precommit == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
_, val := valSet.GetByIndex(uint(idx))
|
if precommit.Height != height {
|
||||||
commitSignBytes := account.SignBytes(chainID, &types.Vote{
|
return fmt.Errorf("Invalid validation -- wrong height: %v vs %v", height, precommit.Height)
|
||||||
Height: height, Round: commit.Round, Type: types.VoteTypeCommit,
|
|
||||||
BlockHash: hash,
|
|
||||||
BlockParts: parts,
|
|
||||||
})
|
|
||||||
|
|
||||||
// Validate
|
|
||||||
if _, seen := seenValidators[string(val.Address)]; seen {
|
|
||||||
return fmt.Errorf("Duplicate validator for commit %v for Validation %v", commit, v)
|
|
||||||
}
|
}
|
||||||
|
if precommit.Round != round {
|
||||||
if !val.PubKey.VerifyBytes(commitSignBytes, commit.Signature) {
|
return fmt.Errorf("Invalid validation -- wrong round: %v vs %v", round, precommit.Round)
|
||||||
return fmt.Errorf("Invalid signature for commit %v for Validation %v", commit, v)
|
|
||||||
}
|
}
|
||||||
|
if precommit.Type != types.VoteTypePrecommit {
|
||||||
// Tally
|
return fmt.Errorf("Invalid validation -- not precommit @ index %v", idx)
|
||||||
seenValidators[string(val.Address)] = struct{}{}
|
}
|
||||||
|
_, val := valSet.GetByIndex(idx)
|
||||||
|
// Validate signature
|
||||||
|
precommitSignBytes := account.SignBytes(chainID, precommit)
|
||||||
|
if !val.PubKey.VerifyBytes(precommitSignBytes, precommit.Signature) {
|
||||||
|
return fmt.Errorf("Invalid validation -- invalid signature: %v", precommit)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(precommit.BlockHash, hash) {
|
||||||
|
continue // Not an error, but doesn't count
|
||||||
|
}
|
||||||
|
if !parts.Equals(precommit.BlockParts) {
|
||||||
|
continue // Not an error, but doesn't count
|
||||||
|
}
|
||||||
|
// Good precommit!
|
||||||
talliedVotingPower += val.VotingPower
|
talliedVotingPower += val.VotingPower
|
||||||
}
|
}
|
||||||
|
|
||||||
if talliedVotingPower > valSet.TotalVotingPower()*2/3 {
|
if talliedVotingPower > valSet.TotalVotingPower()*2/3 {
|
||||||
return nil
|
return nil
|
||||||
} else {
|
} else {
|
||||||
return fmt.Errorf("insufficient voting power %v, needed %v",
|
return fmt.Errorf("Invalid validation -- insufficient voting power: got %v, needed %v",
|
||||||
talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
|
talliedVotingPower, (valSet.TotalVotingPower()*2/3 + 1))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -250,7 +256,7 @@ func (valSet *ValidatorSet) String() string {
|
||||||
|
|
||||||
func (valSet *ValidatorSet) StringIndented(indent string) string {
|
func (valSet *ValidatorSet) StringIndented(indent string) string {
|
||||||
valStrings := []string{}
|
valStrings := []string{}
|
||||||
valSet.Iterate(func(index uint, val *Validator) bool {
|
valSet.Iterate(func(index int, val *Validator) bool {
|
||||||
valStrings = append(valStrings, val.String())
|
valStrings = append(valStrings, val.String())
|
||||||
return false
|
return false
|
||||||
})
|
})
|
||||||
|
@ -288,9 +294,9 @@ func (vs ValidatorsByAddress) Swap(i, j int) {
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
// Use with Heap for sorting validators by accum
|
// Use with Heap for sorting validators by accum
|
||||||
|
|
||||||
type accumComparable uint64
|
type accumComparable int64
|
||||||
|
|
||||||
// We want to find the validator with the greatest accum.
|
// We want to find the validator with the greatest accum.
|
||||||
func (ac accumComparable) Less(o interface{}) bool {
|
func (ac accumComparable) Less(o interface{}) bool {
|
||||||
return uint64(ac) < uint64(o.(accumComparable))
|
return int64(ac) < int64(o.(accumComparable))
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,9 +13,9 @@ func randValidator_() *Validator {
|
||||||
return &Validator{
|
return &Validator{
|
||||||
Address: RandBytes(20),
|
Address: RandBytes(20),
|
||||||
PubKey: account.PubKeyEd25519(RandBytes(64)),
|
PubKey: account.PubKeyEd25519(RandBytes(64)),
|
||||||
BondHeight: uint(RandUint32()),
|
BondHeight: RandInt(),
|
||||||
VotingPower: RandUint64(),
|
VotingPower: RandInt64(),
|
||||||
Accum: int64(RandUint64()),
|
Accum: RandInt64(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
147
types/block.go
147
types/block.go
|
@ -15,13 +15,13 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type Block struct {
|
type Block struct {
|
||||||
*Header `json:"header"`
|
*Header `json:"header"`
|
||||||
*Validation `json:"validation"`
|
*Data `json:"data"`
|
||||||
*Data `json:"data"`
|
LastValidation *Validation `json:"last_validation"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Basic validation that doesn't involve state data.
|
// Basic validation that doesn't involve state data.
|
||||||
func (b *Block) ValidateBasic(chainID string, lastBlockHeight uint, lastBlockHash []byte,
|
func (b *Block) ValidateBasic(chainID string, lastBlockHeight int, lastBlockHash []byte,
|
||||||
lastBlockParts PartSetHeader, lastBlockTime time.Time) error {
|
lastBlockParts PartSetHeader, lastBlockTime time.Time) error {
|
||||||
if b.ChainID != chainID {
|
if b.ChainID != chainID {
|
||||||
return errors.New("Wrong Block.Header.ChainID")
|
return errors.New("Wrong Block.Header.ChainID")
|
||||||
|
@ -29,7 +29,7 @@ func (b *Block) ValidateBasic(chainID string, lastBlockHeight uint, lastBlockHas
|
||||||
if b.Height != lastBlockHeight+1 {
|
if b.Height != lastBlockHeight+1 {
|
||||||
return errors.New("Wrong Block.Header.Height")
|
return errors.New("Wrong Block.Header.Height")
|
||||||
}
|
}
|
||||||
if b.NumTxs != uint(len(b.Data.Txs)) {
|
if b.NumTxs != len(b.Data.Txs) {
|
||||||
return errors.New("Wrong Block.Header.NumTxs")
|
return errors.New("Wrong Block.Header.NumTxs")
|
||||||
}
|
}
|
||||||
if !bytes.Equal(b.LastBlockHash, lastBlockHash) {
|
if !bytes.Equal(b.LastBlockHash, lastBlockHash) {
|
||||||
|
@ -46,7 +46,7 @@ func (b *Block) ValidateBasic(chainID string, lastBlockHeight uint, lastBlockHas
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
if b.Header.Height != 1 {
|
if b.Header.Height != 1 {
|
||||||
if err := b.Validation.ValidateBasic(); err != nil {
|
if err := b.LastValidation.ValidateBasic(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,12 +58,12 @@ func (b *Block) ValidateBasic(chainID string, lastBlockHeight uint, lastBlockHas
|
||||||
// If the block is incomplete (e.g. missing Header.StateHash)
|
// If the block is incomplete (e.g. missing Header.StateHash)
|
||||||
// then the hash is nil, to prevent the usage of that hash.
|
// then the hash is nil, to prevent the usage of that hash.
|
||||||
func (b *Block) Hash() []byte {
|
func (b *Block) Hash() []byte {
|
||||||
if b.Header == nil || b.Validation == nil || b.Data == nil {
|
if b.Header == nil || b.Data == nil || b.LastValidation == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
hashHeader := b.Header.Hash()
|
hashHeader := b.Header.Hash()
|
||||||
hashValidation := b.Validation.Hash()
|
|
||||||
hashData := b.Data.Hash()
|
hashData := b.Data.Hash()
|
||||||
|
hashLastValidation := b.LastValidation.Hash()
|
||||||
|
|
||||||
// If hashHeader is nil, required fields are missing.
|
// If hashHeader is nil, required fields are missing.
|
||||||
if len(hashHeader) == 0 {
|
if len(hashHeader) == 0 {
|
||||||
|
@ -71,7 +71,7 @@ func (b *Block) Hash() []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merkle hash from subhashes.
|
// Merkle hash from subhashes.
|
||||||
hashes := [][]byte{hashHeader, hashValidation, hashData}
|
hashes := [][]byte{hashHeader, hashData, hashLastValidation}
|
||||||
return merkle.SimpleHashFromHashes(hashes)
|
return merkle.SimpleHashFromHashes(hashes)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,8 +106,8 @@ func (b *Block) StringIndented(indent string) string {
|
||||||
%s %v
|
%s %v
|
||||||
%s}#%X`,
|
%s}#%X`,
|
||||||
indent, b.Header.StringIndented(indent+" "),
|
indent, b.Header.StringIndented(indent+" "),
|
||||||
indent, b.Validation.StringIndented(indent+" "),
|
|
||||||
indent, b.Data.StringIndented(indent+" "),
|
indent, b.Data.StringIndented(indent+" "),
|
||||||
|
indent, b.LastValidation.StringIndented(indent+" "),
|
||||||
indent, b.Hash())
|
indent, b.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,10 +123,10 @@ func (b *Block) StringShort() string {
|
||||||
|
|
||||||
type Header struct {
|
type Header struct {
|
||||||
ChainID string `json:"chain_id"`
|
ChainID string `json:"chain_id"`
|
||||||
Height uint `json:"height"`
|
Height int `json:"height"`
|
||||||
Time time.Time `json:"time"`
|
Time time.Time `json:"time"`
|
||||||
Fees uint64 `json:"fees"`
|
Fees int64 `json:"fees"`
|
||||||
NumTxs uint `json:"num_txs"`
|
NumTxs int `json:"num_txs"`
|
||||||
LastBlockHash []byte `json:"last_block_hash"`
|
LastBlockHash []byte `json:"last_block_hash"`
|
||||||
LastBlockParts PartSetHeader `json:"last_block_parts"`
|
LastBlockParts PartSetHeader `json:"last_block_parts"`
|
||||||
StateHash []byte `json:"state_hash"`
|
StateHash []byte `json:"state_hash"`
|
||||||
|
@ -174,54 +174,75 @@ func (h *Header) StringIndented(indent string) string {
|
||||||
indent, h.Hash())
|
indent, h.Hash())
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
type Commit struct {
|
|
||||||
Address []byte `json:"address"`
|
|
||||||
Round uint `json:"round"`
|
|
||||||
Signature account.SignatureEd25519 `json:"signature"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (commit Commit) IsZero() bool {
|
|
||||||
return commit.Round == 0 && commit.Signature.IsZero()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (commit Commit) String() string {
|
|
||||||
return fmt.Sprintf("Commit{A:%X R:%v %X}", commit.Address, commit.Round, Fingerprint(commit.Signature))
|
|
||||||
}
|
|
||||||
|
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
// NOTE: The Commits are in order of address to preserve the bonded ValidatorSet order.
|
// NOTE: Validation is empty for height 1, but never nil.
|
||||||
// Any peer with a block can gossip commits by index with a peer without recalculating the
|
|
||||||
// active ValidatorSet.
|
|
||||||
type Validation struct {
|
type Validation struct {
|
||||||
Commits []Commit `json:"commits"` // Commits (or nil) of all active validators in address order.
|
// NOTE: The Precommits are in order of address to preserve the bonded ValidatorSet order.
|
||||||
|
// Any peer with a block can gossip precommits by index with a peer without recalculating the
|
||||||
|
// active ValidatorSet.
|
||||||
|
Precommits []*Vote `json:"precommits"`
|
||||||
|
|
||||||
// Volatile
|
// Volatile
|
||||||
hash []byte
|
firstPrecommit *Vote
|
||||||
bitArray *BitArray
|
hash []byte
|
||||||
|
bitArray *BitArray
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validation) FirstPrecommit() *Vote {
|
||||||
|
if len(v.Precommits) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
if v.firstPrecommit != nil {
|
||||||
|
return v.firstPrecommit
|
||||||
|
}
|
||||||
|
for _, precommit := range v.Precommits {
|
||||||
|
if precommit != nil {
|
||||||
|
v.firstPrecommit = precommit
|
||||||
|
return precommit
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validation) Height() int {
|
||||||
|
if len(v.Precommits) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return v.FirstPrecommit().Height
|
||||||
|
}
|
||||||
|
|
||||||
|
func (v *Validation) Round() int {
|
||||||
|
if len(v.Precommits) == 0 {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
return v.FirstPrecommit().Round
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) ValidateBasic() error {
|
func (v *Validation) ValidateBasic() error {
|
||||||
if len(v.Commits) == 0 {
|
if len(v.Precommits) == 0 {
|
||||||
return errors.New("No commits in validation")
|
return errors.New("No precommits in validation")
|
||||||
}
|
}
|
||||||
lastAddress := []byte{}
|
height, round := v.Height(), v.Round()
|
||||||
for i := 0; i < len(v.Commits); i++ {
|
for _, precommit := range v.Precommits {
|
||||||
commit := v.Commits[i]
|
// It's OK for precommits to be missing.
|
||||||
if commit.IsZero() {
|
if precommit == nil {
|
||||||
if len(commit.Address) > 0 {
|
continue
|
||||||
return errors.New("Zero commits should not have an address")
|
}
|
||||||
}
|
// Ensure that all votes are precommits
|
||||||
} else {
|
if precommit.Type != VoteTypePrecommit {
|
||||||
if len(commit.Address) == 0 {
|
return fmt.Errorf("Invalid validation vote. Expected precommit, got %v",
|
||||||
return errors.New("Nonzero commits should have an address")
|
precommit.Type)
|
||||||
}
|
}
|
||||||
if len(lastAddress) > 0 && bytes.Compare(lastAddress, commit.Address) != -1 {
|
// Ensure that all heights are the same
|
||||||
return errors.New("Invalid commit order")
|
if precommit.Height != height {
|
||||||
}
|
return fmt.Errorf("Invalid validation precommit height. Expected %v, got %v",
|
||||||
lastAddress = commit.Address
|
height, precommit.Height)
|
||||||
|
}
|
||||||
|
// Ensure that all rounds are the same
|
||||||
|
if precommit.Round != round {
|
||||||
|
return fmt.Errorf("Invalid validation precommit round. Expected %v, got %v",
|
||||||
|
round, precommit.Round)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
@ -229,9 +250,9 @@ func (v *Validation) ValidateBasic() error {
|
||||||
|
|
||||||
func (v *Validation) Hash() []byte {
|
func (v *Validation) Hash() []byte {
|
||||||
if v.hash == nil {
|
if v.hash == nil {
|
||||||
bs := make([]interface{}, len(v.Commits))
|
bs := make([]interface{}, len(v.Precommits))
|
||||||
for i, commit := range v.Commits {
|
for i, precommit := range v.Precommits {
|
||||||
bs[i] = commit
|
bs[i] = precommit
|
||||||
}
|
}
|
||||||
v.hash = merkle.SimpleHashFromBinaries(bs)
|
v.hash = merkle.SimpleHashFromBinaries(bs)
|
||||||
}
|
}
|
||||||
|
@ -242,22 +263,22 @@ func (v *Validation) StringIndented(indent string) string {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return "nil-Validation"
|
return "nil-Validation"
|
||||||
}
|
}
|
||||||
commitStrings := make([]string, len(v.Commits))
|
precommitStrings := make([]string, len(v.Precommits))
|
||||||
for i, commit := range v.Commits {
|
for i, precommit := range v.Precommits {
|
||||||
commitStrings[i] = commit.String()
|
precommitStrings[i] = precommit.String()
|
||||||
}
|
}
|
||||||
return fmt.Sprintf(`Validation{
|
return fmt.Sprintf(`Validation{
|
||||||
%s %v
|
%s Precommits: %v
|
||||||
%s}#%X`,
|
%s}#%X`,
|
||||||
indent, strings.Join(commitStrings, "\n"+indent+" "),
|
indent, strings.Join(precommitStrings, "\n"+indent+" "),
|
||||||
indent, v.hash)
|
indent, v.hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (v *Validation) BitArray() *BitArray {
|
func (v *Validation) BitArray() *BitArray {
|
||||||
if v.bitArray == nil {
|
if v.bitArray == nil {
|
||||||
v.bitArray = NewBitArray(uint(len(v.Commits)))
|
v.bitArray = NewBitArray(len(v.Precommits))
|
||||||
for i, commit := range v.Commits {
|
for i, precommit := range v.Precommits {
|
||||||
v.bitArray.SetIndex(uint(i), !commit.IsZero())
|
v.bitArray.SetIndex(i, precommit != nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return v.bitArray
|
return v.bitArray
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
package types
|
package types
|
||||||
|
|
||||||
type BlockMeta struct {
|
type BlockMeta struct {
|
||||||
Hash []byte `json:"hash"` // The block hash
|
Hash []byte `json:"hash"` // The block hash
|
||||||
Header *Header `json:"header"` // The block's Header
|
Header *Header `json:"header"` // The block's Header
|
||||||
Parts PartSetHeader `json:"parts"` // The PartSetHeader, for transfer
|
PartsHeader PartSetHeader `json:"parts_header"` // The PartSetHeader, for transfer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewBlockMeta(block *Block, blockParts *PartSet) *BlockMeta {
|
func NewBlockMeta(block *Block, blockParts *PartSet) *BlockMeta {
|
||||||
return &BlockMeta{
|
return &BlockMeta{
|
||||||
Hash: block.Hash(),
|
Hash: block.Hash(),
|
||||||
Header: block.Header,
|
Header: block.Header,
|
||||||
Parts: blockParts.Header(),
|
PartsHeader: blockParts.Header(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -55,8 +55,8 @@ type CallData struct {
|
||||||
Caller []byte `json:"caller"`
|
Caller []byte `json:"caller"`
|
||||||
Callee []byte `json:"callee"`
|
Callee []byte `json:"callee"`
|
||||||
Data []byte `json:"data"`
|
Data []byte `json:"data"`
|
||||||
Value uint64 `json:"value"`
|
Value int64 `json:"value"`
|
||||||
Gas uint64 `json:"gas"`
|
Gas int64 `json:"gas"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventMsgCall struct {
|
type EventMsgCall struct {
|
||||||
|
|
|
@ -5,12 +5,12 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
MinNameRegistrationPeriod uint64 = 5
|
MinNameRegistrationPeriod int = 5
|
||||||
|
|
||||||
// cost for storing a name for a block is
|
// cost for storing a name for a block is
|
||||||
// CostPerBlock*CostPerByte*(len(data) + 32)
|
// CostPerBlock*CostPerByte*(len(data) + 32)
|
||||||
NameCostPerByte uint64 = 1
|
NameCostPerByte int64 = 1
|
||||||
NameCostPerBlock uint64 = 1
|
NameCostPerBlock int64 = 1
|
||||||
|
|
||||||
MaxNameLength = 32
|
MaxNameLength = 32
|
||||||
MaxDataLength = 1 << 16
|
MaxDataLength = 1 << 16
|
||||||
|
@ -31,15 +31,15 @@ func validateNameRegEntryData(data string) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// base cost is "effective" number of bytes
|
// base cost is "effective" number of bytes
|
||||||
func BaseEntryCost(name, data string) uint64 {
|
func BaseEntryCost(name, data string) int64 {
|
||||||
return uint64(len(data) + 32)
|
return int64(len(data) + 32)
|
||||||
}
|
}
|
||||||
|
|
||||||
type NameRegEntry struct {
|
type NameRegEntry struct {
|
||||||
Name string `json:"name"` // registered name for the entry
|
Name string `json:"name"` // registered name for the entry
|
||||||
Owner []byte `json:"owner"` // address that created the entry
|
Owner []byte `json:"owner"` // address that created the entry
|
||||||
Data string `json:"data"` // data to store under this name
|
Data string `json:"data"` // data to store under this name
|
||||||
Expires uint64 `json:"expires"` // block at which this entry expires
|
Expires int `json:"expires"` // block at which this entry expires
|
||||||
}
|
}
|
||||||
|
|
||||||
func (entry *NameRegEntry) Copy() *NameRegEntry {
|
func (entry *NameRegEntry) Copy() *NameRegEntry {
|
||||||
|
|
|
@ -61,7 +61,7 @@ func (part *Part) StringIndented(indent string) string {
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
type PartSetHeader struct {
|
type PartSetHeader struct {
|
||||||
Total uint `json:"total"`
|
Total int `json:"total"`
|
||||||
Hash []byte `json:"hash"`
|
Hash []byte `json:"hash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,13 +84,13 @@ func (psh PartSetHeader) WriteSignBytes(w io.Writer, n *int64, err *error) {
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
|
|
||||||
type PartSet struct {
|
type PartSet struct {
|
||||||
total uint
|
total int
|
||||||
hash []byte
|
hash []byte
|
||||||
|
|
||||||
mtx sync.Mutex
|
mtx sync.Mutex
|
||||||
parts []*Part
|
parts []*Part
|
||||||
partsBitArray *BitArray
|
partsBitArray *BitArray
|
||||||
count uint
|
count int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns an immutable, full PartSet from the data bytes.
|
// Returns an immutable, full PartSet from the data bytes.
|
||||||
|
@ -100,14 +100,14 @@ func NewPartSetFromData(data []byte) *PartSet {
|
||||||
total := (len(data) + partSize - 1) / partSize
|
total := (len(data) + partSize - 1) / partSize
|
||||||
parts := make([]*Part, total)
|
parts := make([]*Part, total)
|
||||||
parts_ := make([]merkle.Hashable, total)
|
parts_ := make([]merkle.Hashable, total)
|
||||||
partsBitArray := NewBitArray(uint(total))
|
partsBitArray := NewBitArray(total)
|
||||||
for i := 0; i < total; i++ {
|
for i := 0; i < total; i++ {
|
||||||
part := &Part{
|
part := &Part{
|
||||||
Bytes: data[i*partSize : MinInt(len(data), (i+1)*partSize)],
|
Bytes: data[i*partSize : MinInt(len(data), (i+1)*partSize)],
|
||||||
}
|
}
|
||||||
parts[i] = part
|
parts[i] = part
|
||||||
parts_[i] = part
|
parts_[i] = part
|
||||||
partsBitArray.SetIndex(uint(i), true)
|
partsBitArray.SetIndex(i, true)
|
||||||
}
|
}
|
||||||
// Compute merkle proofs
|
// Compute merkle proofs
|
||||||
proofs := merkle.SimpleProofsFromHashables(parts_)
|
proofs := merkle.SimpleProofsFromHashables(parts_)
|
||||||
|
@ -115,11 +115,11 @@ func NewPartSetFromData(data []byte) *PartSet {
|
||||||
parts[i].Proof = *proofs[i]
|
parts[i].Proof = *proofs[i]
|
||||||
}
|
}
|
||||||
return &PartSet{
|
return &PartSet{
|
||||||
total: uint(total),
|
total: total,
|
||||||
hash: proofs[0].RootHash,
|
hash: proofs[0].RootHash,
|
||||||
parts: parts,
|
parts: parts,
|
||||||
partsBitArray: partsBitArray,
|
partsBitArray: partsBitArray,
|
||||||
count: uint(total),
|
count: total,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,7 +129,7 @@ func NewPartSetFromHeader(header PartSetHeader) *PartSet {
|
||||||
total: header.Total,
|
total: header.Total,
|
||||||
hash: header.Hash,
|
hash: header.Hash,
|
||||||
parts: make([]*Part, header.Total),
|
parts: make([]*Part, header.Total),
|
||||||
partsBitArray: NewBitArray(uint(header.Total)),
|
partsBitArray: NewBitArray(header.Total),
|
||||||
count: 0,
|
count: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -173,14 +173,14 @@ func (ps *PartSet) HashesTo(hash []byte) bool {
|
||||||
return bytes.Equal(ps.hash, hash)
|
return bytes.Equal(ps.hash, hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PartSet) Count() uint {
|
func (ps *PartSet) Count() int {
|
||||||
if ps == nil {
|
if ps == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return ps.count
|
return ps.count
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PartSet) Total() uint {
|
func (ps *PartSet) Total() int {
|
||||||
if ps == nil {
|
if ps == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@ -208,12 +208,12 @@ func (ps *PartSet) AddPart(part *Part) (bool, error) {
|
||||||
|
|
||||||
// Add part
|
// Add part
|
||||||
ps.parts[part.Proof.Index] = part
|
ps.parts[part.Proof.Index] = part
|
||||||
ps.partsBitArray.SetIndex(uint(part.Proof.Index), true)
|
ps.partsBitArray.SetIndex(part.Proof.Index, true)
|
||||||
ps.count++
|
ps.count++
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PartSet) GetPart(index uint) *Part {
|
func (ps *PartSet) GetPart(index int) *Part {
|
||||||
ps.mtx.Lock()
|
ps.mtx.Lock()
|
||||||
defer ps.mtx.Unlock()
|
defer ps.mtx.Unlock()
|
||||||
return ps.parts[index]
|
return ps.parts[index]
|
||||||
|
|
|
@ -27,7 +27,7 @@ func TestBasicPartSet(t *testing.T) {
|
||||||
// Test adding parts to a new partSet.
|
// Test adding parts to a new partSet.
|
||||||
partSet2 := NewPartSetFromHeader(partSet.Header())
|
partSet2 := NewPartSetFromHeader(partSet.Header())
|
||||||
|
|
||||||
for i := uint(0); i < partSet.Total(); i++ {
|
for i := 0; i < partSet.Total(); i++ {
|
||||||
part := partSet.GetPart(i)
|
part := partSet.GetPart(i)
|
||||||
//t.Logf("\n%v", part)
|
//t.Logf("\n%v", part)
|
||||||
added, err := partSet2.AddPart(part)
|
added, err := partSet2.AddPart(part)
|
||||||
|
|
22
types/tx.go
22
types/tx.go
|
@ -24,8 +24,8 @@ var (
|
||||||
)
|
)
|
||||||
|
|
||||||
type ErrTxInvalidSequence struct {
|
type ErrTxInvalidSequence struct {
|
||||||
Got uint64
|
Got int
|
||||||
Expected uint64
|
Expected int
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e ErrTxInvalidSequence) Error() string {
|
func (e ErrTxInvalidSequence) Error() string {
|
||||||
|
@ -79,8 +79,8 @@ var _ = binary.RegisterInterface(
|
||||||
|
|
||||||
type TxInput struct {
|
type TxInput struct {
|
||||||
Address []byte `json:"address"` // Hash of the PubKey
|
Address []byte `json:"address"` // Hash of the PubKey
|
||||||
Amount uint64 `json:"amount"` // Must not exceed account balance
|
Amount int64 `json:"amount"` // Must not exceed account balance
|
||||||
Sequence uint `json:"sequence"` // Must be 1 greater than the last committed TxInput
|
Sequence int `json:"sequence"` // Must be 1 greater than the last committed TxInput
|
||||||
Signature account.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx
|
Signature account.Signature `json:"signature"` // Depends on the PubKey type and the whole Tx
|
||||||
PubKey account.PubKey `json:"pub_key"` // Must not be nil, may be nil
|
PubKey account.PubKey `json:"pub_key"` // Must not be nil, may be nil
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ func (txIn *TxInput) String() string {
|
||||||
|
|
||||||
type TxOutput struct {
|
type TxOutput struct {
|
||||||
Address []byte `json:"address"` // Hash of the PubKey
|
Address []byte `json:"address"` // Hash of the PubKey
|
||||||
Amount uint64 `json:"amount"` // The sum of all outputs must not exceed the inputs.
|
Amount int64 `json:"amount"` // The sum of all outputs must not exceed the inputs.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (txOut *TxOutput) ValidateBasic() error {
|
func (txOut *TxOutput) ValidateBasic() error {
|
||||||
|
@ -163,8 +163,8 @@ func (tx *SendTx) String() string {
|
||||||
type CallTx struct {
|
type CallTx struct {
|
||||||
Input *TxInput `json:"input"`
|
Input *TxInput `json:"input"`
|
||||||
Address []byte `json:"address"`
|
Address []byte `json:"address"`
|
||||||
GasLimit uint64 `json:"gas_limit"`
|
GasLimit int64 `json:"gas_limit"`
|
||||||
Fee uint64 `json:"fee"`
|
Fee int64 `json:"fee"`
|
||||||
Data []byte `json:"data"`
|
Data []byte `json:"data"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,7 +186,7 @@ type NameTx struct {
|
||||||
Input *TxInput `json:"input"`
|
Input *TxInput `json:"input"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Data string `json:"data"`
|
Data string `json:"data"`
|
||||||
Fee uint64 `json:"fee"`
|
Fee int64 `json:"fee"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *NameTx) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) {
|
func (tx *NameTx) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) {
|
||||||
|
@ -220,7 +220,7 @@ func (tx *NameTx) ValidateStrings() error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *NameTx) BaseEntryCost() uint64 {
|
func (tx *NameTx) BaseEntryCost() int64 {
|
||||||
return BaseEntryCost(tx.Name, tx.Data)
|
return BaseEntryCost(tx.Name, tx.Data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ func (tx *BondTx) String() string {
|
||||||
|
|
||||||
type UnbondTx struct {
|
type UnbondTx struct {
|
||||||
Address []byte `json:"address"`
|
Address []byte `json:"address"`
|
||||||
Height uint `json:"height"`
|
Height int `json:"height"`
|
||||||
Signature account.SignatureEd25519 `json:"signature"`
|
Signature account.SignatureEd25519 `json:"signature"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -283,7 +283,7 @@ func (tx *UnbondTx) String() string {
|
||||||
|
|
||||||
type RebondTx struct {
|
type RebondTx struct {
|
||||||
Address []byte `json:"address"`
|
Address []byte `json:"address"`
|
||||||
Height uint `json:"height"`
|
Height int `json:"height"`
|
||||||
Signature account.SignatureEd25519 `json:"signature"`
|
Signature account.SignatureEd25519 `json:"signature"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ func NewSendTx() *SendTx {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *SendTx) AddInput(st AccountGetter, pubkey account.PubKey, amt uint64) error {
|
func (tx *SendTx) AddInput(st AccountGetter, pubkey account.PubKey, amt int64) error {
|
||||||
addr := pubkey.Address()
|
addr := pubkey.Address()
|
||||||
acc := st.GetAccount(addr)
|
acc := st.GetAccount(addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
|
@ -28,7 +28,7 @@ func (tx *SendTx) AddInput(st AccountGetter, pubkey account.PubKey, amt uint64)
|
||||||
return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1)
|
return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *SendTx) AddInputWithNonce(pubkey account.PubKey, amt uint64, nonce uint) error {
|
func (tx *SendTx) AddInputWithNonce(pubkey account.PubKey, amt int64, nonce int) error {
|
||||||
addr := pubkey.Address()
|
addr := pubkey.Address()
|
||||||
tx.Inputs = append(tx.Inputs, &TxInput{
|
tx.Inputs = append(tx.Inputs, &TxInput{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
|
@ -40,7 +40,7 @@ func (tx *SendTx) AddInputWithNonce(pubkey account.PubKey, amt uint64, nonce uin
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *SendTx) AddOutput(addr []byte, amt uint64) error {
|
func (tx *SendTx) AddOutput(addr []byte, amt int64) error {
|
||||||
tx.Outputs = append(tx.Outputs, &TxOutput{
|
tx.Outputs = append(tx.Outputs, &TxOutput{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
Amount: amt,
|
Amount: amt,
|
||||||
|
@ -60,7 +60,7 @@ func (tx *SendTx) SignInput(chainID string, i int, privAccount *account.PrivAcco
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// CallTx interface for creating tx
|
// CallTx interface for creating tx
|
||||||
|
|
||||||
func NewCallTx(st AccountGetter, from account.PubKey, to, data []byte, amt, gasLimit, fee uint64) (*CallTx, error) {
|
func NewCallTx(st AccountGetter, from account.PubKey, to, data []byte, amt, gasLimit, fee int64) (*CallTx, error) {
|
||||||
addr := from.Address()
|
addr := from.Address()
|
||||||
acc := st.GetAccount(addr)
|
acc := st.GetAccount(addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
|
@ -71,7 +71,7 @@ func NewCallTx(st AccountGetter, from account.PubKey, to, data []byte, amt, gasL
|
||||||
return NewCallTxWithNonce(from, to, data, amt, gasLimit, fee, nonce), nil
|
return NewCallTxWithNonce(from, to, data, amt, gasLimit, fee, nonce), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCallTxWithNonce(from account.PubKey, to, data []byte, amt, gasLimit, fee uint64, nonce uint) *CallTx {
|
func NewCallTxWithNonce(from account.PubKey, to, data []byte, amt, gasLimit, fee int64, nonce int) *CallTx {
|
||||||
addr := from.Address()
|
addr := from.Address()
|
||||||
input := &TxInput{
|
input := &TxInput{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
|
@ -98,7 +98,7 @@ func (tx *CallTx) Sign(chainID string, privAccount *account.PrivAccount) {
|
||||||
//----------------------------------------------------------------------------
|
//----------------------------------------------------------------------------
|
||||||
// NameTx interface for creating tx
|
// NameTx interface for creating tx
|
||||||
|
|
||||||
func NewNameTx(st AccountGetter, from account.PubKey, name, data string, amt, fee uint64) (*NameTx, error) {
|
func NewNameTx(st AccountGetter, from account.PubKey, name, data string, amt, fee int64) (*NameTx, error) {
|
||||||
addr := from.Address()
|
addr := from.Address()
|
||||||
acc := st.GetAccount(addr)
|
acc := st.GetAccount(addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
|
@ -109,7 +109,7 @@ func NewNameTx(st AccountGetter, from account.PubKey, name, data string, amt, fe
|
||||||
return NewNameTxWithNonce(from, name, data, amt, fee, nonce), nil
|
return NewNameTxWithNonce(from, name, data, amt, fee, nonce), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewNameTxWithNonce(from account.PubKey, name, data string, amt, fee uint64, nonce uint) *NameTx {
|
func NewNameTxWithNonce(from account.PubKey, name, data string, amt, fee int64, nonce int) *NameTx {
|
||||||
addr := from.Address()
|
addr := from.Address()
|
||||||
input := &TxInput{
|
input := &TxInput{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
|
@ -147,7 +147,7 @@ func NewBondTx(pubkey account.PubKey) (*BondTx, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *BondTx) AddInput(st AccountGetter, pubkey account.PubKey, amt uint64) error {
|
func (tx *BondTx) AddInput(st AccountGetter, pubkey account.PubKey, amt int64) error {
|
||||||
addr := pubkey.Address()
|
addr := pubkey.Address()
|
||||||
acc := st.GetAccount(addr)
|
acc := st.GetAccount(addr)
|
||||||
if acc == nil {
|
if acc == nil {
|
||||||
|
@ -156,7 +156,7 @@ func (tx *BondTx) AddInput(st AccountGetter, pubkey account.PubKey, amt uint64)
|
||||||
return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1)
|
return tx.AddInputWithNonce(pubkey, amt, acc.Sequence+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *BondTx) AddInputWithNonce(pubkey account.PubKey, amt uint64, nonce uint) error {
|
func (tx *BondTx) AddInputWithNonce(pubkey account.PubKey, amt int64, nonce int) error {
|
||||||
addr := pubkey.Address()
|
addr := pubkey.Address()
|
||||||
tx.Inputs = append(tx.Inputs, &TxInput{
|
tx.Inputs = append(tx.Inputs, &TxInput{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
|
@ -168,7 +168,7 @@ func (tx *BondTx) AddInputWithNonce(pubkey account.PubKey, amt uint64, nonce uin
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tx *BondTx) AddOutput(addr []byte, amt uint64) error {
|
func (tx *BondTx) AddOutput(addr []byte, amt int64) error {
|
||||||
tx.UnbondTo = append(tx.UnbondTo, &TxOutput{
|
tx.UnbondTo = append(tx.UnbondTo, &TxOutput{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
Amount: amt,
|
Amount: amt,
|
||||||
|
@ -198,7 +198,7 @@ func (tx *BondTx) SignInput(chainID string, i int, privAccount *account.PrivAcco
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// UnbondTx interface for creating tx
|
// UnbondTx interface for creating tx
|
||||||
|
|
||||||
func NewUnbondTx(addr []byte, height uint) *UnbondTx {
|
func NewUnbondTx(addr []byte, height int) *UnbondTx {
|
||||||
return &UnbondTx{
|
return &UnbondTx{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
Height: height,
|
Height: height,
|
||||||
|
@ -212,7 +212,7 @@ func (tx *UnbondTx) Sign(chainID string, privAccount *account.PrivAccount) {
|
||||||
//----------------------------------------------------------------------
|
//----------------------------------------------------------------------
|
||||||
// RebondTx interface for creating tx
|
// RebondTx interface for creating tx
|
||||||
|
|
||||||
func NewRebondTx(addr []byte, height uint) *RebondTx {
|
func NewRebondTx(addr []byte, height int) *RebondTx {
|
||||||
return &RebondTx{
|
return &RebondTx{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
Height: height,
|
Height: height,
|
||||||
|
|
|
@ -27,11 +27,9 @@ func (err *ErrVoteConflictingSignature) Error() string {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Represents a prevote, precommit, or commit vote from validators for consensus.
|
// Represents a prevote, precommit, or commit vote from validators for consensus.
|
||||||
// Commit votes get aggregated into the next block's Validaiton.
|
|
||||||
// See the whitepaper for details.
|
|
||||||
type Vote struct {
|
type Vote struct {
|
||||||
Height uint `json:"height"`
|
Height int `json:"height"`
|
||||||
Round uint `json:"round"`
|
Round int `json:"round"`
|
||||||
Type byte `json:"type"`
|
Type byte `json:"type"`
|
||||||
BlockHash []byte `json:"block_hash"` // empty if vote is nil.
|
BlockHash []byte `json:"block_hash"` // empty if vote is nil.
|
||||||
BlockParts PartSetHeader `json:"block_parts"` // zero if vote is nil.
|
BlockParts PartSetHeader `json:"block_parts"` // zero if vote is nil.
|
||||||
|
@ -42,7 +40,6 @@ type Vote struct {
|
||||||
const (
|
const (
|
||||||
VoteTypePrevote = byte(0x01)
|
VoteTypePrevote = byte(0x01)
|
||||||
VoteTypePrecommit = byte(0x02)
|
VoteTypePrecommit = byte(0x02)
|
||||||
VoteTypeCommit = byte(0x03)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (vote *Vote) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) {
|
func (vote *Vote) WriteSignBytes(chainID string, w io.Writer, n *int64, err *error) {
|
||||||
|
@ -57,14 +54,15 @@ func (vote *Vote) Copy() *Vote {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (vote *Vote) String() string {
|
func (vote *Vote) String() string {
|
||||||
|
if vote == nil {
|
||||||
|
return "nil-Vote"
|
||||||
|
}
|
||||||
var typeString string
|
var typeString string
|
||||||
switch vote.Type {
|
switch vote.Type {
|
||||||
case VoteTypePrevote:
|
case VoteTypePrevote:
|
||||||
typeString = "Prevote"
|
typeString = "Prevote"
|
||||||
case VoteTypePrecommit:
|
case VoteTypePrecommit:
|
||||||
typeString = "Precommit"
|
typeString = "Precommit"
|
||||||
case VoteTypeCommit:
|
|
||||||
typeString = "Commit"
|
|
||||||
default:
|
default:
|
||||||
panic("Unknown vote type")
|
panic("Unknown vote type")
|
||||||
}
|
}
|
||||||
|
|
22
vm/gas.go
22
vm/gas.go
|
@ -1,17 +1,17 @@
|
||||||
package vm
|
package vm
|
||||||
|
|
||||||
const (
|
const (
|
||||||
GasSha3 uint64 = 1
|
GasSha3 int64 = 1
|
||||||
GasGetAccount uint64 = 1
|
GasGetAccount int64 = 1
|
||||||
GasStorageUpdate uint64 = 1
|
GasStorageUpdate int64 = 1
|
||||||
|
|
||||||
GasStackOp uint64 = 1
|
GasStackOp int64 = 1
|
||||||
|
|
||||||
GasEcRecover uint64 = 1
|
GasEcRecover int64 = 1
|
||||||
GasSha256Word uint64 = 1
|
GasSha256Word int64 = 1
|
||||||
GasSha256Base uint64 = 1
|
GasSha256Base int64 = 1
|
||||||
GasRipemd160Word uint64 = 1
|
GasRipemd160Word int64 = 1
|
||||||
GasRipemd160Base uint64 = 1
|
GasRipemd160Base int64 = 1
|
||||||
GasIdentityWord uint64 = 1
|
GasIdentityWord int64 = 1
|
||||||
GasIdentityBase uint64 = 1
|
GasIdentityBase int64 = 1
|
||||||
)
|
)
|
||||||
|
|
24
vm/native.go
24
vm/native.go
|
@ -11,17 +11,17 @@ import (
|
||||||
var nativeContracts = make(map[Word256]NativeContract)
|
var nativeContracts = make(map[Word256]NativeContract)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
nativeContracts[Uint64ToWord256(1)] = ecrecoverFunc
|
nativeContracts[Int64ToWord256(1)] = ecrecoverFunc
|
||||||
nativeContracts[Uint64ToWord256(2)] = sha256Func
|
nativeContracts[Int64ToWord256(2)] = sha256Func
|
||||||
nativeContracts[Uint64ToWord256(3)] = ripemd160Func
|
nativeContracts[Int64ToWord256(3)] = ripemd160Func
|
||||||
nativeContracts[Uint64ToWord256(4)] = identityFunc
|
nativeContracts[Int64ToWord256(4)] = identityFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
type NativeContract func(input []byte, gas *uint64) (output []byte, err error)
|
type NativeContract func(input []byte, gas *int64) (output []byte, err error)
|
||||||
|
|
||||||
func ecrecoverFunc(input []byte, gas *uint64) (output []byte, err error) {
|
func ecrecoverFunc(input []byte, gas *int64) (output []byte, err error) {
|
||||||
// Deduct gas
|
// Deduct gas
|
||||||
gasRequired := GasEcRecover
|
gasRequired := GasEcRecover
|
||||||
if *gas < gasRequired {
|
if *gas < gasRequired {
|
||||||
|
@ -42,9 +42,9 @@ func ecrecoverFunc(input []byte, gas *uint64) (output []byte, err error) {
|
||||||
return LeftPadBytes(hashed, 32), nil
|
return LeftPadBytes(hashed, 32), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sha256Func(input []byte, gas *uint64) (output []byte, err error) {
|
func sha256Func(input []byte, gas *int64) (output []byte, err error) {
|
||||||
// Deduct gas
|
// Deduct gas
|
||||||
gasRequired := uint64((len(input)+31)/32)*GasSha256Word + GasSha256Base
|
gasRequired := int64((len(input)+31)/32)*GasSha256Word + GasSha256Base
|
||||||
if *gas < gasRequired {
|
if *gas < gasRequired {
|
||||||
return nil, ErrInsufficientGas
|
return nil, ErrInsufficientGas
|
||||||
} else {
|
} else {
|
||||||
|
@ -59,9 +59,9 @@ func sha256Func(input []byte, gas *uint64) (output []byte, err error) {
|
||||||
return hasher.Sum(nil), nil
|
return hasher.Sum(nil), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ripemd160Func(input []byte, gas *uint64) (output []byte, err error) {
|
func ripemd160Func(input []byte, gas *int64) (output []byte, err error) {
|
||||||
// Deduct gas
|
// Deduct gas
|
||||||
gasRequired := uint64((len(input)+31)/32)*GasRipemd160Word + GasRipemd160Base
|
gasRequired := int64((len(input)+31)/32)*GasRipemd160Word + GasRipemd160Base
|
||||||
if *gas < gasRequired {
|
if *gas < gasRequired {
|
||||||
return nil, ErrInsufficientGas
|
return nil, ErrInsufficientGas
|
||||||
} else {
|
} else {
|
||||||
|
@ -76,9 +76,9 @@ func ripemd160Func(input []byte, gas *uint64) (output []byte, err error) {
|
||||||
return LeftPadBytes(hasher.Sum(nil), 32), nil
|
return LeftPadBytes(hasher.Sum(nil), 32), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func identityFunc(input []byte, gas *uint64) (output []byte, err error) {
|
func identityFunc(input []byte, gas *int64) (output []byte, err error) {
|
||||||
// Deduct gas
|
// Deduct gas
|
||||||
gasRequired := uint64((len(input)+31)/32)*GasIdentityWord + GasIdentityBase
|
gasRequired := int64((len(input)+31)/32)*GasIdentityWord + GasIdentityBase
|
||||||
if *gas < gasRequired {
|
if *gas < gasRequired {
|
||||||
return nil, ErrInsufficientGas
|
return nil, ErrInsufficientGas
|
||||||
} else {
|
} else {
|
||||||
|
|
14
vm/stack.go
14
vm/stack.go
|
@ -10,11 +10,11 @@ type Stack struct {
|
||||||
data []Word256
|
data []Word256
|
||||||
ptr int
|
ptr int
|
||||||
|
|
||||||
gas *uint64
|
gas *int64
|
||||||
err *error
|
err *error
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewStack(capacity int, gas *uint64, err *error) *Stack {
|
func NewStack(capacity int, gas *int64, err *error) *Stack {
|
||||||
return &Stack{
|
return &Stack{
|
||||||
data: make([]Word256, capacity),
|
data: make([]Word256, capacity),
|
||||||
ptr: 0,
|
ptr: 0,
|
||||||
|
@ -23,7 +23,7 @@ func NewStack(capacity int, gas *uint64, err *error) *Stack {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) useGas(gasToUse uint64) {
|
func (st *Stack) useGas(gasToUse int64) {
|
||||||
if *st.gas > gasToUse {
|
if *st.gas > gasToUse {
|
||||||
*st.gas -= gasToUse
|
*st.gas -= gasToUse
|
||||||
} else {
|
} else {
|
||||||
|
@ -54,8 +54,8 @@ func (st *Stack) PushBytes(bz []byte) {
|
||||||
st.Push(LeftPadWord256(bz))
|
st.Push(LeftPadWord256(bz))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) Push64(i uint64) {
|
func (st *Stack) Push64(i int64) {
|
||||||
st.Push(Uint64ToWord256(i))
|
st.Push(Int64ToWord256(i))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) Pop() Word256 {
|
func (st *Stack) Pop() Word256 {
|
||||||
|
@ -72,9 +72,9 @@ func (st *Stack) PopBytes() []byte {
|
||||||
return st.Pop().Bytes()
|
return st.Pop().Bytes()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) Pop64() uint64 {
|
func (st *Stack) Pop64() int64 {
|
||||||
d := st.Pop()
|
d := st.Pop()
|
||||||
return Uint64FromWord256(d)
|
return Int64FromWord256(d)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (st *Stack) Len() int {
|
func (st *Stack) Len() int {
|
||||||
|
|
|
@ -80,6 +80,6 @@ func createAddress(creator *Account) Word256 {
|
||||||
creator.Nonce += 1
|
creator.Nonce += 1
|
||||||
temp := make([]byte, 32+8)
|
temp := make([]byte, 32+8)
|
||||||
copy(temp, creator.Address[:])
|
copy(temp, creator.Address[:])
|
||||||
PutUint64BE(temp[32:], nonce)
|
PutInt64BE(temp[32:], nonce)
|
||||||
return LeftPadWord256(sha3.Sha3(temp)[:20])
|
return LeftPadWord256(sha3.Sha3(temp)[:20])
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,13 +43,13 @@ func TestVM(t *testing.T) {
|
||||||
|
|
||||||
// Create accounts
|
// Create accounts
|
||||||
account1 := &Account{
|
account1 := &Account{
|
||||||
Address: Uint64ToWord256(100),
|
Address: Int64ToWord256(100),
|
||||||
}
|
}
|
||||||
account2 := &Account{
|
account2 := &Account{
|
||||||
Address: Uint64ToWord256(101),
|
Address: Int64ToWord256(101),
|
||||||
}
|
}
|
||||||
|
|
||||||
var gas uint64 = 100000
|
var gas int64 = 100000
|
||||||
N := []byte{0x0f, 0x0f}
|
N := []byte{0x0f, 0x0f}
|
||||||
// Loop N times
|
// Loop N times
|
||||||
code := []byte{0x60, 0x00, 0x60, 0x20, 0x52, 0x5B, byte(0x60 + len(N) - 1)}
|
code := []byte{0x60, 0x00, 0x60, 0x20, 0x52, 0x5B, byte(0x60 + len(N) - 1)}
|
||||||
|
@ -81,7 +81,7 @@ func TestSubcurrency(t *testing.T) {
|
||||||
|
|
||||||
ourVm := NewVM(st, newParams(), Zero256, nil)
|
ourVm := NewVM(st, newParams(), Zero256, nil)
|
||||||
|
|
||||||
var gas uint64 = 1000
|
var gas int64 = 1000
|
||||||
code_parts := []string{"620f42403355",
|
code_parts := []string{"620f42403355",
|
||||||
"7c0100000000000000000000000000000000000000000000000000000000",
|
"7c0100000000000000000000000000000000000000000000000000000000",
|
||||||
"600035046315cf268481141561004657",
|
"600035046315cf268481141561004657",
|
||||||
|
@ -105,13 +105,13 @@ func TestSendCall(t *testing.T) {
|
||||||
|
|
||||||
// Create accounts
|
// Create accounts
|
||||||
account1 := &Account{
|
account1 := &Account{
|
||||||
Address: Uint64ToWord256(100),
|
Address: Int64ToWord256(100),
|
||||||
}
|
}
|
||||||
account2 := &Account{
|
account2 := &Account{
|
||||||
Address: Uint64ToWord256(101),
|
Address: Int64ToWord256(101),
|
||||||
}
|
}
|
||||||
account3 := &Account{
|
account3 := &Account{
|
||||||
Address: Uint64ToWord256(102),
|
Address: Int64ToWord256(102),
|
||||||
}
|
}
|
||||||
|
|
||||||
// account1 will call account2 which will trigger CALL opcode to account3
|
// account1 will call account2 which will trigger CALL opcode to account3
|
||||||
|
@ -146,7 +146,7 @@ func TestSendCall(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// subscribes to an AccReceive, runs the vm, returns the exception
|
// subscribes to an AccReceive, runs the vm, returns the exception
|
||||||
func runVMWaitEvents(t *testing.T, ourVm *VM, caller, callee *Account, subscribeAddr, contractCode []byte, gas uint64) string {
|
func runVMWaitEvents(t *testing.T, ourVm *VM, caller, callee *Account, subscribeAddr, contractCode []byte, gas int64) string {
|
||||||
// we need to catch the event from the CALL to check for exceptions
|
// we need to catch the event from the CALL to check for exceptions
|
||||||
evsw := new(events.EventSwitch)
|
evsw := new(events.EventSwitch)
|
||||||
evsw.Start()
|
evsw.Start()
|
||||||
|
|
10
vm/types.go
10
vm/types.go
|
@ -10,9 +10,9 @@ const (
|
||||||
|
|
||||||
type Account struct {
|
type Account struct {
|
||||||
Address Word256
|
Address Word256
|
||||||
Balance uint64
|
Balance int64
|
||||||
Code []byte
|
Code []byte
|
||||||
Nonce uint64
|
Nonce int64
|
||||||
StorageRoot Word256
|
StorageRoot Word256
|
||||||
Other interface{} // For holding all other data.
|
Other interface{} // For holding all other data.
|
||||||
}
|
}
|
||||||
|
@ -26,7 +26,7 @@ type Log struct {
|
||||||
Address Word256
|
Address Word256
|
||||||
Topics []Word256
|
Topics []Word256
|
||||||
Data []byte
|
Data []byte
|
||||||
Height uint64
|
Height int64
|
||||||
}
|
}
|
||||||
|
|
||||||
type AppState interface {
|
type AppState interface {
|
||||||
|
@ -46,8 +46,8 @@ type AppState interface {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Params struct {
|
type Params struct {
|
||||||
BlockHeight uint64
|
BlockHeight int64
|
||||||
BlockHash Word256
|
BlockHash Word256
|
||||||
BlockTime int64
|
BlockTime int64
|
||||||
GasLimit uint64
|
GasLimit int64
|
||||||
}
|
}
|
||||||
|
|
42
vm/vm.go
42
vm/vm.go
|
@ -72,7 +72,7 @@ func (vm *VM) SetFireable(evc events.Fireable) {
|
||||||
// value: To be transferred from caller to callee. Refunded upon error.
|
// value: To be transferred from caller to callee. Refunded upon error.
|
||||||
// gas: Available gas. No refunds for gas.
|
// gas: Available gas. No refunds for gas.
|
||||||
// code: May be nil, since the CALL opcode may be used to send value from contracts to accounts
|
// code: May be nil, since the CALL opcode may be used to send value from contracts to accounts
|
||||||
func (vm *VM) Call(caller, callee *Account, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
|
func (vm *VM) Call(caller, callee *Account, code, input []byte, value int64, gas *int64) (output []byte, err error) {
|
||||||
|
|
||||||
exception := new(string)
|
exception := new(string)
|
||||||
defer func() {
|
defer func() {
|
||||||
|
@ -109,14 +109,14 @@ func (vm *VM) Call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||||
}
|
}
|
||||||
|
|
||||||
// Just like Call() but does not transfer 'value' or modify the callDepth.
|
// Just like Call() but does not transfer 'value' or modify the callDepth.
|
||||||
func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, gas *uint64) (output []byte, err error) {
|
func (vm *VM) call(caller, callee *Account, code, input []byte, value int64, gas *int64) (output []byte, err error) {
|
||||||
dbg.Printf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.callDepth, caller.Address[:4], callee.Address, len(callee.Code), *gas, input)
|
dbg.Printf("(%d) (%X) %X (code=%d) gas: %v (d) %X\n", vm.callDepth, caller.Address[:4], callee.Address, len(callee.Code), *gas, input)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
pc uint64 = 0
|
pc int64 = 0
|
||||||
stack = NewStack(dataStackCapacity, gas, &err)
|
stack = NewStack(dataStackCapacity, gas, &err)
|
||||||
memory = make([]byte, memoryCapacity)
|
memory = make([]byte, memoryCapacity)
|
||||||
ok = false // convenience
|
ok = false // convenience
|
||||||
)
|
)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
|
@ -388,7 +388,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||||
if idx < 32 {
|
if idx < 32 {
|
||||||
res = val[idx]
|
res = val[idx]
|
||||||
}
|
}
|
||||||
stack.Push64(uint64(res))
|
stack.Push64(int64(res))
|
||||||
dbg.Printf(" => 0x%X\n", res)
|
dbg.Printf(" => 0x%X\n", res)
|
||||||
|
|
||||||
case SHA3: // 0x20
|
case SHA3: // 0x20
|
||||||
|
@ -444,7 +444,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||||
dbg.Printf(" => 0x%X\n", res)
|
dbg.Printf(" => 0x%X\n", res)
|
||||||
|
|
||||||
case CALLDATASIZE: // 0x36
|
case CALLDATASIZE: // 0x36
|
||||||
stack.Push64(uint64(len(input)))
|
stack.Push64(int64(len(input)))
|
||||||
dbg.Printf(" => %d\n", len(input))
|
dbg.Printf(" => %d\n", len(input))
|
||||||
|
|
||||||
case CALLDATACOPY: // 0x37
|
case CALLDATACOPY: // 0x37
|
||||||
|
@ -463,7 +463,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||||
dbg.Printf(" => [%v, %v, %v] %X\n", memOff, inputOff, length, data)
|
dbg.Printf(" => [%v, %v, %v] %X\n", memOff, inputOff, length, data)
|
||||||
|
|
||||||
case CODESIZE: // 0x38
|
case CODESIZE: // 0x38
|
||||||
l := uint64(len(code))
|
l := int64(len(code))
|
||||||
stack.Push64(l)
|
stack.Push64(l)
|
||||||
dbg.Printf(" => %d\n", l)
|
dbg.Printf(" => %d\n", l)
|
||||||
|
|
||||||
|
@ -496,7 +496,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||||
return nil, firstErr(err, ErrUnknownAddress)
|
return nil, firstErr(err, ErrUnknownAddress)
|
||||||
}
|
}
|
||||||
code := acc.Code
|
code := acc.Code
|
||||||
l := uint64(len(code))
|
l := int64(len(code))
|
||||||
stack.Push64(l)
|
stack.Push64(l)
|
||||||
dbg.Printf(" => %d\n", l)
|
dbg.Printf(" => %d\n", l)
|
||||||
|
|
||||||
|
@ -534,11 +534,11 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||||
|
|
||||||
case TIMESTAMP: // 0x42
|
case TIMESTAMP: // 0x42
|
||||||
time := vm.params.BlockTime
|
time := vm.params.BlockTime
|
||||||
stack.Push64(uint64(time))
|
stack.Push64(int64(time))
|
||||||
dbg.Printf(" => 0x%X\n", time)
|
dbg.Printf(" => 0x%X\n", time)
|
||||||
|
|
||||||
case BLOCKHEIGHT: // 0x43
|
case BLOCKHEIGHT: // 0x43
|
||||||
number := uint64(vm.params.BlockHeight)
|
number := int64(vm.params.BlockHeight)
|
||||||
stack.Push64(number)
|
stack.Push64(number)
|
||||||
dbg.Printf(" => 0x%X\n", number)
|
dbg.Printf(" => 0x%X\n", number)
|
||||||
|
|
||||||
|
@ -604,7 +604,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||||
stack.Push64(pc)
|
stack.Push64(pc)
|
||||||
|
|
||||||
case MSIZE: // 0x59
|
case MSIZE: // 0x59
|
||||||
stack.Push64(uint64(len(memory)))
|
stack.Push64(int64(len(memory)))
|
||||||
|
|
||||||
case GAS: // 0x5A
|
case GAS: // 0x5A
|
||||||
stack.Push64(*gas)
|
stack.Push64(*gas)
|
||||||
|
@ -615,7 +615,7 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||||
// Do nothing
|
// Do nothing
|
||||||
|
|
||||||
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32:
|
||||||
a := uint64(op - PUSH1 + 1)
|
a := int64(op - PUSH1 + 1)
|
||||||
codeSegment, ok := subslice(code, pc+1, a)
|
codeSegment, ok := subslice(code, pc+1, a)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, firstErr(err, ErrCodeOutOfBounds)
|
return nil, firstErr(err, ErrCodeOutOfBounds)
|
||||||
|
@ -792,8 +792,8 @@ func (vm *VM) call(caller, callee *Account, code, input []byte, value uint64, ga
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func subslice(data []byte, offset, length uint64) (ret []byte, ok bool) {
|
func subslice(data []byte, offset, length int64) (ret []byte, ok bool) {
|
||||||
size := uint64(len(data))
|
size := int64(len(data))
|
||||||
if size < offset {
|
if size < offset {
|
||||||
return nil, false
|
return nil, false
|
||||||
} else if size < offset+length {
|
} else if size < offset+length {
|
||||||
|
@ -812,15 +812,15 @@ func rightMostBytes(data []byte, n int) []byte {
|
||||||
return data[offset:]
|
return data[offset:]
|
||||||
}
|
}
|
||||||
|
|
||||||
func codeGetOp(code []byte, n uint64) OpCode {
|
func codeGetOp(code []byte, n int64) OpCode {
|
||||||
if uint64(len(code)) <= n {
|
if int64(len(code)) <= n {
|
||||||
return OpCode(0) // stop
|
return OpCode(0) // stop
|
||||||
} else {
|
} else {
|
||||||
return OpCode(code[n])
|
return OpCode(code[n])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func jump(code []byte, to uint64, pc *uint64) (err error) {
|
func jump(code []byte, to int64, pc *int64) (err error) {
|
||||||
dest := codeGetOp(code, to)
|
dest := codeGetOp(code, to)
|
||||||
if dest != JUMPDEST {
|
if dest != JUMPDEST {
|
||||||
dbg.Printf(" ~> %v invalid jump dest %v\n", to, dest)
|
dbg.Printf(" ~> %v invalid jump dest %v\n", to, dest)
|
||||||
|
@ -839,7 +839,7 @@ func firstErr(errA, errB error) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func useGas(gas *uint64, gasToUse uint64) bool {
|
func useGas(gas *int64, gasToUse int64) bool {
|
||||||
if *gas > gasToUse {
|
if *gas > gasToUse {
|
||||||
*gas -= gasToUse
|
*gas -= gasToUse
|
||||||
return true
|
return true
|
||||||
|
@ -848,7 +848,7 @@ func useGas(gas *uint64, gasToUse uint64) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func transfer(from, to *Account, amount uint64) error {
|
func transfer(from, to *Account, amount int64) error {
|
||||||
if from.Balance < amount {
|
if from.Balance < amount {
|
||||||
return ErrInsufficientBalance
|
return ErrInsufficientBalance
|
||||||
} else {
|
} else {
|
||||||
|
|
Loading…
Reference in New Issue