| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | // Copyright 2019 The go-ethereum Authors | 
					
						
							|  |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package dbtest | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bytes" | 
					
						
							|  |  |  | 	"reflect" | 
					
						
							|  |  |  | 	"sort" | 
					
						
							|  |  |  | 	"testing" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	"github.com/ethereum/go-ethereum/ethdb" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TestDatabaseSuite runs a suite of tests against a KeyValueStore database | 
					
						
							|  |  |  | // implementation. | 
					
						
							|  |  |  | func TestDatabaseSuite(t *testing.T, New func() ethdb.KeyValueStore) { | 
					
						
							|  |  |  | 	t.Run("Iterator", func(t *testing.T) { | 
					
						
							|  |  |  | 		tests := []struct { | 
					
						
							|  |  |  | 			content map[string]string | 
					
						
							|  |  |  | 			prefix  string | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 			start   string | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			order   []string | 
					
						
							|  |  |  | 		}{ | 
					
						
							|  |  |  | 			// Empty databases should be iterable | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 			{map[string]string{}, "", "", nil}, | 
					
						
							|  |  |  | 			{map[string]string{}, "non-existent-prefix", "", nil}, | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// Single-item databases should be iterable | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 			{map[string]string{"key": "val"}, "", "", []string{"key"}}, | 
					
						
							|  |  |  | 			{map[string]string{"key": "val"}, "k", "", []string{"key"}}, | 
					
						
							|  |  |  | 			{map[string]string{"key": "val"}, "l", "", nil}, | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// Multi-item databases should be fully iterable | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				map[string]string{"k1": "v1", "k5": "v5", "k2": "v2", "k4": "v4", "k3": "v3"}, | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 				"", "", | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 				[]string{"k1", "k2", "k3", "k4", "k5"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				map[string]string{"k1": "v1", "k5": "v5", "k2": "v2", "k4": "v4", "k3": "v3"}, | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 				"k", "", | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 				[]string{"k1", "k2", "k3", "k4", "k5"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				map[string]string{"k1": "v1", "k5": "v5", "k2": "v2", "k4": "v4", "k3": "v3"}, | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 				"l", "", | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 				nil, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			// Multi-item databases should be prefix-iterable | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				map[string]string{ | 
					
						
							|  |  |  | 					"ka1": "va1", "ka5": "va5", "ka2": "va2", "ka4": "va4", "ka3": "va3", | 
					
						
							|  |  |  | 					"kb1": "vb1", "kb5": "vb5", "kb2": "vb2", "kb4": "vb4", "kb3": "vb3", | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 				"ka", "", | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 				[]string{"ka1", "ka2", "ka3", "ka4", "ka5"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				map[string]string{ | 
					
						
							|  |  |  | 					"ka1": "va1", "ka5": "va5", "ka2": "va2", "ka4": "va4", "ka3": "va3", | 
					
						
							|  |  |  | 					"kb1": "vb1", "kb5": "vb5", "kb2": "vb2", "kb4": "vb4", "kb3": "vb3", | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 				"kc", "", | 
					
						
							|  |  |  | 				nil, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			// Multi-item databases should be prefix-iterable with start position | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				map[string]string{ | 
					
						
							|  |  |  | 					"ka1": "va1", "ka5": "va5", "ka2": "va2", "ka4": "va4", "ka3": "va3", | 
					
						
							|  |  |  | 					"kb1": "vb1", "kb5": "vb5", "kb2": "vb2", "kb4": "vb4", "kb3": "vb3", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"ka", "3", | 
					
						
							|  |  |  | 				[]string{"ka3", "ka4", "ka5"}, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				map[string]string{ | 
					
						
							|  |  |  | 					"ka1": "va1", "ka5": "va5", "ka2": "va2", "ka4": "va4", "ka3": "va3", | 
					
						
							|  |  |  | 					"kb1": "vb1", "kb5": "vb5", "kb2": "vb2", "kb4": "vb4", "kb3": "vb3", | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 				"ka", "8", | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 				nil, | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for i, tt := range tests { | 
					
						
							|  |  |  | 			// Create the key-value data store | 
					
						
							|  |  |  | 			db := New() | 
					
						
							|  |  |  | 			for key, val := range tt.content { | 
					
						
							|  |  |  | 				if err := db.Put([]byte(key), []byte(val)); err != nil { | 
					
						
							|  |  |  | 					t.Fatalf("test %d: failed to insert item %s:%s into database: %v", i, key, val, err) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// Iterate over the database with the given configs and verify the results | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 			it, idx := db.NewIterator([]byte(tt.prefix), []byte(tt.start)), 0 | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			for it.Next() { | 
					
						
							|  |  |  | 				if len(tt.order) <= idx { | 
					
						
							|  |  |  | 					t.Errorf("test %d: prefix=%q more items than expected: checking idx=%d (key %q), expecting len=%d", i, tt.prefix, idx, it.Key(), len(tt.order)) | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if !bytes.Equal(it.Key(), []byte(tt.order[idx])) { | 
					
						
							|  |  |  | 					t.Errorf("test %d: item %d: key mismatch: have %s, want %s", i, idx, string(it.Key()), tt.order[idx]) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				if !bytes.Equal(it.Value(), []byte(tt.content[tt.order[idx]])) { | 
					
						
							|  |  |  | 					t.Errorf("test %d: item %d: value mismatch: have %s, want %s", i, idx, string(it.Value()), tt.content[tt.order[idx]]) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				idx++ | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if err := it.Error(); err != nil { | 
					
						
							|  |  |  | 				t.Errorf("test %d: iteration failed: %v", i, err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if idx != len(tt.order) { | 
					
						
							|  |  |  | 				t.Errorf("test %d: iteration terminated prematurely: have %d, want %d", i, idx, len(tt.order)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			db.Close() | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("IteratorWith", func(t *testing.T) { | 
					
						
							|  |  |  | 		db := New() | 
					
						
							|  |  |  | 		defer db.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		keys := []string{"1", "2", "3", "4", "6", "10", "11", "12", "20", "21", "22"} | 
					
						
							|  |  |  | 		sort.Strings(keys) // 1, 10, 11, etc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		for _, k := range keys { | 
					
						
							|  |  |  | 			if err := db.Put([]byte(k), nil); err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 			it := db.NewIterator(nil, nil) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			got, want := iterateKeys(it), keys | 
					
						
							|  |  |  | 			if err := it.Error(); err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !reflect.DeepEqual(got, want) { | 
					
						
							|  |  |  | 				t.Errorf("Iterator: got: %s; want: %s", got, want) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 			it := db.NewIterator([]byte("1"), nil) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			got, want := iterateKeys(it), []string{"1", "10", "11", "12"} | 
					
						
							|  |  |  | 			if err := it.Error(); err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !reflect.DeepEqual(got, want) { | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 				t.Errorf("IteratorWith(1,nil): got: %s; want: %s", got, want) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 			it := db.NewIterator([]byte("5"), nil) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			got, want := iterateKeys(it), []string{} | 
					
						
							|  |  |  | 			if err := it.Error(); err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !reflect.DeepEqual(got, want) { | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 				t.Errorf("IteratorWith(5,nil): got: %s; want: %s", got, want) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 			it := db.NewIterator(nil, []byte("2")) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			got, want := iterateKeys(it), []string{"2", "20", "21", "22", "3", "4", "6"} | 
					
						
							|  |  |  | 			if err := it.Error(); err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !reflect.DeepEqual(got, want) { | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 				t.Errorf("IteratorWith(nil,2): got: %s; want: %s", got, want) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 			it := db.NewIterator(nil, []byte("5")) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			got, want := iterateKeys(it), []string{"6"} | 
					
						
							|  |  |  | 			if err := it.Error(); err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if !reflect.DeepEqual(got, want) { | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 				t.Errorf("IteratorWith(nil,5): got: %s; want: %s", got, want) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("KeyValueOperations", func(t *testing.T) { | 
					
						
							|  |  |  | 		db := New() | 
					
						
							|  |  |  | 		defer db.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		key := []byte("foo") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if got, err := db.Has(key); err != nil { | 
					
						
							|  |  |  | 			t.Error(err) | 
					
						
							|  |  |  | 		} else if got { | 
					
						
							|  |  |  | 			t.Errorf("wrong value: %t", got) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		value := []byte("hello world") | 
					
						
							|  |  |  | 		if err := db.Put(key, value); err != nil { | 
					
						
							|  |  |  | 			t.Error(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if got, err := db.Has(key); err != nil { | 
					
						
							|  |  |  | 			t.Error(err) | 
					
						
							|  |  |  | 		} else if !got { | 
					
						
							|  |  |  | 			t.Errorf("wrong value: %t", got) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if got, err := db.Get(key); err != nil { | 
					
						
							|  |  |  | 			t.Error(err) | 
					
						
							|  |  |  | 		} else if !bytes.Equal(got, value) { | 
					
						
							|  |  |  | 			t.Errorf("wrong value: %q", got) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err := db.Delete(key); err != nil { | 
					
						
							|  |  |  | 			t.Error(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if got, err := db.Has(key); err != nil { | 
					
						
							|  |  |  | 			t.Error(err) | 
					
						
							|  |  |  | 		} else if got { | 
					
						
							|  |  |  | 			t.Errorf("wrong value: %t", got) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("Batch", func(t *testing.T) { | 
					
						
							|  |  |  | 		db := New() | 
					
						
							|  |  |  | 		defer db.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		b := db.NewBatch() | 
					
						
							|  |  |  | 		for _, k := range []string{"1", "2", "3", "4"} { | 
					
						
							|  |  |  | 			if err := b.Put([]byte(k), nil); err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if has, err := db.Has([]byte("1")); err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} else if has { | 
					
						
							|  |  |  | 			t.Error("db contains element before batch write") | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err := b.Write(); err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 			it := db.NewIterator(nil, nil) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			if got, want := iterateKeys(it), []string{"1", "2", "3", "4"}; !reflect.DeepEqual(got, want) { | 
					
						
							|  |  |  | 				t.Errorf("got: %s; want: %s", got, want) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		b.Reset() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Mix writes and deletes in batch | 
					
						
							|  |  |  | 		b.Put([]byte("5"), nil) | 
					
						
							|  |  |  | 		b.Delete([]byte("1")) | 
					
						
							|  |  |  | 		b.Put([]byte("6"), nil) | 
					
						
							|  |  |  | 		b.Delete([]byte("3")) | 
					
						
							|  |  |  | 		b.Put([]byte("3"), nil) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err := b.Write(); err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 			it := db.NewIterator(nil, nil) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 			if got, want := iterateKeys(it), []string{"2", "3", "4", "5", "6"}; !reflect.DeepEqual(got, want) { | 
					
						
							|  |  |  | 				t.Errorf("got: %s; want: %s", got, want) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	t.Run("BatchReplay", func(t *testing.T) { | 
					
						
							|  |  |  | 		db := New() | 
					
						
							|  |  |  | 		defer db.Close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		want := []string{"1", "2", "3", "4"} | 
					
						
							|  |  |  | 		b := db.NewBatch() | 
					
						
							|  |  |  | 		for _, k := range want { | 
					
						
							|  |  |  | 			if err := b.Put([]byte(k), nil); err != nil { | 
					
						
							|  |  |  | 				t.Fatal(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		b2 := db.NewBatch() | 
					
						
							|  |  |  | 		if err := b.Replay(b2); err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if err := b2.Replay(db); err != nil { | 
					
						
							|  |  |  | 			t.Fatal(err) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 		it := db.NewIterator(nil, nil) | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 		if got := iterateKeys(it); !reflect.DeepEqual(got, want) { | 
					
						
							|  |  |  | 			t.Errorf("got: %s; want: %s", got, want) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func iterateKeys(it ethdb.Iterator) []string { | 
					
						
							|  |  |  | 	keys := []string{} | 
					
						
							|  |  |  | 	for it.Next() { | 
					
						
							|  |  |  | 		keys = append(keys, string(it.Key())) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	sort.Strings(keys) | 
					
						
							| 
									
										
										
										
											2020-04-15 13:08:53 +02:00
										 |  |  | 	it.Release() | 
					
						
							| 
									
										
										
										
											2019-08-22 05:47:24 -04:00
										 |  |  | 	return keys | 
					
						
							|  |  |  | } |