-
Notifications
You must be signed in to change notification settings - Fork 158
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #168 from etclabscore/feat/ancient-remote
add support for ancient storage as json-rpc service
- Loading branch information
Showing
18 changed files
with
1,491 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
# Ancient Store Memory Mapped Test Util | ||
|
||
This application is intended for testing purposed only. Ancient data is stored ephemerally. | ||
The program expects first and only argument to be an IPC path, or, the directory | ||
in which a default 'mock-freezer.ipc' path should be created. | ||
This memory mapped ancient store can also be used as a library. | ||
Package 'lib' logic may be imported and used in testing contexts as well. | ||
|
||
## Usage | ||
``` | ||
ancient-store-mem your-ipc-path | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
// Copyright 2020 The core-geth Authors | ||
// This file is part of the core-geth library. | ||
// | ||
// The core-geth 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 core-geth 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 core-geth library. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
package lib | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
"sync" | ||
) | ||
|
||
const ( | ||
freezerRemoteHashTable = "hashes" | ||
freezerRemoteHeaderTable = "headers" | ||
freezerRemoteBodiesTable = "bodies" | ||
freezerRemoteReceiptTable = "receipts" | ||
freezerRemoteDifficultyTable = "diffs" | ||
) | ||
|
||
var ( | ||
errOutOfBounds = errors.New("out of bounds") | ||
errOutOfOrder = errors.New("out of order") | ||
) | ||
|
||
// MemFreezerRemoteServerAPI is a mock freezer server implementation. | ||
type MemFreezerRemoteServerAPI struct { | ||
store map[string][]byte | ||
count uint64 | ||
mu sync.Mutex | ||
} | ||
|
||
func NewMemFreezerRemoteServerAPI() *MemFreezerRemoteServerAPI { | ||
return &MemFreezerRemoteServerAPI{store: make(map[string][]byte)} | ||
} | ||
|
||
func (r *MemFreezerRemoteServerAPI) storeKey(kind string, number uint64) string { | ||
return fmt.Sprintf("%s-%d", kind, number) | ||
} | ||
|
||
func (f *MemFreezerRemoteServerAPI) Reset() { | ||
f.count = 0 | ||
f.mu.Lock() | ||
f.store = make(map[string][]byte) | ||
f.mu.Unlock() | ||
} | ||
|
||
func (f *MemFreezerRemoteServerAPI) HasAncient(kind string, number uint64) (bool, error) { | ||
fmt.Println("mock server called", "method=HasAncient") | ||
f.mu.Lock() | ||
defer f.mu.Unlock() | ||
_, ok := f.store[f.storeKey(kind, number)] | ||
return ok, nil | ||
} | ||
|
||
func (f *MemFreezerRemoteServerAPI) Ancient(kind string, number uint64) ([]byte, error) { | ||
fmt.Println("mock server called", "method=Ancient") | ||
f.mu.Lock() | ||
defer f.mu.Unlock() | ||
v, ok := f.store[f.storeKey(kind, number)] | ||
if !ok { | ||
return nil, errOutOfBounds | ||
} | ||
return v, nil | ||
} | ||
|
||
func (f *MemFreezerRemoteServerAPI) Ancients() (uint64, error) { | ||
fmt.Println("mock server called", "method=Ancients") | ||
return f.count, nil | ||
} | ||
|
||
func (f *MemFreezerRemoteServerAPI) AncientSize(kind string) (uint64, error) { | ||
fmt.Println("mock server called", "method=AncientSize") | ||
sum := uint64(0) | ||
for k, v := range f.store { | ||
if strings.HasPrefix(k, kind) { | ||
sum += uint64(len(v)) | ||
} | ||
} | ||
return sum, nil | ||
} | ||
|
||
func (f *MemFreezerRemoteServerAPI) AppendAncient(number uint64, hash, header, body, receipt, td []byte) error { | ||
fmt.Println("mock server called", "method=AppendAncient", "number=", number, "header", fmt.Sprintf("%x", header)) | ||
fieldNames := []string{ | ||
freezerRemoteHashTable, | ||
freezerRemoteHeaderTable, | ||
freezerRemoteBodiesTable, | ||
freezerRemoteReceiptTable, | ||
freezerRemoteDifficultyTable, | ||
} | ||
fields := [][]byte{hash, header, body, receipt, td} | ||
if number != f.count { | ||
return errOutOfOrder | ||
} | ||
f.count = number + 1 | ||
f.mu.Lock() | ||
defer f.mu.Unlock() | ||
for i, fv := range fields { | ||
kind := fieldNames[i] | ||
f.store[f.storeKey(kind, number)] = fv | ||
} | ||
return nil | ||
} | ||
|
||
func (f *MemFreezerRemoteServerAPI) TruncateAncients(n uint64) error { | ||
fmt.Println("mock server called", "method=TruncateAncients") | ||
f.count = n | ||
f.mu.Lock() | ||
defer f.mu.Unlock() | ||
for k := range f.store { | ||
spl := strings.Split(k, "-") | ||
num, err := strconv.ParseUint(spl[1], 10, 64) | ||
if err != nil { | ||
return err | ||
} | ||
if num >= n { | ||
delete(f.store, k) | ||
} | ||
} | ||
return nil | ||
} | ||
|
||
func (f *MemFreezerRemoteServerAPI) Sync() error { | ||
fmt.Println("mock server called", "method=Sync") | ||
return nil | ||
} | ||
|
||
func (f *MemFreezerRemoteServerAPI) Close() error { | ||
fmt.Println("mock server called", "method=Close") | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// Copyright 2020 The core-geth Authors | ||
// This file is part of the core-geth library. | ||
// | ||
// The core-geth 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 core-geth 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 core-geth library. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
package main | ||
|
||
func main() { | ||
Execute() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// Copyright 2020 The core-geth Authors | ||
// This file is part of the core-geth library. | ||
// | ||
// The core-geth 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 core-geth 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 core-geth library. If not, see <http://www.gnu.org/licenses/>. | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"os" | ||
"path/filepath" | ||
|
||
"github.com/ethereum/go-ethereum/cmd/ancient-store-mem/lib" | ||
"github.com/ethereum/go-ethereum/rpc" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
// rootCmd represents the base command when called without any subcommands | ||
var rootCmd = &cobra.Command{ | ||
Use: "ancient-store-mem", | ||
Short: "Memory-backed remote ancient store application", | ||
Long: `Uses a memory-backed map to store ancient data. | ||
This application is intended for testing purposed only. | ||
Ancient data is stored ephemerally. | ||
Expects first and only argument to an IPC path, or, the directory | ||
in which a default 'mock-freezer.ipc' path should be created. | ||
Package 'lib' logic may be imported and used in testing contexts as well. | ||
`, | ||
|
||
Run: func(cmd *cobra.Command, args []string) { | ||
ipcPath := args[0] | ||
fi, err := os.Stat(ipcPath) | ||
if err != nil && !os.IsNotExist(err) { | ||
log.Fatalln(err) | ||
} | ||
if fi != nil && fi.IsDir() { | ||
ipcPath = filepath.Join(ipcPath, "mock-freezer.ipc") | ||
} | ||
listener, server, err := rpc.StartIPCEndpoint(ipcPath, nil) | ||
if err != nil { | ||
log.Fatalln(err) | ||
} | ||
defer os.Remove(ipcPath) | ||
mock := lib.NewMemFreezerRemoteServerAPI() | ||
err = server.RegisterName("freezer", mock) | ||
if err != nil { | ||
log.Fatalln(err) | ||
} | ||
quit := make(chan bool, 1) | ||
go func() { | ||
log.Println("Serving", listener.Addr()) | ||
log.Fatalln(server.ServeListener(listener)) | ||
}() | ||
<-quit | ||
}, | ||
} | ||
|
||
// Execute adds all child commands to the root command and sets flags appropriately. | ||
// This is called by main.main(). It only needs to happen once to the rootCmd. | ||
func Execute() { | ||
if err := rootCmd.Execute(); err != nil { | ||
fmt.Println(err) | ||
os.Exit(1) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.