/
statedb.go
640 lines (556 loc) · 19 KB
/
statedb.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
// Copyright Fuzamei Corp. 2018 All Rights Reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package state
import (
"fmt"
"strings"
"github.com/33cn/chain33/account"
"github.com/33cn/chain33/client"
"github.com/33cn/chain33/common/address"
"github.com/33cn/chain33/common/db"
"github.com/33cn/chain33/common/log/log15"
"github.com/33cn/chain33/types"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/common"
"github.com/33cn/plugin/plugin/dapp/evm/executor/vm/model"
evmtypes "github.com/33cn/plugin/plugin/dapp/evm/types"
)
// MemoryStateDB 内存状态数据库,保存在区块操作时内部的数据变更操作
// 本数据库不会直接写文件,只会暂存变更记录
// 在区块打包完成后,这里的缓存变更数据会被清空(通过区块打包分别写入blockchain和statedb数据库)
// 在交易执行过程中,本数据库会暂存并变更,在交易执行结束后,会返回变更的数据集,返回给blockchain
// 执行器的Exec阶段会返回:交易收据、合约账户(包含合约地址、合约代码、合约存储信息)
// 执行器的ExecLocal阶段会返回:合约创建人和合约的关联信息
type MemoryStateDB struct {
// StateDB 状态DB,从执行器框架传入
StateDB db.KV
// LocalDB 本地DB,从执行器框架传入
LocalDB db.KVDB
// CoinsAccount Coins账户操作对象,从执行器框架传入
CoinsAccount *account.DB
//evm 平台账户地址
evmPlatformAddr string
// 缓存账户对象
accounts map[string]*ContractAccount
// 合约执行过程中退回的资金
refund uint64
// 存储makeLogN指令对应的日志数据
logs map[common.Hash][]*model.ContractLog
logSize uint
// 版本号,用于标识数据变更版本
snapshots []*Snapshot
currentVer *Snapshot
versionID int
// 存储sha3指令对应的数据,仅用于debug日志
preimages map[common.Hash][]byte
// 当前临时交易哈希和交易序号
txHash common.Hash
txIndex int
// 当前区块高度
blockHeight int64
// 用户保存合约账户的状态数据或合约代码数据有没有发生变更
stateDirty map[string]interface{}
dataDirty map[string]interface{}
api client.QueueProtocolAPI
}
// NewMemoryStateDB 基于执行器框架的三个DB构建内存状态机对象
// 此对象的生命周期对应一个区块,在同一个区块内的多个交易执行时共享同一个DB对象
// 开始执行下一个区块时(执行器框架调用setEnv设置的区块高度发生变更时),会重新创建此DB对象
func NewMemoryStateDB(StateDB db.KV, LocalDB db.KVDB, CoinsAccount *account.DB, blockHeight int64, api client.QueueProtocolAPI) *MemoryStateDB {
mdb := &MemoryStateDB{
StateDB: StateDB,
LocalDB: LocalDB,
CoinsAccount: CoinsAccount,
evmPlatformAddr: address.GetExecAddress(api.GetConfig().ExecName("evm")).String(),
accounts: make(map[string]*ContractAccount),
logs: make(map[common.Hash][]*model.ContractLog),
logSize: 0,
preimages: make(map[common.Hash][]byte),
stateDirty: make(map[string]interface{}),
dataDirty: make(map[string]interface{}),
blockHeight: blockHeight,
refund: 0,
txIndex: 0,
api: api,
}
return mdb
}
// Prepare 每一个交易执行之前调用此方法,设置此交易的上下文信息
// 目前的上下文中包含交易哈希以及交易在区块中的序号
func (mdb *MemoryStateDB) Prepare(txHash common.Hash, txIndex int) {
mdb.txHash = txHash
mdb.txIndex = txIndex
log15.Info("MemoryStateDB::Prepare", "txHash", txHash.Hex(), "txIndex", txIndex, "logSize", mdb.logSize)
}
// CreateAccount 创建一个新的合约账户对象
func (mdb *MemoryStateDB) CreateAccount(addr, creator string, execName, alias string) {
acc := mdb.GetAccount(addr)
if acc == nil {
// 这种情况下为新增合约账户
acc := NewContractAccount(addr, mdb)
acc.SetCreator(creator)
acc.SetExecName(execName)
acc.SetAliasName(alias)
mdb.accounts[addr] = acc
mdb.addChange(createAccountChange{baseChange: baseChange{}, account: addr})
}
}
func (mdb *MemoryStateDB) addChange(entry DataChange) {
if mdb.currentVer != nil {
mdb.currentVer.append(entry)
}
}
// SubBalance 从外部账户地址扣钱(钱其实是打到合约账户中的)
func (mdb *MemoryStateDB) SubBalance(addr, caddr string, value uint64) {
res := mdb.Transfer(addr, caddr, value)
log15.Debug("transfer result", "from", addr, "to", caddr, "amount", value, "result", res)
}
// AddBalance 向外部账户地址打钱(钱其实是外部账户之前打到合约账户中的)
func (mdb *MemoryStateDB) AddBalance(addr, caddr string, value uint64) {
res := mdb.Transfer(caddr, addr, value)
log15.Debug("transfer result", "from", addr, "to", caddr, "amount", value, "result", res)
}
// GetBalance
func (mdb *MemoryStateDB) GetBalance(addr string) uint64 {
ac := mdb.CoinsAccount.LoadExecAccount(addr, mdb.evmPlatformAddr)
return uint64(ac.Balance)
}
// GetNonce 目前chain33中没有保留账户的nonce信息,这里临时添加到合约账户中;
// 所以,目前只有合约对象有nonce值
func (mdb *MemoryStateDB) GetNonce(addr string) uint64 {
acc := mdb.GetAccount(addr)
if acc != nil {
return acc.GetNonce()
}
return 0
}
// SetNonce 设置nonce值
func (mdb *MemoryStateDB) SetNonce(addr string, nonce uint64) {
acc := mdb.GetAccount(addr)
if acc != nil {
acc.SetNonce(nonce)
}
}
// GetCodeHash 获取代码哈希
func (mdb *MemoryStateDB) GetCodeHash(addr string) common.Hash {
acc := mdb.GetAccount(addr)
if acc != nil {
return common.BytesToHash(acc.Data.GetCodeHash())
}
return common.Hash{}
}
// GetCode 获取代码内容
func (mdb *MemoryStateDB) GetCode(addr string) []byte {
//if "15wDXJKYxTq3FvfL5uK4MCZXdQfcSTGUtt" == addr {
// panic("MemoryStateDB::debugCall::GetCode")
//}
log15.Debug("MemoryStateDB::debugCall::GetCode", "addr", addr)
acc := mdb.GetAccount(addr)
if acc != nil {
return acc.Data.GetCode()
}
return nil
}
// SetCode 设置代码内容
func (mdb *MemoryStateDB) SetCode(addr string, code []byte) {
log15.Debug("MemoryStateDB::debugCall::SetCode", "addr", addr)
acc := mdb.GetAccount(addr)
if acc != nil {
mdb.dataDirty[addr] = true
acc.SetCode(code)
}
}
// SetAbi 设置ABI内容
func (mdb *MemoryStateDB) SetAbi(addr, abi string) {
acc := mdb.GetAccount(addr)
if acc != nil {
mdb.dataDirty[addr] = true
acc.SetAbi(abi)
}
}
// GetAbi 获取ABI
func (mdb *MemoryStateDB) GetAbi(addr string) string {
acc := mdb.GetAccount(addr)
if acc != nil {
return acc.Data.GetAbi()
}
return ""
}
// GetCodeSize 获取合约代码自身的大小
// 对应 EXTCODESIZE 操作码
func (mdb *MemoryStateDB) GetCodeSize(addr string) int {
code := mdb.GetCode(addr)
if code != nil {
return len(code)
}
return 0
}
// AddRefund 合约自杀或SSTORE指令时,返还Gas
func (mdb *MemoryStateDB) AddRefund(gas uint64) {
mdb.addChange(refundChange{baseChange: baseChange{}, prev: mdb.refund})
mdb.refund += gas
}
// GetRefund 获取奖励
func (mdb *MemoryStateDB) GetRefund() uint64 {
return mdb.refund
}
// GetAccount 从缓存中获取或加载合约账户
func (mdb *MemoryStateDB) GetAccount(addr string) *ContractAccount {
if acc, ok := mdb.accounts[addr]; ok {
return acc
}
// 需要加载合约对象,根据是否存在合约代码来判断是否有合约对象
contract := NewContractAccount(addr, mdb)
contract.LoadContract(mdb.StateDB)
if contract.Empty() {
return nil
}
mdb.accounts[addr] = contract
return contract
}
// GetState SLOAD 指令加载合约状态数据
func (mdb *MemoryStateDB) GetState(addr string, key common.Hash) common.Hash {
// 先从合约缓存中获取
acc := mdb.GetAccount(addr)
if acc != nil {
return acc.GetState(key)
}
return common.Hash{}
}
// SetState SSTORE 指令修改合约状态数据
func (mdb *MemoryStateDB) SetState(addr string, key common.Hash, value common.Hash) {
acc := mdb.GetAccount(addr)
if acc != nil {
acc.SetState(key, value)
// 新的分叉中状态数据变更不需要单独进行标识
cfg := mdb.api.GetConfig()
if !cfg.IsDappFork(mdb.blockHeight, "evm", evmtypes.ForkEVMState) {
mdb.stateDirty[addr] = true
}
}
}
// TransferStateData 转换合约状态数据存储
func (mdb *MemoryStateDB) TransferStateData(addr string) {
acc := mdb.GetAccount(addr)
if acc != nil {
acc.TransferState()
}
}
// UpdateState 表示合约地址的状态数据发生了变更,需要进行更新
func (mdb *MemoryStateDB) UpdateState(addr string) {
mdb.stateDirty[addr] = true
}
// Suicide SELFDESTRUCT 合约对象自杀
// 合约自杀后,合约对象依然存在,只是无法被调用,也无法恢复
func (mdb *MemoryStateDB) Suicide(addr string) bool {
acc := mdb.GetAccount(addr)
if acc != nil {
mdb.addChange(suicideChange{
baseChange: baseChange{},
account: addr,
prev: acc.State.GetSuicided(),
})
mdb.stateDirty[addr] = true
return acc.Suicide()
}
return false
}
// HasSuicided 判断此合约对象是否已经自杀
// 自杀的合约对象是不允许调用的
func (mdb *MemoryStateDB) HasSuicided(addr string) bool {
acc := mdb.GetAccount(addr)
if acc != nil {
return acc.HasSuicided()
}
return false
}
// Exist 判断合约对象是否存在
func (mdb *MemoryStateDB) Exist(addr string) bool {
return mdb.GetAccount(addr) != nil
}
// Empty 判断合约对象是否为空
func (mdb *MemoryStateDB) Empty(addr string) bool {
acc := mdb.GetAccount(addr)
// 如果包含合约代码,则不为空
if acc != nil && !acc.Empty() {
return false
}
// 账户有余额,也不为空
if mdb.GetBalance(addr) != 0 {
return false
}
return true
}
// RevertToSnapshot 将数据状态回滚到指定快照版本(中间的版本数据将会被删除)
func (mdb *MemoryStateDB) RevertToSnapshot(version int) {
if version >= len(mdb.snapshots) {
return
}
ver := mdb.snapshots[version]
// 如果版本号不对,回滚失败
if ver == nil || ver.id != version {
log15.Crit(fmt.Errorf("Snapshot id %v cannot be reverted", version).Error())
return
}
// 从最近版本开始回滚
for index := len(mdb.snapshots) - 1; index >= version; index-- {
mdb.snapshots[index].revert()
}
// 只保留回滚版本之前的版本数据
mdb.snapshots = mdb.snapshots[:version]
mdb.versionID = version
if version == 0 {
mdb.currentVer = nil
} else {
mdb.currentVer = mdb.snapshots[version-1]
}
}
// Snapshot 对当前的数据状态打快照,并生成快照版本号,方便后面回滚数据
func (mdb *MemoryStateDB) Snapshot() int {
id := mdb.versionID
mdb.versionID++
mdb.currentVer = &Snapshot{id: id, statedb: mdb}
mdb.snapshots = append(mdb.snapshots, mdb.currentVer)
log15.Debug("MemoryStateDB::Snapshot", "mdb.versionID", mdb.versionID)
return id
}
// GetLastSnapshot 获取最后一次成功的快照版本号
func (mdb *MemoryStateDB) GetLastSnapshot() *Snapshot {
if mdb.versionID == 0 {
return nil
}
return mdb.snapshots[mdb.versionID-1]
}
// GetReceiptLogs 获取合约对象的变更日志
func (mdb *MemoryStateDB) GetReceiptLogs(addr string) (logs []*types.ReceiptLog) {
acc := mdb.GetAccount(addr)
if acc != nil {
if mdb.stateDirty[addr] != nil {
stateLog := acc.BuildStateLog()
if stateLog != nil {
logs = append(logs, stateLog)
}
}
if mdb.dataDirty[addr] != nil {
logs = append(logs, acc.BuildDataLog())
}
return
}
return
}
// GetChangedData 获取本次操作所引起的状态数据变更
// 因为目前执行器每次执行都是一个新的MemoryStateDB,所以,所有的快照都是从0开始的,
// 这里获取的应该是从0到目前快照的所有变更;
// 另外,因为合约内部会调用其它合约,也会产生数据变更,所以这里返回的数据,不止是一个合约的数据。
func (mdb *MemoryStateDB) GetChangedData(version int) (kvSet []*types.KeyValue, logs []*types.ReceiptLog) {
if version < 0 || version >= len(mdb.snapshots) {
return
}
for _, snapshot := range mdb.snapshots {
kv, log := snapshot.getData()
if kv != nil {
kvSet = append(kvSet, kv...)
}
if log != nil {
logs = append(logs, log...)
}
}
return
}
// CanTransfer 借助coins执行器进行转账相关操作
func (mdb *MemoryStateDB) CanTransfer(sender string, amount uint64) bool {
senderAcc := mdb.CoinsAccount.LoadExecAccount(sender, mdb.evmPlatformAddr)
log15.Info("CanTransfer", "balance", senderAcc.Balance, "sender", sender, "evmPlatformAddr", mdb.evmPlatformAddr,
"mdb.CoinsAccount", mdb.CoinsAccount)
return senderAcc.Balance >= int64(amount)
}
// TransferType 定义转账类型
type TransferType int
const (
_ TransferType = iota
// NoNeed 无需转账
NoNeed
// ToExec 向合约转账
ToExec
// FromExec 从合约转入
FromExec
// Error 处理出错
Error
)
// Transfer 借助coins执行器进行转账相关操作
func (mdb *MemoryStateDB) Transfer(sender, recipient string, amount uint64) bool {
log15.Debug("transfer from contract to external(contract)", "sender", sender, "recipient", recipient, "amount", amount)
var (
ret *types.Receipt
err error
)
value := int64(amount)
if value < 0 {
return false
}
if 0 == value {
return true
}
ret, err = mdb.CoinsAccount.ExecTransfer(sender, recipient, mdb.evmPlatformAddr, int64(amount))
// 这种情况下转账失败并不进行处理,也不会从sender账户扣款,打印日志即可
if err != nil {
log15.Error("transfer error", "sender", sender, "recipient", recipient, "amount", amount, "err info", err)
return false
}
if ret != nil {
mdb.addChange(transferChange{
baseChange: baseChange{},
amount: value,
data: ret.KV,
logs: ret.Logs,
})
}
log15.Info("transfer successful", "balance", mdb.CoinsAccount.LoadExecAccount(recipient, mdb.evmPlatformAddr).Balance,
"mdb.CoinsAccount", mdb.CoinsAccount)
return true
}
// 因为chain33的限制,在执行器中转账只能在以下几个方向进行:
// A账户的X合约 <-> B账户的X合约;
// 其它情况不支持,所以要想实现EVM合约与账户之间的转账需要经过中转处理,比如A要向B创建的X合约转账,则执行以下流程:
// A -> A:X -> B:X; (其中第一步需要外部手工执行)
// 本方法封装第二步转账逻辑;
func (mdb *MemoryStateDB) transfer2Contract(sender, recipient string, amount int64) (ret *types.Receipt, err error) {
// 首先获取合约的创建者信息
contract := mdb.GetAccount(recipient)
if contract == nil {
return nil, model.ErrAddrNotExists
}
creator := contract.GetCreator()
if len(creator) == 0 {
return nil, model.ErrNoCreator
}
execAddr := recipient
ret = &types.Receipt{}
cfg := mdb.api.GetConfig()
if cfg.IsDappFork(mdb.GetBlockHeight(), "evm", evmtypes.ForkEVMFrozen) {
// 用户向合约转账时,将钱转到合约地址下execAddr:execAddr
rs, err := mdb.CoinsAccount.ExecTransfer(sender, execAddr, execAddr, amount)
if err != nil {
return nil, err
}
ret.KV = append(ret.KV, rs.KV...)
ret.Logs = append(ret.Logs, rs.Logs...)
} else {
if strings.Compare(sender, creator) != 0 {
// 用户向合约转账时,首先将钱转到创建者合约地址下
rs, err := mdb.CoinsAccount.ExecTransfer(sender, creator, execAddr, amount)
if err != nil {
return nil, err
}
ret.KV = append(ret.KV, rs.KV...)
ret.Logs = append(ret.Logs, rs.Logs...)
}
}
return ret, nil
}
// chain33转账限制请参考方法 Transfer2Contract ;
// 本方法封装从合约账户到外部账户的转账逻辑;
func (mdb *MemoryStateDB) transfer2External(sender, recipient string, amount int64) (ret *types.Receipt, err error) {
// 首先获取合约的创建者信息
contract := mdb.GetAccount(sender)
if contract == nil {
return nil, model.ErrAddrNotExists
}
creator := contract.GetCreator()
if len(creator) == 0 {
return nil, model.ErrNoCreator
}
execAddr := sender
cfg := mdb.api.GetConfig()
if cfg.IsDappFork(mdb.GetBlockHeight(), "evm", evmtypes.ForkEVMFrozen) {
// 合约向用户地址转账时,从合约地址下的钱中转出到用户合约地址
ret, err = mdb.CoinsAccount.ExecTransfer(execAddr, recipient, execAddr, amount)
if err != nil {
return nil, err
}
} else {
// 第一步先从创建者的合约账户到接受者的合约账户
// 如果是自己调用自己创建的合约,这一步也可以省略
if strings.Compare(creator, recipient) != 0 {
ret, err = mdb.CoinsAccount.ExecTransfer(creator, recipient, execAddr, amount)
if err != nil {
return nil, err
}
}
}
return ret, nil
}
func (mdb *MemoryStateDB) mergeResult(one, two *types.Receipt) (ret *types.Receipt) {
ret = one
if ret == nil {
ret = two
} else if two != nil {
ret.KV = append(ret.KV, two.KV...)
ret.Logs = append(ret.Logs, two.Logs...)
}
return
}
// AddLog LOG0-4 指令对应的具体操作
// 生成对应的日志信息,目前这些生成的日志信息会在合约执行后打印到日志文件中
func (mdb *MemoryStateDB) AddLog(log *model.ContractLog) {
newEvmLog := &types.EVMLog{
Topic: [][]byte{log.Topics[0].Bytes()},
Data: log.Data,
}
if len(log.Topics) > 0 {
for i := 1; i < len(log.Topics); i++ {
newEvmLog.Topic = append(newEvmLog.Topic, log.Topics[i].Bytes())
}
}
receiptLog := &types.ReceiptLog{
Ty: evmtypes.TyLogEVMEventData,
Log: types.Encode(newEvmLog),
}
mdb.addChange(addLogChange{
txhash: mdb.txHash,
logs: []*types.ReceiptLog{receiptLog}})
log.TxHash = mdb.txHash
log.Index = int(mdb.logSize)
mdb.logs[mdb.txHash] = append(mdb.logs[mdb.txHash], log)
mdb.logSize++
log15.Info("MemoryStateDB::AddLog", "txhash", mdb.txHash.Hex(), "blockHeight", mdb.blockHeight, "txIndex", mdb.txIndex,
"mdb.logSize", mdb.logSize, "topic", log.Topics[0].Hex())
}
// AddPreimage 存储sha3指令对应的数据
func (mdb *MemoryStateDB) AddPreimage(hash common.Hash, data []byte) {
// 目前只用于打印日志
if _, ok := mdb.preimages[hash]; !ok {
mdb.addChange(addPreimageChange{hash: hash})
pi := make([]byte, len(data))
copy(pi, data)
mdb.preimages[hash] = pi
}
}
// PrintLogs 本合约执行完毕之后打印合约生成的日志(如果有)
// 这里不保证当前区块可以打包成功,只是在执行区块中的交易时,如果交易执行成功,就会打印合约日志
func (mdb *MemoryStateDB) PrintLogs() {
items := mdb.logs[mdb.txHash]
log15.Debug("PrintLogs", "item number:", len(items), "txhash", mdb.txHash.Hex())
for _, item := range items {
item.PrintLog()
}
}
// WritePreimages 打印本区块内生成的preimages日志
func (mdb *MemoryStateDB) WritePreimages(number int64) {
for k, v := range mdb.preimages {
log15.Debug("Contract preimages ", "key:", k.Str(), "value:", common.Bytes2Hex(v), "block height:", number)
}
}
// ResetDatas 测试用,清空版本数据
func (mdb *MemoryStateDB) ResetDatas() {
mdb.currentVer = nil
mdb.snapshots = mdb.snapshots[:0]
}
// GetBlockHeight 返回当前区块高度
func (mdb *MemoryStateDB) GetBlockHeight() int64 {
return mdb.blockHeight
}
// GetConfig 获取系统配置
func (mdb *MemoryStateDB) GetConfig() *types.Chain33Config {
return mdb.api.GetConfig()
}