一、 账本数据库概述
1. 背景信息
账本数据库融合了区块链思想,将用户操作记录至两种历史表中:
用户历史表
全局区块表
当用户创建防篡改用户表时,系统将自动为该表添加一个hash列来保存每行数据的hash摘要信息,同时在blockchain模式下会创建一张用户历史表来记录对应用户表中每条数据的变更行为;而用户对防篡改用户表的一次修改行为将记录至全局区块表中。由于历史表具有只可追加不可修改的特点,因此历史表记录串联起来便形成了用户对防篡改用户表的修改历史。
用户历史表命名和结构如下:
表 1 用户历史表blockchain.__hist所包含的字段
字段名 | 类型 | 描述 |
rec_num | bigint | 行级修改操作在历史表中的执行序号。 |
hash_ins | hash16 | INSERT或UPDATE操作插入的数据行的hash值。 |
hash_del | hash16 | DELETE或UPDATE操作删除的数据行的hash值。 |
pre_hash | hash32 | 当前用户历史表的数据整体摘要。 |
表 2 hash_ins与hash_del场景对应关系
- | hash_ins | hash_del |
INSERT | (√) 插入行的hash值 | |
DELETE | (√) 删除行的hash值。 | |
UPDATE | (√) 新插入数据的hash值 | (√) 删除前该行的hash值。 |
2. 操作步骤
(1) 创建防篡改模式。
例如,创建防篡改模式ledgernsp。
```sql MogDB=CREATE SCHEMA ledgernsp WITH BLOCKCHAIN; ```
2. 在防篡改模式下创建防篡改用户表。
例如,创建防篡改用户表ledgernsp.usertable。
```sql MogDB=CREATE TABLE ledgernsp.usertable(id int, name text); ```
查看防篡改用户表结构及其对应的用户历史表结构。
```sql MogDB=\d+ ledgernsp.usertable; MogDB=\d+ blockchain.ledgernsp_usertable_hist; ```
执行结果如下:
```sql MogDB=\d+ ledgernsp.usertable; Table "ledgernsp.usertable" Column | Type | Modifiers | Storage | Stats target | Description --------+---------+-----------+----------+--------------+------------- id | integer | | plain | | name | text | | extended | | hash | hash16 | | plain | | Has OIDs: no Distribute By: HASH(id) Location Nodes: ALL DATANODES Options: orientation=row, compression=no History table name: ledgernsp_usertable_hist MogDB=\d+ blockchain.ledgernsp_usertable_hist; Table "blockchain.ledgernsp_usertable_hist" Column | Type | Modifiers | Storage | Stats target | Description ----------+--------+-----------+---------+--------------+------------- rec_num | bigint | | plain | | hash_ins | hash16 | | plain | | hash_del | hash16 | | plain | | pre_hash | hash32 | | plain | | Indexes: "gs_hist_16388_index" PRIMARY KEY, btree (rec_num int4_ops) TABLESPACE pg_default Has OIDs: no Options: internal_mask=263 ```
说明:
防篡改表不支持非行存表、临时表、外表、unlog表、非行存表均无防篡改属性。
防篡改表在创建时会自动增加一个名为hash的系统列,所以防篡改表单表最大列数为1599。
3. 修改防篡改用户表数据。
例如,对防篡改用户表执行INSERT/UPDATE/DELETE。
```sql MogDB=INSERT INTO ledgernsp.usertable VALUES(1, 'alex'), (2, 'bob'), (3, 'peter'); INSERT 0 3 MogDB=SELECT *, hash FROM ledgernsp.usertable ORDER BY id; id | name | hash ----+-------+------------------ 1 | alex | 1f2e543c580cb8c5 2 | bob | 8fcd74a8a6a4b484 3 | peter | f51b4b1b12d0354b (3 rows) MogDB=UPDATE ledgernsp.usertable SET name = 'bob2' WHERE id = 2; UPDATE 1 MogDB=SELECT *, hash FROM ledgernsp.usertable ORDER BY id; id | name | hash ----+-------+------------------ 1 | alex | 1f2e543c580cb8c5 2 | bob2 | 437761affbb7c605 3 | peter | f51b4b1b12d0354b (3 rows) MogDB=DELETE FROM ledgernsp.usertable WHERE id = 3; DELETE 1 MogDB=SELECT *, hash FROM ledgernsp.usertable ORDER BY id; id | name | hash ----+------+------------------ 1 | alex | 1f2e543c580cb8c5 2 | bob2 | 437761affbb7c605 (2 rows) ```
二、查看账本历史操作记录
1. 前提条件
系统中需要有审计管理员或者具有审计管理员权限的角色。
数据库正常运行,并且对防篡改数据库执行了一系列增、删、改等操作,保证在查询时段内有账本操作记录结果产生。
2. 背景信息
只有拥有AUDITADMIN属性的用户才可以查看账本历史操作记录。有关数据库用户及创建用户的办法请参见[管理用户及权限](https://docs.mogdb.io/zh/mogdb/v3.0/2-managing-users-and-their-permissions)。
查询全局区块表命令是直接查询gs_global_chain表,操作为:
```sql SELECT * FROM gs_global_chain; ```
该表有11个字段,每个字段的含义见章节[GS_GLOBAL_CHAIN](https://docs.mogdb.io/zh/mogdb/v3.0/GS_GLOBAL_CHAIN)。
查询用户历史表的命令是直接查询BLOCKCHAIN模式下的用户历史表,操作为:
例如用户表所在的模式为ledgernsp,表名为usertable,则对应的用户历史表名为blockchain.ledgernsp_usertable_hist;
```sql SELECT * FROM blockchain.ledgernsp_usertable_hist; ```
用户历史表有4个字段,每个字段的含义见[表1](https://docs.mogdb.io/zh/mogdb/v3.0/5-setting-a-ledger-databasetable1)。
说明: 用户历史表的表名一般为blockchain.hist形式。当防篡改用户表模式名或者表名过长导致前述方式生成的表名超出表名长度限制,则会采用blockchain.hist的方式命名。
3. 操作步骤
以操作系统用户omm登录数据库主节点。
使用如下命令连接数据库。
```sql gsql -d postgres -p 8000 ```
postgres为需要连接的数据库名称,8000为端口号。
4. 查询全局区块表记录。
```sql MogDB=SELECT * FROM gs_global_chain; blocknum | dbname | username | starttime | relid | relnsp | relname | relhash | globalhash | txcommand ----------+----------+----------+-------------------------------+-------+-----------+-----------+------------------+----------------------------------+------------------ ------------------------------------------------------------ 0 | postgres | omm | 2021-04-14 07:00:46.32757+08 | 16393 | ledgernsp | usertable | a41714001181a294 | 6b5624e039e8aee36bff3e8295c75b40 | insert into ledge rnsp.usertable values(1, 'alex'), (2, 'bob'), (3, 'peter'); 1 | postgres | omm | 2021-04-14 07:01:19.767799+08 | 16393 | ledgernsp | usertable | b3a9ed0755131181 | 328b48c4370faed930937869783c23e0 | update ledgernsp. usertable set name = 'bob2' where id = 2; 2 | postgres | omm | 2021-04-14 07:01:29.896148+08 | 16393 | ledgernsp | usertable | 0ae4b4e4ed2fcab5 | aa8f0a236357cac4e5bc1648a739f2ef | delete from ledge rnsp.usertable where id = 3; ```
该结果表明,用户omm连续执行了三条DML命令,包括INSERT、UPDATE和DELETE操作。
5. 查询历史表记录。
```sql MogDB=SELECT * FROM blockchain.ledgernsp_usertable_hist; rec_num | hash_ins | hash_del | pre_hash ---------+------------------+------------------+---------------------------------- 0 | 1f2e543c580cb8c5 | | e1b664970d925d09caa295abd38d9b35 1 | 8fcd74a8a6a4b484 | | dad3ed8939a141bf3682043891776b67 2 | f51b4b1b12d0354b | | 53eb887fc7c4302402343c8914e43c69 3 | 437761affbb7c605 | 8fcd74a8a6a4b484 | c2868c5b49550801d0dbbbaa77a83a10 4 | | f51b4b1b12d0354b | 9c512619f6ffef38c098477933499fe3 (5 rows) ```
查询结果显示,用户omm对ledgernsp.usertable表插入了3条数据,更新了1条数据,随后删除了1行数据,最后剩余2行数据,hash值分别为1f2e543c580cb8c5和437761affbb7c605。
6. 查询用户表数据及hash校验列。
```sql MogDB=SELECT *, hash FROM ledgernsp.usertable; id | name | hash ----+------+------------------ 1 | alex | 1f2e543c580cb8c5 2 | bob2 | 437761affbb7c605 (2 rows) ```
查询结果显示,用户表中剩余2条数据,与步骤4中的记录一致。
三、校验账本数据一致性
1. 前提条件
数据库正常运行,并且对防篡改数据库执行了一系列增、删、改等操作,保证在查询时段内有账本操作记录结果产生。
2. 背景信息
账本数据库校验功能目前提供两种校验接口,分别为:]ledger_hist_check(text, text)](https://docs.mogdb.io/zh/mogdb/v3.0/20.1-ledger-database-functions)和[ledger_gchain_check(text, text)](https://docs.mogdb.io/zh/mogdb/v3.0/20.1-ledger-database-functions)。普通用户调用校验接口,仅能校验自己有权限访问的表。
校验防篡改用户表和用户历史表的接口为pg_catalog.ledger_hist_check,操作为:
```sql SELECT pg_catalog.ledger_hist_check(schema_name text,table_name text); ```
如果校验通过,函数返回t,反之则返回f。
校验防篡改用户表、用户历史表和全局区块表三者是否一致的接口为pg_catalog.ledger_gchain_check,操作为:
```sql SELECT pg_catalog.ledger_gchain_check(schema_name text, table_name text); ```
如果校验通过,函数返回t,反之则返回f。
3. 操作步骤
校验防篡改用户表ledgernsp.usertable与其对应的历史表是否一致。
```sql MogDB=SELECT pg_catalog.ledger_hist_check('ledgernsp', 'usertable'); ledger_hist_check ------------------- t (1 row) ```
该结果表明防篡改用户表和用户历史表中记录的结果能够一一对应,保持一致。
查询防篡改用户表ledgernsp.usertable与其对应的历史表以及全局区块表中关于该表的记录是否一致。
```sql MogDB= SELECT pg_catalog.ledger_gchain_check('ledgernsp', 'usertable'); ledger_gchain_check --------------------- t (1 row) ```
查询结果显示,上述三表中关于ledgernsp.usertable的记录保持一致,未发生篡改行为。
四、归档账本数据库
1. 前提条件
系统中需要有审计管理员或者具有审计管理员权限的角色。
数据库正常运行,并且对防篡改数据库执行了一系列增、删、改等操作,保证在查询时段内有账本操作记录结果产生。
数据库已经正确配置审计文件的存储路径audit_directory。
2. 背景信息
账本数据库归档功能目前提供两种校验接口,分别为:[ledger_hist_archive(text, text)](https://docs.mogdb.io/zh/mogdb/v3.0/20.1-ledger-database-functions)和[ledger_gchain_archive(void)](https://docs.mogdb.io/zh/mogdb/v3.0/20.1-ledger-database-functions)。账本数据库接口仅审计管理员可以调用。
归档用户历史表的接口为pg_catalog.ledger_hist_archive,操作为:
```sql SELECT pg_catalog.ledger_hist_archive(schema_name text,table_name text); ```
如果归档成功,函数返回t,反之则返回f。
归档全局区块表的接口为pg_catalog.ledger_gchain_archive,操作为:
```sql SELECT pg_catalog.ledger_gchain_archive(); ```
如果归档成功,函数返回t,反之则返回f。
3. 操作步骤
对指定用户历史表进行归档操作。
```sql MogDB=SELECT pg_catalog.ledger_hist_archive('ledgernsp', 'usertable') ledger_hist_archive --------------------- t (1 row) ```
用户历史表将归档为一条数据:
```sql MogDB=SELECT * FROM blockchain.ledgernsp_usertable_hist; rec_num | hash_ins | hash_del | pre_hash ---------+------------------+------------------+---------------------------------- 3 | e78e75b00d396899 | 8fcd74a8a6a4b484 | fd61cb772033da297d10c4e658e898d7 (1 row) ```
该结果表明当前节点用户历史表导出成功。
执行全局区块表导出操作。
```sql MogDB=SELECT pg_catalog.ledger_gchain_archive(); ledger_gchain_archive ----------------------- t (1 row) ```
全局历史表将以用户表为单位归档为N(用户表数量)条数据:
```sql MogDB=SELECT * FROM gs_global_chain; blocknum | dbname | username | starttime | relid | relnsp | relname | relhash | globalhash | txcommand ----------+----------+----------+-------------------------------+-------+-----------+-----------+------------------+----------------------------------+----------- 1 | postgres | libc | 2021-05-10 19:59:38.619472+08 | 16388 | ledgernsp | usertable | 57c101076694b415 | be82f98ee68b2bc4e375f69209345406 | Archived. (1 row) ```
该结果表明,当前节点全局区块表导出成功。
五、修复账本数据库
1. 前提条件
系统中需要有审计管理员或者具有审计管理员权限的角色。
数据库正常运行,并且对防篡改数据库执行了一系列增、删、改等操作,保证在查询时段内有账本操作记录结果产生。
2. 背景信息
当在异常情况或表被损坏时需要使用[账本数据库](https://docs.mogdb.io/zh/mogdb/v3.0/5-setting-a-ledger-database)的函数章节中的ledger_gchain_repair(text, text)或ledger_hist_repair(text, text)接口对全局区块表或用户历史表进行修复,修复后调用全局区块表或用户历史表校验接口结果为true。
修复用户历史表的接口为pg_catalog.ledger_hist_repair,操作为:
```sql SELECT pg_catalog.ledger_hist_repair(schema_name text,table_name text); ```
如果修复成功,函数返回修复过程中用户历史表hash的增量。
归档全局区块表的接口为pg_catalog.ledger_gchain_repair,操作为:
```sql SELECT pg_catalog.ledger_gchain_repair(schema_name text,table_name text); ```
如果修复成功,函数返回修复过程中全局区块表hash的增量。
3. 操作步骤
执行历史表修复操作。
```sql MogDB=SELECT pg_catalog.ledger_hist_repair('ledgernsp', 'usertable'); ledger_hist_repair -------------------- 84e8bfc3b974e9cf (1 row) ```
该结果表明当前节点用户历史表修复成功,修复造成的用户历史表hash增量为84e8bfc3b974e9cf。
执行全局区块表修复操作。
```sql MogDB=SELECT pg_catalog.ledger_gchain_repair('ledgernsp', 'usertable'); ledger_gchain_repair ---------------------- a41714001181a294 (1 row) ```
该结果表明,全局区块表修复成功,且插入一条修复数据,其hash值为a41714001181a294。