mirror of https://github.com/poanetwork/gecko.git
Merge branch 'master' into gossip
This commit is contained in:
commit
2e2e033562
|
@ -12,6 +12,7 @@ import (
|
|||
|
||||
"github.com/ava-labs/gecko/database"
|
||||
"github.com/ava-labs/gecko/database/nodb"
|
||||
"github.com/ava-labs/gecko/utils"
|
||||
"github.com/ava-labs/gecko/utils/hashing"
|
||||
"github.com/ava-labs/gecko/vms/components/codec"
|
||||
)
|
||||
|
@ -174,7 +175,7 @@ type batch struct {
|
|||
}
|
||||
|
||||
func (b *batch) Put(key, value []byte) error {
|
||||
b.writes = append(b.writes, keyValue{copyBytes(key), copyBytes(value), false})
|
||||
b.writes = append(b.writes, keyValue{utils.CopyBytes(key), utils.CopyBytes(value), false})
|
||||
encValue, err := b.db.encrypt(value)
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -183,7 +184,7 @@ func (b *batch) Put(key, value []byte) error {
|
|||
}
|
||||
|
||||
func (b *batch) Delete(key []byte) error {
|
||||
b.writes = append(b.writes, keyValue{copyBytes(key), nil, true})
|
||||
b.writes = append(b.writes, keyValue{utils.CopyBytes(key), nil, true})
|
||||
return b.Batch.Delete(key)
|
||||
}
|
||||
|
||||
|
@ -251,12 +252,6 @@ func (it *iterator) Error() error {
|
|||
|
||||
func (it *iterator) Value() []byte { return it.val }
|
||||
|
||||
func copyBytes(bytes []byte) []byte {
|
||||
copiedBytes := make([]byte, len(bytes))
|
||||
copy(copiedBytes, bytes)
|
||||
return copiedBytes
|
||||
}
|
||||
|
||||
type encryptedValue struct {
|
||||
Ciphertext []byte `serialize:"true"`
|
||||
Nonce []byte `serialize:"true"`
|
||||
|
|
|
@ -17,46 +17,42 @@ package database
|
|||
// iterator until exhaustion. An iterator is not safe for concurrent use, but it
|
||||
// is safe to use multiple iterators concurrently.
|
||||
type Iterator interface {
|
||||
// Next moves the iterator to the next key/value pair. It returns whether the
|
||||
// iterator is exhausted.
|
||||
// Next moves the iterator to the next key/value pair. It returns whether
|
||||
// the iterator is exhausted.
|
||||
Next() bool
|
||||
|
||||
// Error returns any accumulated error. Exhausting all the key/value pairs
|
||||
// is not considered to be an error.
|
||||
Error() error
|
||||
|
||||
// Key returns the key of the current key/value pair, or nil if done. The caller
|
||||
// should not modify the contents of the returned slice, and its contents may
|
||||
// change on the next call to Next.
|
||||
// Key returns the key of the current key/value pair, or nil if done.
|
||||
Key() []byte
|
||||
|
||||
// Value returns the value of the current key/value pair, or nil if done. The
|
||||
// caller should not modify the contents of the returned slice, and its contents
|
||||
// may change on the next call to Next.
|
||||
// Value returns the value of the current key/value pair, or nil if done.
|
||||
Value() []byte
|
||||
|
||||
// Release releases associated resources. Release should always succeed and can
|
||||
// be called multiple times without causing error.
|
||||
// Release releases associated resources. Release should always succeed and
|
||||
// can be called multiple times without causing error.
|
||||
Release()
|
||||
}
|
||||
|
||||
// Iteratee wraps the NewIterator methods of a backing data store.
|
||||
type Iteratee interface {
|
||||
// NewIterator creates a binary-alphabetical iterator over the entire keyspace
|
||||
// contained within the key-value database.
|
||||
// NewIterator creates a binary-alphabetical iterator over the entire
|
||||
// keyspace contained within the key-value database.
|
||||
NewIterator() Iterator
|
||||
|
||||
// NewIteratorWithStart creates a binary-alphabetical iterator over a subset of
|
||||
// database content starting at a particular initial key (or after, if it does
|
||||
// not exist).
|
||||
// NewIteratorWithStart creates a binary-alphabetical iterator over a subset
|
||||
// of database content starting at a particular initial key (or after, if it
|
||||
// does not exist).
|
||||
NewIteratorWithStart(start []byte) Iterator
|
||||
|
||||
// NewIteratorWithPrefix creates a binary-alphabetical iterator over a subset
|
||||
// of database content with a particular key prefix.
|
||||
// NewIteratorWithPrefix creates a binary-alphabetical iterator over a
|
||||
// subset of database content with a particular key prefix.
|
||||
NewIteratorWithPrefix(prefix []byte) Iterator
|
||||
|
||||
// NewIteratorWithStartAndPrefix creates a binary-alphabetical iterator over a
|
||||
// subset of database content with a particular key prefix starting at a
|
||||
// NewIteratorWithStartAndPrefix creates a binary-alphabetical iterator over
|
||||
// a subset of database content with a particular key prefix starting at a
|
||||
// specified key.
|
||||
NewIteratorWithStartAndPrefix(start, prefix []byte) Iterator
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@ import (
|
|||
"bytes"
|
||||
|
||||
"github.com/ava-labs/gecko/database"
|
||||
"github.com/ava-labs/gecko/utils"
|
||||
"github.com/syndtr/goleveldb/leveldb"
|
||||
"github.com/syndtr/goleveldb/leveldb/errors"
|
||||
"github.com/syndtr/goleveldb/leveldb/filter"
|
||||
|
@ -208,7 +209,14 @@ func (r *replayer) Delete(key []byte) {
|
|||
|
||||
type iter struct{ iterator.Iterator }
|
||||
|
||||
func (i *iter) Error() error { return updateError(i.Iterator.Error()) }
|
||||
// Error implements the Iterator interface
|
||||
func (it *iter) Error() error { return updateError(it.Iterator.Error()) }
|
||||
|
||||
// Key implements the Iterator interface
|
||||
func (it *iter) Key() []byte { return utils.CopyBytes(it.Iterator.Key()) }
|
||||
|
||||
// Value implements the Iterator interface
|
||||
func (it *iter) Value() []byte { return utils.CopyBytes(it.Iterator.Value()) }
|
||||
|
||||
func updateError(err error) error {
|
||||
switch err {
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
|
||||
"github.com/ava-labs/gecko/database"
|
||||
"github.com/ava-labs/gecko/database/nodb"
|
||||
"github.com/ava-labs/gecko/utils"
|
||||
)
|
||||
|
||||
// DefaultSize is the default initial size of the memory database
|
||||
|
@ -62,7 +63,7 @@ func (db *Database) Get(key []byte) ([]byte, error) {
|
|||
return nil, database.ErrClosed
|
||||
}
|
||||
if entry, ok := db.db[string(key)]; ok {
|
||||
return copyBytes(entry), nil
|
||||
return utils.CopyBytes(entry), nil
|
||||
}
|
||||
return nil, database.ErrNotFound
|
||||
}
|
||||
|
@ -75,7 +76,7 @@ func (db *Database) Put(key []byte, value []byte) error {
|
|||
if db.db == nil {
|
||||
return database.ErrClosed
|
||||
}
|
||||
db.db[string(key)] = copyBytes(value)
|
||||
db.db[string(key)] = utils.CopyBytes(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -154,13 +155,13 @@ type batch struct {
|
|||
}
|
||||
|
||||
func (b *batch) Put(key, value []byte) error {
|
||||
b.writes = append(b.writes, keyValue{copyBytes(key), copyBytes(value), false})
|
||||
b.writes = append(b.writes, keyValue{utils.CopyBytes(key), utils.CopyBytes(value), false})
|
||||
b.size += len(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *batch) Delete(key []byte) error {
|
||||
b.writes = append(b.writes, keyValue{copyBytes(key), nil, true})
|
||||
b.writes = append(b.writes, keyValue{utils.CopyBytes(key), nil, true})
|
||||
b.size++
|
||||
return nil
|
||||
}
|
||||
|
@ -253,9 +254,3 @@ func (it *iterator) Value() []byte {
|
|||
|
||||
// Release implements the Iterator interface
|
||||
func (it *iterator) Release() { it.keys = nil; it.values = nil }
|
||||
|
||||
func copyBytes(bytes []byte) []byte {
|
||||
copiedBytes := make([]byte, len(bytes))
|
||||
copy(copiedBytes, bytes)
|
||||
return copiedBytes
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
|
||||
"github.com/ava-labs/gecko/database"
|
||||
"github.com/ava-labs/gecko/database/nodb"
|
||||
"github.com/ava-labs/gecko/utils"
|
||||
"github.com/ava-labs/gecko/utils/hashing"
|
||||
)
|
||||
|
||||
|
@ -174,13 +175,13 @@ type batch struct {
|
|||
|
||||
// Put implements the Batch interface
|
||||
func (b *batch) Put(key, value []byte) error {
|
||||
b.writes = append(b.writes, keyValue{copyBytes(key), copyBytes(value), false})
|
||||
b.writes = append(b.writes, keyValue{utils.CopyBytes(key), utils.CopyBytes(value), false})
|
||||
return b.Batch.Put(b.db.prefix(key), value)
|
||||
}
|
||||
|
||||
// Delete implements the Batch interface
|
||||
func (b *batch) Delete(key []byte) error {
|
||||
b.writes = append(b.writes, keyValue{copyBytes(key), nil, true})
|
||||
b.writes = append(b.writes, keyValue{utils.CopyBytes(key), nil, true})
|
||||
return b.Batch.Delete(b.db.prefix(key))
|
||||
}
|
||||
|
||||
|
@ -229,9 +230,3 @@ func (it *iterator) Key() []byte {
|
|||
}
|
||||
return key
|
||||
}
|
||||
|
||||
func copyBytes(bytes []byte) []byte {
|
||||
copiedBytes := make([]byte, len(bytes))
|
||||
copy(copiedBytes, bytes)
|
||||
return copiedBytes
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/ava-labs/gecko/database"
|
||||
"github.com/ava-labs/gecko/database/nodb"
|
||||
"github.com/ava-labs/gecko/database/rpcdb/rpcdbproto"
|
||||
"github.com/ava-labs/gecko/utils"
|
||||
)
|
||||
|
||||
var (
|
||||
|
@ -137,13 +138,13 @@ type batch struct {
|
|||
}
|
||||
|
||||
func (b *batch) Put(key, value []byte) error {
|
||||
b.writes = append(b.writes, keyValue{copyBytes(key), copyBytes(value), false})
|
||||
b.writes = append(b.writes, keyValue{utils.CopyBytes(key), utils.CopyBytes(value), false})
|
||||
b.size += len(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *batch) Delete(key []byte) error {
|
||||
b.writes = append(b.writes, keyValue{copyBytes(key), nil, true})
|
||||
b.writes = append(b.writes, keyValue{utils.CopyBytes(key), nil, true})
|
||||
b.size++
|
||||
return nil
|
||||
}
|
||||
|
@ -246,12 +247,6 @@ func (it *iterator) Release() {
|
|||
})
|
||||
}
|
||||
|
||||
func copyBytes(bytes []byte) []byte {
|
||||
copiedBytes := make([]byte, len(bytes))
|
||||
copy(copiedBytes, bytes)
|
||||
return copiedBytes
|
||||
}
|
||||
|
||||
func updateError(err error) error {
|
||||
if err == nil {
|
||||
return nil
|
||||
|
|
|
@ -24,6 +24,7 @@ var (
|
|||
TestIteratorStart,
|
||||
TestIteratorPrefix,
|
||||
TestIteratorStartPrefix,
|
||||
TestIteratorMemorySafety,
|
||||
TestIteratorClosed,
|
||||
TestStatNoPanic,
|
||||
TestCompactNoPanic,
|
||||
|
@ -622,6 +623,63 @@ func TestIteratorStartPrefix(t *testing.T, db Database) {
|
|||
}
|
||||
}
|
||||
|
||||
// TestIteratorMemorySafety ...
|
||||
func TestIteratorMemorySafety(t *testing.T, db Database) {
|
||||
key1 := []byte("hello1")
|
||||
value1 := []byte("world1")
|
||||
|
||||
key2 := []byte("z")
|
||||
value2 := []byte("world2")
|
||||
|
||||
key3 := []byte("hello3")
|
||||
value3 := []byte("world3")
|
||||
|
||||
if err := db.Put(key1, value1); err != nil {
|
||||
t.Fatalf("Unexpected error on batch.Put: %s", err)
|
||||
} else if err := db.Put(key2, value2); err != nil {
|
||||
t.Fatalf("Unexpected error on batch.Put: %s", err)
|
||||
} else if err := db.Put(key3, value3); err != nil {
|
||||
t.Fatalf("Unexpected error on batch.Put: %s", err)
|
||||
}
|
||||
|
||||
iterator := db.NewIterator()
|
||||
if iterator == nil {
|
||||
t.Fatalf("db.NewIterator returned nil")
|
||||
}
|
||||
defer iterator.Release()
|
||||
|
||||
keys := [][]byte{}
|
||||
values := [][]byte{}
|
||||
for iterator.Next() {
|
||||
keys = append(keys, iterator.Key())
|
||||
values = append(values, iterator.Value())
|
||||
}
|
||||
|
||||
expectedKeys := [][]byte{
|
||||
key1,
|
||||
key3,
|
||||
key2,
|
||||
}
|
||||
expectedValues := [][]byte{
|
||||
value1,
|
||||
value3,
|
||||
value2,
|
||||
}
|
||||
|
||||
for i, key := range keys {
|
||||
value := values[i]
|
||||
expectedKey := expectedKeys[i]
|
||||
expectedValue := expectedValues[i]
|
||||
|
||||
if !bytes.Equal(key, expectedKey) {
|
||||
t.Fatalf("Wrong key")
|
||||
}
|
||||
if !bytes.Equal(value, expectedValue) {
|
||||
t.Fatalf("Wrong key")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestIteratorClosed ...
|
||||
func TestIteratorClosed(t *testing.T, db Database) {
|
||||
key1 := []byte("hello1")
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/ava-labs/gecko/database"
|
||||
"github.com/ava-labs/gecko/database/memdb"
|
||||
"github.com/ava-labs/gecko/database/nodb"
|
||||
"github.com/ava-labs/gecko/utils"
|
||||
)
|
||||
|
||||
// Database implements the Database interface by living on top of another
|
||||
|
@ -61,7 +62,7 @@ func (db *Database) Get(key []byte) ([]byte, error) {
|
|||
if val.delete {
|
||||
return nil, database.ErrNotFound
|
||||
}
|
||||
return copyBytes(val.value), nil
|
||||
return utils.CopyBytes(val.value), nil
|
||||
}
|
||||
return db.db.Get(key)
|
||||
}
|
||||
|
@ -262,14 +263,14 @@ type batch struct {
|
|||
|
||||
// Put implements the Database interface
|
||||
func (b *batch) Put(key, value []byte) error {
|
||||
b.writes = append(b.writes, keyValue{copyBytes(key), copyBytes(value), false})
|
||||
b.writes = append(b.writes, keyValue{utils.CopyBytes(key), utils.CopyBytes(value), false})
|
||||
b.size += len(value)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete implements the Database interface
|
||||
func (b *batch) Delete(key []byte) error {
|
||||
b.writes = append(b.writes, keyValue{copyBytes(key), nil, true})
|
||||
b.writes = append(b.writes, keyValue{utils.CopyBytes(key), nil, true})
|
||||
b.size++
|
||||
return nil
|
||||
}
|
||||
|
@ -414,9 +415,3 @@ func (it *iterator) Release() {
|
|||
it.values = nil
|
||||
it.Iterator.Release()
|
||||
}
|
||||
|
||||
func copyBytes(bytes []byte) []byte {
|
||||
copiedBytes := make([]byte, len(bytes))
|
||||
copy(copiedBytes, bytes)
|
||||
return copiedBytes
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package utils
|
||||
|
||||
// CopyBytes returns a copy of the provided byte slice. If nil is provided, nil
|
||||
// will be returned.
|
||||
func CopyBytes(b []byte) []byte {
|
||||
if b == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
cb := make([]byte, len(b))
|
||||
copy(cb, b)
|
||||
return cb
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
// (c) 2019-2020, Ava Labs, Inc. All rights reserved.
|
||||
// See the file LICENSE for licensing terms.
|
||||
|
||||
package utils
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestCopyBytesNil(t *testing.T) {
|
||||
result := CopyBytes(nil)
|
||||
assert.Nil(t, result, "CopyBytes(nil) should have returned nil")
|
||||
}
|
||||
|
||||
func TestCopyBytes(t *testing.T) {
|
||||
input := []byte{1}
|
||||
result := CopyBytes(input)
|
||||
assert.Equal(t, input, result, "CopyBytes should have returned equal bytes")
|
||||
|
||||
input[0] = 0
|
||||
assert.NotEqual(t, input, result, "CopyBytes should have returned independent bytes")
|
||||
}
|
|
@ -130,8 +130,6 @@ func (s *state) SetStatus(id ids.ID, status choices.Status) error {
|
|||
return s.vm.db.Delete(id.Bytes())
|
||||
}
|
||||
|
||||
s.c.Put(id, status)
|
||||
|
||||
p := wrappers.Packer{Bytes: make([]byte, 4)}
|
||||
|
||||
p.PackInt(uint32(status))
|
||||
|
@ -143,6 +141,8 @@ func (s *state) SetStatus(id ids.ID, status choices.Status) error {
|
|||
if p.Errored() {
|
||||
return p.Err
|
||||
}
|
||||
|
||||
s.c.Put(id, status)
|
||||
return s.vm.db.Put(id.Bytes(), p.Bytes)
|
||||
}
|
||||
|
||||
|
@ -186,8 +186,6 @@ func (s *state) SetIDs(id ids.ID, idSlice []ids.ID) error {
|
|||
return s.vm.db.Delete(id.Bytes())
|
||||
}
|
||||
|
||||
s.c.Put(id, idSlice)
|
||||
|
||||
size := wrappers.IntLen + hashing.HashLen*len(idSlice)
|
||||
p := wrappers.Packer{Bytes: make([]byte, size)}
|
||||
|
||||
|
@ -203,5 +201,7 @@ func (s *state) SetIDs(id ids.ID, idSlice []ids.ID) error {
|
|||
if p.Errored() {
|
||||
return p.Err
|
||||
}
|
||||
|
||||
s.c.Put(id, idSlice)
|
||||
return s.vm.db.Put(id.Bytes(), p.Bytes)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue