Repository: NethermindEth/juno
Pull request #149 (2022-05-14 05:15:32)

Initial implementation of block manager
## Changes:
- Implement a block manage to be able to search and save the blocks

## Types of changes

What types of changes does your code introduce?
_Put an `x` in the boxes that apply_

- [ ] Bugfix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation Update
- [ ] Code style update (formatting, renaming)
- [ ] Refactoring (no functional changes, no api changes)
- [ ] Build related changes
- [ ] Other (please describe): 

## Testing
**Requires testing**

- [x] Yes
- [ ] No

**In case you checked yes, did you write tests??**

- [x] Yes
- [ ] No

codecov[bot]: # [Codecov](https://codecov.io/gh/NethermindEth/juno/pull/149?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth) Report
> Merging [#149](https://codecov.io/gh/NethermindEth/juno/pull/149?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth) (492178d) into [main](https://codecov.io/gh/NethermindEth/juno/commit/2240b0e5abf29c1c62d4ef4f014190f3aac1cd2f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth) (2240b0e) will **not change** coverage.
> The diff coverage is `100.00%`.

```diff
@@            Coverage Diff            @@
##              main      #149   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           26        28    +2     
  Lines         1427      1460   +33     
=========================================
+ Hits          1427      1460   +33     
```

| Flag | Coverage Δ | |
|---|---|---|
| unittests | `100.00% <100.00%> (ø)` | |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/NethermindEth/juno/pull/149?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth) | Coverage Δ | |
|---|---|---|
| [pkg/db/block/block.go](https://codecov.io/gh/NethermindEth/juno/pull/149/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-cGtnL2RiL2Jsb2NrL2Jsb2NrLmdv) | `100.00% <100.00%> (ø)` | |
| [pkg/db/block/manager.go](https://codecov.io/gh/NethermindEth/juno/pull/149/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-cGtnL2RiL2Jsb2NrL21hbmFnZXIuZ28=) | `100.00% <100.00%> (ø)` | |
| [pkg/rpc/server.go](https://codecov.io/gh/NethermindEth/juno/pull/149/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-cGtnL3JwYy9zZXJ2ZXIuZ28=) | `100.00% <0.00%> (ø)` | |
| [pkg/crypto/weierstrass/weierstrass.go](https://codecov.io/gh/NethermindEth/juno/pull/149/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth#diff-cGtnL2NyeXB0by93ZWllcnN0cmFzcy93ZWllcnN0cmFzcy5nbw==) | `100.00% <0.00%> (ø)` | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/NethermindEth/juno/pull/149?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/NethermindEth/juno/pull/149?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth). Last update [2240b0e...492178d](https://codecov.io/gh/NethermindEth/juno/pull/149?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=NethermindEth).


Patch:
diff --git a/internal/db/Makefile b/internal/db/Makefile
index 85b8912b..b69d9d2b 100644
--- a/internal/db/Makefile
+++ b/internal/db/Makefile
@@ -7,6 +7,7 @@ generate:
 	@protoc --proto_path=./abi --go_out=./abi --go_opt=paths=source_relative abi.proto
 	@protoc --proto_path=./transaction --go_out=./transaction --go_opt=paths=source_relative transaction.proto
 	@protoc --proto_path=./state --go_out=./state --go_opt=paths=source_relative state.proto
+	@protoc --proto_path=./block --go_out=./block --go_opt=paths=source_relative block.proto
 
 add-notest:
 	find . -name '*.pb.go' -exec sh -c "awk '/func/ { print \"// notest\"; }; 1;' {} > tmp_file && mv tmp_file {}" \;
diff --git a/internal/db/block/block.pb.go b/internal/db/block/block.pb.go
new file mode 100644
index 00000000..b68b7dc0
--- /dev/null
+++ b/internal/db/block/block.pb.go
@@ -0,0 +1,274 @@
+// Code generated by protoc-gen-go. DO NOT EDIT.
+// versions:
+// 	protoc-gen-go v1.28.0
+// 	protoc        v3.17.3
+// source: block.proto
+
+package block
+
+import (
+	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
+	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
+	reflect "reflect"
+	sync "sync"
+)
+
+const (
+	// Verify that this generated code is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
+	// Verify that runtime/protoimpl is sufficiently up-to-date.
+	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
+)
+
+type Block struct {
+	state         protoimpl.MessageState
+	sizeCache     protoimpl.SizeCache
+	unknownFields protoimpl.UnknownFields
+
+	Hash             []byte   `protobuf:"bytes,1,opt,name=hash,proto3" json:"hash,omitempty"`
+	BlockNumber      uint64   `protobuf:"varint,2,opt,name=blockNumber,proto3" json:"blockNumber,omitempty"`
+	ParentBlockHash  []byte   `protobuf:"bytes,3,opt,name=parentBlockHash,proto3" json:"parentBlockHash,omitempty"`
+	Status           string   `protobuf:"bytes,4,opt,name=status,proto3" json:"status,omitempty"`
+	SequencerAddress []byte   `protobuf:"bytes,5,opt,name=sequencerAddress,proto3" json:"sequencerAddress,omitempty"`
+	GlobalStateRoot  []byte   `protobuf:"bytes,6,opt,name=globalStateRoot,proto3" json:"globalStateRoot,omitempty"`
+	OldRoot          []byte   `protobuf:"bytes,7,opt,name=oldRoot,proto3" json:"oldRoot,omitempty"`
+	AcceptedTime     int64    `protobuf:"varint,8,opt,name=acceptedTime,proto3" json:"acceptedTime,omitempty"`
+	TimeStamp        int64    `protobuf:"varint,9,opt,name=timeStamp,proto3" json:"timeStamp,omitempty"`
+	TxCount          uint64   `protobuf:"varint,10,opt,name=txCount,proto3" json:"txCount,omitempty"`
+	TxCommitment     []byte   `protobuf:"bytes,11,opt,name=txCommitment,proto3" json:"txCommitment,omitempty"`
+	EventCount       uint64   `protobuf:"varint,12,opt,name=eventCount,proto3" json:"eventCount,omitempty"`
+	EventCommitment  []byte   `protobuf:"bytes,13,opt,name=eventCommitment,proto3" json:"eventCommitment,omitempty"`
+	TxHashes         [][]byte `protobuf:"bytes,14,rep,name=TxHashes,proto3" json:"TxHashes,omitempty"`
+}
+
+func (x *Block) Reset() {
+	*x = Block{}
+	if protoimpl.UnsafeEnabled {
+		mi := &file_block_proto_msgTypes[0]
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		ms.StoreMessageInfo(mi)
+	}
+}
+
+func (x *Block) String() string {
+	return protoimpl.X.MessageStringOf(x)
+}
+
+func (*Block) ProtoMessage() {}
+
+func (x *Block) ProtoReflect() protoreflect.Message {
+	mi := &file_block_proto_msgTypes[0]
+	if protoimpl.UnsafeEnabled && x != nil {
+		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
+		if ms.LoadMessageInfo() == nil {
+			ms.StoreMessageInfo(mi)
+		}
+		return ms
+	}
+	return mi.MessageOf(x)
+}
+
+// Deprecated: Use Block.ProtoReflect.Descriptor instead.
+func (*Block) Descriptor() ([]byte, []int) {
+	return file_block_proto_rawDescGZIP(), []int{0}
+}
+
+func (x *Block) GetHash() []byte {
+	if x != nil {
+		return x.Hash
+	}
+	return nil
+}
+
+func (x *Block) GetBlockNumber() uint64 {
+	if x != nil {
+		return x.BlockNumber
+	}
+	return 0
+}
+
+func (x *Block) GetParentBlockHash() []byte {
+	if x != nil {
+		return x.ParentBlockHash
+	}
+	return nil
+}
+
+func (x *Block) GetStatus() string {
+	if x != nil {
+		return x.Status
+	}
+	return ""
+}
+
+func (x *Block) GetSequencerAddress() []byte {
+	if x != nil {
+		return x.SequencerAddress
+	}
+	return nil
+}
+
+func (x *Block) GetGlobalStateRoot() []byte {
+	if x != nil {
+		return x.GlobalStateRoot
+	}
+	return nil
+}
+
+func (x *Block) GetOldRoot() []byte {
+	if x != nil {
+		return x.OldRoot
+	}
+	return nil
+}
+
+func (x *Block) GetAcceptedTime() int64 {
+	if x != nil {
+		return x.AcceptedTime
+	}
+	return 0
+}
+
+func (x *Block) GetTimeStamp() int64 {
+	if x != nil {
+		return x.TimeStamp
+	}
+	return 0
+}
+
+func (x *Block) GetTxCount() uint64 {
+	if x != nil {
+		return x.TxCount
+	}
+	return 0
+}
+
+func (x *Block) GetTxCommitment() []byte {
+	if x != nil {
+		return x.TxCommitment
+	}
+	return nil
+}
+
+func (x *Block) GetEventCount() uint64 {
+	if x != nil {
+		return x.EventCount
+	}
+	return 0
+}
+
+func (x *Block) GetEventCommitment() []byte {
+	if x != nil {
+		return x.EventCommitment
+	}
+	return nil
+}
+
+func (x *Block) GetTxHashes() [][]byte {
+	if x != nil {
+		return x.TxHashes
+	}
+	return nil
+}
+
+var File_block_proto protoreflect.FileDescriptor
+
+var file_block_proto_rawDesc = []byte{
+	0x0a, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xd5, 0x03,
+	0x0a, 0x05, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x61, 0x73, 0x68, 0x18,
+	0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x68, 0x61, 0x73, 0x68, 0x12, 0x20, 0x0a, 0x0b, 0x62,
+	0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04,
+	0x52, 0x0b, 0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x4e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x12, 0x28, 0x0a,
+	0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c, 0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68,
+	0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x42, 0x6c,
+	0x6f, 0x63, 0x6b, 0x48, 0x61, 0x73, 0x68, 0x12, 0x16, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
+	0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12,
+	0x2a, 0x0a, 0x10, 0x73, 0x65, 0x71, 0x75, 0x65, 0x6e, 0x63, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72,
+	0x65, 0x73, 0x73, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x10, 0x73, 0x65, 0x71, 0x75, 0x65,
+	0x6e, 0x63, 0x65, 0x72, 0x41, 0x64, 0x64, 0x72, 0x65, 0x73, 0x73, 0x12, 0x28, 0x0a, 0x0f, 0x67,
+	0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x6f, 0x6f, 0x74, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53, 0x74, 0x61, 0x74,
+	0x65, 0x52, 0x6f, 0x6f, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6f, 0x6c, 0x64, 0x52, 0x6f, 0x6f, 0x74,
+	0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x07, 0x6f, 0x6c, 0x64, 0x52, 0x6f, 0x6f, 0x74, 0x12,
+	0x22, 0x0a, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x18,
+	0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x54,
+	0x69, 0x6d, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d, 0x70,
+	0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x53, 0x74, 0x61, 0x6d,
+	0x70, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x78, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x07, 0x74, 0x78, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x22, 0x0a, 0x0c, 0x74,
+	0x78, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28,
+	0x0c, 0x52, 0x0c, 0x74, 0x78, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12,
+	0x1e, 0x0a, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0c, 0x20,
+	0x01, 0x28, 0x04, 0x52, 0x0a, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12,
+	0x28, 0x0a, 0x0f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65,
+	0x6e, 0x74, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x43,
+	0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x78, 0x48,
+	0x61, 0x73, 0x68, 0x65, 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0c, 0x52, 0x08, 0x54, 0x78, 0x48,
+	0x61, 0x73, 0x68, 0x65, 0x73, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
+	0x63, 0x6f, 0x6d, 0x2f, 0x4e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x64, 0x45, 0x74,
+	0x68, 0x2f, 0x6a, 0x75, 0x6e, 0x6f, 0x2f, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f,
+	0x62, 0x6c, 0x6f, 0x63, 0x6b, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+}
+
+var (
+	file_block_proto_rawDescOnce sync.Once
+	file_block_proto_rawDescData = file_block_proto_rawDesc
+)
+
+func file_block_proto_rawDescGZIP() []byte {
+	file_block_proto_rawDescOnce.Do(func() {
+		file_block_proto_rawDescData = protoimpl.X.CompressGZIP(file_block_proto_rawDescData)
+	})
+	return file_block_proto_rawDescData
+}
+
+var file_block_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
+var file_block_proto_goTypes = []interface{}{
+	(*Block)(nil), // 0: Block
+}
+var file_block_proto_depIdxs = []int32{
+	0, // [0:0] is the sub-list for method output_type
+	0, // [0:0] is the sub-list for method input_type
+	0, // [0:0] is the sub-list for extension type_name
+	0, // [0:0] is the sub-list for extension extendee
+	0, // [0:0] is the sub-list for field type_name
+}
+
+func init() { file_block_proto_init() }
+func file_block_proto_init() {
+	if File_block_proto != nil {
+		return
+	}
+	if !protoimpl.UnsafeEnabled {
+		file_block_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
+			switch v := v.(*Block); i {
+			case 0:
+				return &v.state
+			case 1:
+				return &v.sizeCache
+			case 2:
+				return &v.unknownFields
+			default:
+				return nil
+			}
+		}
+	}
+	type x struct{}
+	out := protoimpl.TypeBuilder{
+		File: protoimpl.DescBuilder{
+			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
+			RawDescriptor: file_block_proto_rawDesc,
+			NumEnums:      0,
+			NumMessages:   1,
+			NumExtensions: 0,
+			NumServices:   0,
+		},
+		GoTypes:           file_block_proto_goTypes,
+		DependencyIndexes: file_block_proto_depIdxs,
+		MessageInfos:      file_block_proto_msgTypes,
+	}.Build()
+	File_block_proto = out.File
+	file_block_proto_rawDesc = nil
+	file_block_proto_goTypes = nil
+	file_block_proto_depIdxs = nil
+}
diff --git a/internal/db/block/block.proto b/internal/db/block/block.proto
new file mode 100644
index 00000000..70c173e3
--- /dev/null
+++ b/internal/db/block/block.proto
@@ -0,0 +1,20 @@
+syntax = "proto3";
+
+option go_package = "github.com/NethermindEth/juno/internal/block";
+
+message Block {
+  bytes hash = 1;
+  uint64 blockNumber = 2;
+  bytes parentBlockHash = 3;
+  string status = 4;
+  bytes sequencerAddress = 5;
+  bytes globalStateRoot = 6;
+  bytes oldRoot = 7;
+  int64 acceptedTime = 8;
+  int64 timeStamp = 9;
+  uint64 txCount = 10;
+  bytes txCommitment = 11;
+  uint64 eventCount = 12;
+  bytes eventCommitment = 13;
+  repeated bytes TxHashes = 14;
+}
\ No newline at end of file
diff --git a/internal/db/block/manager.go b/internal/db/block/manager.go
new file mode 100644
index 00000000..100f2b7a
--- /dev/null
+++ b/internal/db/block/manager.go
@@ -0,0 +1,48 @@
+package block
+
+import (
+	"github.com/NethermindEth/juno/internal/db"
+	"google.golang.org/protobuf/proto"
+)
+
+// Manager is a Block database manager to save and search the blocks.
+type Manager struct {
+	database db.Databaser
+}
+
+// NewManager returns a new Block manager using the given database.
+func NewManager(database db.Databaser) *Manager {
+	return &Manager{database: database}
+}
+
+// GetBlock search the block with the given block hash. If the block does not
+// exist then returns nil. If any error happens, then panic.
+func (manager *Manager) GetBlock(blockHash []byte) *Block {
+	rawResult, err := manager.database.Get(blockHash)
+	if err != nil {
+		panic(any(err))
+	}
+	block := &Block{}
+	err = proto.Unmarshal(rawResult, block)
+	if err != nil {
+		panic(any(err))
+	}
+	return block
+}
+
+// PutBlock saves the given block with the given hash as key. If any error happens
+// then panic.
+func (manager *Manager) PutBlock(blockHash []byte, block *Block) {
+	rawValue, err := proto.Marshal(block)
+	if err != nil {
+		panic(any(err))
+	}
+	err = manager.database.Put(blockHash, rawValue)
+	if err != nil {
+		panic(any(err))
+	}
+}
+
+func (manager *Manager) Close() {
+	manager.database.Close()
+}
diff --git a/internal/services/block.go b/internal/services/block.go
new file mode 100644
index 00000000..19d59497
--- /dev/null
+++ b/internal/services/block.go
@@ -0,0 +1,88 @@
+package services
+
+import (
+	"context"
+	"github.com/NethermindEth/juno/internal/config"
+	"github.com/NethermindEth/juno/internal/db"
+	"github.com/NethermindEth/juno/internal/db/block"
+	"github.com/NethermindEth/juno/internal/log"
+)
+
+// BlockService is a service to manage the block database. Before
+// using the service, it must be configured with the Setup method;
+// otherwise, the value will be the default. To stop the service, call the
+// Close method.
+var BlockService blockService
+
+type blockService struct {
+	service
+	manager *block.Manager
+}
+
+// Setup is used to configure the service before it's started. The database
+// param is the database where the transactions will be stored.
+func (s *blockService) Setup(database db.Databaser) {
+	if s.service.Running() {
+		// notest
+		s.logger.Panic("trying to Setup with service running")
+	}
+	s.manager = block.NewManager(database)
+}
+
+// Run starts the service. If the Setup method is not called before, the default
+// values are used.
+func (s *blockService) Run() error {
+	if s.logger == nil {
+		s.logger = log.Default.Named("Block Service")
+	}
+
+	if err := s.service.Run(); err != nil {
+		// notest
+		return err
+	}
+
+	s.setDefaults()
+	return nil
+}
+
+func (s *blockService) setDefaults() {
+	if s.manager == nil {
+		// notest
+		database := db.NewKeyValueDb(config.DataDir+"/block", 0)
+		s.manager = block.NewManager(database)
+	}
+}
+
+// Close stops the service, waiting to end the current operations, and closes
+// the database manager.
+func (s *blockService) Close(ctx context.Context) {
+	s.service.Close(ctx)
+	s.manager.Close()
+}
+
+// GetBlock searches for the block associated with the given block hash. If the
+// block does not exist on the database, then returns nil.
+func (s *blockService) GetBlock(blockHash []byte) *block.Block {
+	s.AddProcess()
+	defer s.DoneProcess()
+
+	s.logger.
+		With("blockHash", blockHash).
+		Debug("GetBlock")
+
+	return s.manager.GetBlock(blockHash)
+}
+
+// StoreBlock stores the given block into the database. The key used to map the
+// block it's the hash of the block. If the database already has a block with
+// the same key, then the value is overwritten.
+func (s *blockService) StoreBlock(blockHash []byte, block *block.Block) {
+	s.AddProcess()
+	defer s.DoneProcess()
+
+	s.logger.
+		With("blockHash", blockHash).
+		Debug("StoreBlock")
+
+	s.manager.PutBlock(blockHash, block)
+}


Test patch:
diff --git a/internal/db/block/block_test.go b/internal/db/block/block_test.go
new file mode 100644
index 00000000..c7fcb881
--- /dev/null
+++ b/internal/db/block/block_test.go
@@ -0,0 +1,67 @@
+package block
+
+import (
+	"bytes"
+	"encoding/hex"
+	"fmt"
+	"github.com/NethermindEth/juno/internal/db"
+	"google.golang.org/protobuf/proto"
+	"math/big"
+	"testing"
+)
+
+func TestManager_PutBlock(t *testing.T) {
+	blocks := []*Block{
+		{
+			Hash:             fromHexString("43950c9e3565cba1f2627b219d4863380f93a8548818ce26019d1bd5eebb0fb"),
+			BlockNumber:      2175,
+			ParentBlockHash:  fromHexString("f8fe26de3ce9ee4d543b1152deb2ce549e589524d79598227761d6006b74a9"),
+			Status:           "ACCEPTED_ON_L2",
+			SequencerAddress: fromHexString("0"),
+			GlobalStateRoot:  fromHexString("6a42d697b5b735eef03bb71841ed5099d57088f7b5eec8e356fe2601d5ba08f"),
+			OldRoot:          fromHexString("1d932dcf7da6c4f7605117cf514d953147161ab2d8f762dcebbb6dad427e519"),
+			AcceptedTime:     1652492749,
+			TimeStamp:        1652488132,
+			TxCount:          2,
+			TxCommitment:     fromHexString("0"),
+			EventCount:       19,
+			EventCommitment:  fromHexString("0"),
+			TxHashes: [][]byte{
+				fromHexString("5ce76214481ebb29f912cb5d31abdff34fd42217f5ece9dda76d9fcfd62dc73"),
+				fromHexString("4ff16b7673da1f4c4b114d28e0e1a366bd61b702eca3e21882da6c8939e60a2"),
+			},
+		},
+	}
+	manager := NewManager(db.NewKeyValueDb(t.TempDir(), 0))
+	for _, block := range blocks {
+		key := block.Hash
+		manager.PutBlock(key, block)
+		returnedBlock := manager.GetBlock(key)
+		if returnedBlock == nil {
+			t.Errorf("unexpected nil after search for block with hash %s", hex.EncodeToString(block.Hash))
+		}
+		if !equalData(t, block, returnedBlock) {
+			t.Errorf("block")
+		}
+	}
+}
+
+func equalData(t *testing.T, a, b *Block) bool {
+	aData, err := proto.Marshal(a)
+	if err != nil {
+		t.Errorf("marshal error: %s", err)
+	}
+	bData, err := proto.Marshal(b)
+	if err != nil {
+		t.Errorf("marshal error: %s", err)
+	}
+	return bytes.Compare(aData, bData) == 0
+}
+
+func fromHexString(s string) []byte {
+	number, ok := new(big.Int).SetString(s, 16)
+	if !ok {
+		panic(any(fmt.Errorf("error pasing hex-string: %s", s)))
+	}
+	return number.Bytes()
+}
diff --git a/internal/services/block_test.go b/internal/services/block_test.go
new file mode 100644
index 00000000..f81a8b18
--- /dev/null
+++ b/internal/services/block_test.go
@@ -0,0 +1,74 @@
+package services
+
+import (
+	"bytes"
+	"context"
+	"encoding/hex"
+	"fmt"
+	"github.com/NethermindEth/juno/internal/db"
+	"github.com/NethermindEth/juno/internal/db/block"
+	"google.golang.org/protobuf/proto"
+	"math/big"
+	"testing"
+)
+
+func TestService(t *testing.T) {
+	blocks := []*block.Block{
+		{
+			Hash:             fromHexString("43950c9e3565cba1f2627b219d4863380f93a8548818ce26019d1bd5eebb0fb"),
+			BlockNumber:      2175,
+			ParentBlockHash:  fromHexString("f8fe26de3ce9ee4d543b1152deb2ce549e589524d79598227761d6006b74a9"),
+			Status:           "ACCEPTED_ON_L2",
+			SequencerAddress: fromHexString("0"),
+			GlobalStateRoot:  fromHexString("6a42d697b5b735eef03bb71841ed5099d57088f7b5eec8e356fe2601d5ba08f"),
+			OldRoot:          fromHexString("1d932dcf7da6c4f7605117cf514d953147161ab2d8f762dcebbb6dad427e519"),
+			AcceptedTime:     1652492749,
+			TimeStamp:        1652488132,
+			TxCount:          2,
+			TxCommitment:     fromHexString("0"),
+			EventCount:       19,
+			EventCommitment:  fromHexString("0"),
+			TxHashes: [][]byte{
+				fromHexString("5ce76214481ebb29f912cb5d31abdff34fd42217f5ece9dda76d9fcfd62dc73"),
+				fromHexString("4ff16b7673da1f4c4b114d28e0e1a366bd61b702eca3e21882da6c8939e60a2"),
+			},
+		},
+	}
+	BlockService.Setup(db.NewKeyValueDb(t.TempDir(), 0))
+	err := BlockService.Run()
+	if err != nil {
+		t.Errorf("error starting the service: %s", err)
+	}
+	for _, b := range blocks {
+		key := b.Hash
+		BlockService.StoreBlock(key, b)
+		returnedBlock := BlockService.GetBlock(key)
+		if returnedBlock == nil {
+			t.Errorf("unexpected nil after search for block with hash %s", hex.EncodeToString(b.Hash))
+		}
+		if !equalData(t, b, returnedBlock) {
+			t.Errorf("b")
+		}
+	}
+	BlockService.Close(context.Background())
+}
+
+func equalData(t *testing.T, a, b *block.Block) bool {
+	aData, err := proto.Marshal(a)
+	if err != nil {
+		t.Errorf("marshal error: %s", err)
+	}
+	bData, err := proto.Marshal(b)
+	if err != nil {
+		t.Errorf("marshal error: %s", err)
+	}
+	return bytes.Compare(aData, bData) == 0
+}
+
+func fromHexString(s string) []byte {
+	number, ok := new(big.Int).SetString(s, 16)
+	if !ok {
+		panic(any(fmt.Errorf("error pasing hex-string: %s", s)))
+	}
+	return number.Bytes()
+}