package trillian import ( "context" "github.com/davecgh/go-spew/spew" "github.com/google/trillian" "github.com/google/trillian/client" "github.com/google/trillian/merkle/rfc6962" tt "github.com/google/trillian/types" "github.com/sirupsen/logrus" "google.golang.org/grpc" "google.golang.org/protobuf/types/known/durationpb" "strconv" "testing" "time" ) var admin_api_client trillian.TrillianAdminClient var logClient trillian.TrillianLogClient var ctx context.Context func TestMain(m *testing.M) { con, err := grpc.Dial("192.168.3.106:8090", grpc.WithInsecure()) if err != nil { logrus.Error("consumer connect err:", err.Error()) } admin_api_client = trillian.NewTrillianAdminClient(con) logClient = trillian.NewTrillianLogClient(con) ctx = context.Background() m.Run() } //单条插入 func TestQueueLeafRequest(t *testing.T) { //1 创建基础树 resp, err := admin_api_client.CreateTree(ctx, &trillian.CreateTreeRequest{ Tree: &trillian.Tree{ TreeState: trillian.TreeState_ACTIVE, //ACTIVE:正常状态 FROZEN:只读,禁止写入 DRAINING:继续构建排队的数据,不接受新数据 TreeType: trillian.TreeType_LOG, // LOG:树表示可验证的日志,自动分配叶子索引序列号 PREORDERED_LOG:手动分配序列号 DisplayName: time.Now().Format("2006-01-02 15:04:05"), //名称 Description: "Description", //简介 MaxRootDuration: durationpb.New(time.Hour), //一定时间没提交,也会产生新的签名根.如果为零,则禁用此行为 }, }) if err != nil { logrus.Errorf("CreateTree:" + err.Error()) return } //树id var logId = resp.TreeId //2 初始化树 _, err = logClient.InitLog(ctx, &trillian.InitLogRequest{ LogId: logId, //绑定多个指定外联id //ChargeTo: &trillian.ChargeTo{ // User: []string{"id1","id2"}, //}, }) if err != nil { logrus.Errorf("InitLog:" + err.Error()) return } //3 加入叶子节点 var data = "测试数据" + time.Now().String() _, err = logClient.QueueLeaf(ctx, &trillian.QueueLeafRequest{ LogId: logId, Leaf: &trillian.LogLeaf{ LeafValue: []byte(data), ExtraData: []byte("额外数据" + time.Now().String()), //LeafIdentityHash: //自定义hash 为空默认为交易hash }, }) if err != nil { logrus.Errorf("QueueLeaf:" + err.Error()) return } time.Sleep(time.Second * 2) //延迟,树可能还没更新 //4 交易验证 //4.1 获取当前树TreeSize resLogRoot, err := logClient.GetLatestSignedLogRoot(ctx, &trillian.GetLatestSignedLogRootRequest{ LogId: logId, }) if err != nil { logrus.Errorf("GetLatestSignedLogRoot:" + err.Error()) return } //4.2 解析根树数据 var logRoot tt.LogRootV1 if err := logRoot.UnmarshalBinary(resLogRoot.SignedLogRoot.LogRoot); err != nil { logrus.Errorf("UnmarshalBinary:" + err.Error()) return } treeSize := logRoot.TreeSize //4.3 按交易hash获取默克尔树证明 hash := rfc6962.DefaultHasher.HashLeaf([]byte(data)) resInclusionByHash, err := logClient.GetInclusionProofByHash(ctx, &trillian.GetInclusionProofByHashRequest{ LogId: logId, LeafHash: hash, TreeSize: int64(treeSize), //多实例服务器可能存在偏差,请求的 tree_size 大于服务器上可用的值,proof证明为空,会返回最新根数据 }) if err != nil { logrus.Errorf("GetInclusionProofByHash:" + err.Error()) return } //4.4 验证交易有效性 err = client.NewLogVerifier(rfc6962.DefaultHasher).VerifyInclusionByHash(&logRoot, hash, resInclusionByHash.Proof[0]) if err != nil { logrus.Errorf("交易验证失败:" + err.Error()) } else { logrus.Infof("验证成功") } } //批量插入 func TestAddSequencedLeavesRequest(t *testing.T) { //1 创建基础树 resp, err := admin_api_client.CreateTree(ctx, &trillian.CreateTreeRequest{ Tree: &trillian.Tree{ TreeState: trillian.TreeState_ACTIVE, //ACTIVE:正常状态 FROZEN:只读,禁止写入 DRAINING:继续构建排队的数据,不接受新数据 TreeType: trillian.TreeType_PREORDERED_LOG, // LOG:树表示可验证的日志,自动分配叶子索引序列号 PREORDERED_LOG:手动分配序列号 DisplayName: time.Now().Format("2006-01-02 15:04:05"), //名称 Description: "Description", //简介 MaxRootDuration: durationpb.New(time.Hour), //一定时间没提交,也会产生新的签名根.如果为零,则禁用此行为 }, }) if err != nil { logrus.Errorf("CreateTree:" + err.Error()) return } //树id var logId = resp.TreeId //2 初始化树3 _, err = logClient.InitLog(ctx, &trillian.InitLogRequest{ LogId: logId, //绑定多个指定外联id //ChargeTo: &trillian.ChargeTo{ // User: []string{"id1","id2"}, //}, }) if err != nil { logrus.Errorf("InitLog:" + err.Error()) return } //3 批量添加数据 var leaves []*trillian.LogLeaf //3.1 按序组装数据 for i := 0; i < 2; i++ { leaves = append(leaves, &trillian.LogLeaf{ LeafValue: []byte("data" + strconv.Itoa(i)), ExtraData: []byte("ok22"), LeafIndex: int64(i), }) } //leaves = append(leaves, &trillian.LogLeaf{ // LeafValue: []byte("data" + strconv.Itoa(0)), // ExtraData: []byte("ok22"), // LeafIndex: int64(0), //}) //leaves = append(leaves, &trillian.LogLeaf{ // LeafValue: []byte("data" + strconv.Itoa(1)), // ExtraData: []byte("ok22"), // LeafIndex: int64(1), //}) //3.2 报错数据 _, err = logClient.AddSequencedLeaves(context.Background(), &trillian.AddSequencedLeavesRequest{ LogId: logId, Leaves: leaves, }) if err != nil { logrus.Error("TestInitLogRequest connect err:", err.Error()) } time.Sleep(time.Second * 2) //延迟,树可能还没更新 //4 交易验证 //4.1 获取当前树TreeSize resLogRoot, err := logClient.GetLatestSignedLogRoot(ctx, &trillian.GetLatestSignedLogRootRequest{ LogId: logId, }) if err != nil { logrus.Errorf("GetLatestSignedLogRoot:" + err.Error()) return } //4.2 解析根树数据 var logRoot tt.LogRootV1 if err := logRoot.UnmarshalBinary(resLogRoot.SignedLogRoot.LogRoot); err != nil { logrus.Errorf("UnmarshalBinary:" + err.Error()) return } treeSize := logRoot.TreeSize //4.3 按交易hash获取默克尔树证明 var data = "data" + strconv.Itoa(0)//模拟交易数据 hash := rfc6962.DefaultHasher.HashLeaf([]byte(data)) resInclusionByHash, err := logClient.GetInclusionProofByHash(ctx, &trillian.GetInclusionProofByHashRequest{ LogId: logId, LeafHash: hash, TreeSize: int64(treeSize), //多实例服务器可能存在偏差,请求的 tree_size 大于服务器上可用的值,proof证明为空,会返回最新根数据 }) if err != nil { logrus.Errorf("GetInclusionProofByHash:" + err.Error()) return } //4.4 验证交易有效性 err = client.NewLogVerifier(rfc6962.DefaultHasher).VerifyInclusionByHash(&logRoot, hash, resInclusionByHash.Proof[0]) if err != nil { logrus.Errorf("交易验证失败:" + err.Error()) } else { logrus.Infof("验证成功") } } func TestGetRange(t *testing.T) { res, err := logClient.GetLeavesByRange(ctx, &trillian.GetLeavesByRangeRequest{ LogId: 4821037117312290399, StartIndex: 2, Count: 1, }) if err != nil { logrus.Errorf("GetLeavesByRange:" + err.Error()) } r, err := logClient.GetEntryAndProof(ctx, &trillian.GetEntryAndProofRequest{ LogId: 4821037117312290399, LeafIndex: res.Leaves[0].LeafIndex, TreeSize: int64(13), }) if err != nil { logrus.Errorf("GetLeavesByRange:" + err.Error()) } spew.Dump(r) }