cranberry

Форк
0
/
block_service.go 
192 строки · 5.4 Кб
1
package services
2

3
import (
4
	"database/sql"
5

6
	"go.uber.org/zap"
7

8
	"gitverse.ru/IvanTimofeev/cranberry/internal/db"
9
	"gitverse.ru/IvanTimofeev/cranberry/internal/errors"
10
	"gitverse.ru/IvanTimofeev/cranberry/internal/log"
11
	"gitverse.ru/IvanTimofeev/cranberry/internal/merkle"
12
	pbapi "gitverse.ru/IvanTimofeev/cranberry/pkg/grpc"
13
	utility "gitverse.ru/IvanTimofeev/cranberry/pkg/utility"
14
)
15

16
const LAST_BLOCK_HEIGHT_PARAM_NAME = "last_block_height"
17
const BLOCK_TX_COUNT = 1000
18

19
type BlockService struct {
20
	poolService      *PoolService
21
	txService        *TxService
22
	db               *db.Db
23
	logger           *zap.SugaredLogger
24
	validatorService *ValidatorService
25
}
26

27
func NewBlockService(poolService *PoolService, db *db.Db,
28
	txService *TxService, validatorService *ValidatorService) *BlockService {
29
	return &BlockService{
30
		poolService:      poolService,
31
		txService:        txService,
32
		validatorService: validatorService,
33
		db:               db,
34
		logger:           log.GetLogger(),
35
	}
36
}
37

38
func (s *BlockService) MakeGenesisBlock(addr string, balance uint64) error {
39
	_, ok, err := s.db.GetUint64Param(LAST_BLOCK_HEIGHT_PARAM_NAME)
40
	if err != nil {
41
		return err
42
	}
43
	if !ok {
44
		txs := make([]*pbapi.TxContainer, 0, BLOCK_TX_COUNT)
45
		genesisBlockHeader := &pbapi.BlockHeader{
46
			MerkleRoot: merkle.MerkleRoot(txs),
47
			PrevHash:   "",
48
			Height:     0,
49
		}
50
		genesisBlockContainer := &pbapi.BlockContainer{
51
			Hash:                utility.BlockHeaderToHash(genesisBlockHeader),
52
			Header:              genesisBlockHeader,
53
			Txs:                 txs,
54
			ValidatorSignatures: []*pbapi.SignatureItem{},
55
		}
56
		err := s.db.RunTransaction(func(dbtx *sql.Tx) error {
57
			pubKeyBytes := utility.PubKeyToBytes(&s.validatorService.GetPrivKey().PublicKey)
58
			validator := &pbapi.Validator{
59
				Addr:   s.validatorService.GetValidatorAddr(),
60
				PubKey: pubKeyBytes,
61
			}
62
			return s.db.SaveValidator(validator, dbtx)
63
		})()
64
		if err != nil {
65
			return err
66
		}
67
		err = s.db.RunTransaction(func(dbtx *sql.Tx) error {
68
			err := s.db.SaveBlock(genesisBlockContainer, dbtx)
69
			if err != nil {
70
				return err
71
			}
72
			err = s.db.SaveUint64Param(LAST_BLOCK_HEIGHT_PARAM_NAME, 0, dbtx)
73
			if err != nil {
74
				return err
75
			}
76
			err = s.db.SaveAccount(&pbapi.Account{
77
				Addr:    addr,
78
				Balance: balance,
79
			}, dbtx)
80
			if err != nil {
81
				return err
82
			}
83
			return nil
84
		})()
85
		if err != nil {
86
			return err
87
		}
88
	}
89
	return nil
90
}
91

92
func (s *BlockService) MakeBlock() error {
93
	lastBlockHeight, ok, err := s.db.GetUint64Param(LAST_BLOCK_HEIGHT_PARAM_NAME)
94
	if err != nil {
95
		return err
96
	}
97
	if ok {
98
		//собираем транзакции для формирования блока
99
		txcs := make([]*pbapi.TxContainer, 0, BLOCK_TX_COUNT)
100
		for i := uint64(0); i < BLOCK_TX_COUNT; i++ {
101
			if txc, ok := s.poolService.memorypool.ExtractTx(); ok {
102
				txc.OrderInBlock = &i
103
				txcs = append(txcs, txc)
104
			}
105
		}
106
		s.logger.Infof("Count of txs = %d", len(txcs))
107
		//запрашиваем последний блок
108
		lastBlockContainer, _, err := s.db.GetBlockByHeight(lastBlockHeight)
109
		if err != nil {
110
			return err
111
		}
112
		newBlockHeader := &pbapi.BlockHeader{
113
			MerkleRoot: merkle.MerkleRoot(txcs),
114
			PrevHash:   lastBlockContainer.Hash,
115
			Height:     lastBlockHeight + 1,
116
		}
117
		newBlockContainer := &pbapi.BlockContainer{
118
			Hash:                utility.BlockHeaderToHash(newBlockHeader),
119
			Header:              newBlockHeader,
120
			Txs:                 txcs,
121
			ValidatorSignatures: []*pbapi.SignatureItem{},
122
		}
123
		signature, err := utility.SignBlock(s.validatorService.GetPrivKey(), newBlockHeader)
124
		if err != nil {
125
			return err
126
		}
127
		newBlockContainer.ValidatorSignatures = append(newBlockContainer.ValidatorSignatures,
128
			&pbapi.SignatureItem{
129
				Addr:      s.validatorService.GetValidatorAddr(),
130
				Signature: signature,
131
			})
132
		// валидируем блок
133
		verified, err := s.validatorService.ValidateBlock(newBlockContainer)
134
		if err != nil {
135
			return err
136
		}
137
		if !verified {
138
			return errors.BlockInvaliderror(newBlockContainer.Hash)
139
		}
140
		//сохраняем блок, высоту и публичный ключ подписанта
141
		err = s.db.RunTransaction(func(dbtx *sql.Tx) error {
142
			err := s.db.SaveBlock(newBlockContainer, dbtx)
143
			if err != nil {
144
				return err
145
			}
146
			err = s.db.SaveUint64Param(LAST_BLOCK_HEIGHT_PARAM_NAME, newBlockHeader.Height, dbtx)
147
			if err != nil {
148
				return err
149
			}
150
			for _, txc := range txcs {
151
				// исполняем транзакцию
152
				err := s.txService.ExecuteTx(txc, newBlockContainer, dbtx)
153
				if err != nil {
154
					return err
155
				}
156
			}
157
			return nil
158
		})()
159
		if err != nil {
160
			return err
161
		}
162
	}
163
	return nil
164
}
165

166
func (s *BlockService) GetBlockByHeight(height uint64) (*pbapi.BlockContainer, error) {
167
	blockConatiner, ok, err := s.db.GetBlockByHeight(height)
168
	if err != nil {
169
		return nil, err
170
	}
171
	if !ok {
172
		return nil, nil
173
	}
174
	return blockConatiner, nil
175
}
176

177
func (s *BlockService) GetBlockWithTxsByHeight(height uint64) (*pbapi.BlockContainer, error) {
178
	blockConatiner, err := s.GetBlockByHeight(height)
179
	if err != nil {
180
		return nil, err
181
	}
182
	txcs, err := s.db.GetAllTxsByBlockHeight(height)
183
	if err != nil {
184
		return nil, err
185
	}
186
	blockConatiner.Txs = txcs
187
	return blockConatiner, nil
188
}
189

190
func (s BlockService) GetLastBlock() (*pbapi.BlockContainer, error) {
191
	return nil, nil
192
}
193

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.