github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/internal/peer/channel/create_test.go (about) 1 /* 2 Copyright Digital Asset Holdings, LLC All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package channel 8 9 import ( 10 "bytes" 11 "errors" 12 "fmt" 13 "io/ioutil" 14 "net" 15 "os" 16 "path/filepath" 17 "regexp" 18 "sync" 19 "testing" 20 "time" 21 22 "github.com/golang/protobuf/proto" 23 "github.com/hechain20/hechain/core/config/configtest" 24 "github.com/hechain20/hechain/internal/peer/common" 25 "github.com/hechain20/hechain/internal/peer/common/mock" 26 "github.com/hechain20/hechain/internal/pkg/identity" 27 msptesttools "github.com/hechain20/hechain/msp/mgmt/testtools" 28 "github.com/hechain20/hechain/protoutil" 29 cb "github.com/hyperledger/fabric-protos-go/common" 30 "github.com/hyperledger/fabric-protos-go/orderer" 31 "github.com/spf13/viper" 32 "github.com/stretchr/testify/require" 33 "google.golang.org/grpc" 34 ) 35 36 //go:generate counterfeiter -o mock/signer_serializer.go --fake-name SignerSerializer . signerSerializer 37 38 type signerSerializer interface { 39 identity.SignerSerializer 40 } 41 42 type timeoutOrderer struct { 43 counter int 44 net.Listener 45 *grpc.Server 46 nextExpectedSeek uint64 47 t *testing.T 48 blockChannel chan uint64 49 } 50 51 func newOrderer(port int, t *testing.T) *timeoutOrderer { 52 srv := grpc.NewServer() 53 lsnr, err := net.Listen("tcp", fmt.Sprintf("localhost:%d", port)) 54 if err != nil { 55 panic(err) 56 } 57 o := &timeoutOrderer{ 58 Server: srv, 59 Listener: lsnr, 60 t: t, 61 nextExpectedSeek: uint64(1), 62 blockChannel: make(chan uint64, 1), 63 counter: int(1), 64 } 65 orderer.RegisterAtomicBroadcastServer(srv, o) 66 go srv.Serve(lsnr) 67 return o 68 } 69 70 func (o *timeoutOrderer) Shutdown() { 71 o.Server.Stop() 72 o.Listener.Close() 73 } 74 75 func (*timeoutOrderer) Broadcast(orderer.AtomicBroadcast_BroadcastServer) error { 76 panic("Should not have been called") 77 } 78 79 func (o *timeoutOrderer) SendBlock(seq uint64) { 80 o.blockChannel <- seq 81 } 82 83 func (o *timeoutOrderer) Deliver(stream orderer.AtomicBroadcast_DeliverServer) error { 84 o.timeoutIncrement() 85 if o.counter > 5 { 86 o.sendBlock(stream, 0) 87 } 88 return nil 89 } 90 91 func (o *timeoutOrderer) sendBlock(stream orderer.AtomicBroadcast_DeliverServer, seq uint64) { 92 block := &cb.Block{ 93 Header: &cb.BlockHeader{ 94 Number: seq, 95 }, 96 } 97 stream.Send(&orderer.DeliverResponse{ 98 Type: &orderer.DeliverResponse_Block{Block: block}, 99 }) 100 } 101 102 func (o *timeoutOrderer) timeoutIncrement() { 103 o.counter++ 104 } 105 106 var once sync.Once 107 108 /// mock deliver client for UT 109 type mockDeliverClient struct { 110 err error 111 } 112 113 func (m *mockDeliverClient) readBlock() (*cb.Block, error) { 114 if m.err != nil { 115 return nil, m.err 116 } 117 return &cb.Block{}, nil 118 } 119 120 func (m *mockDeliverClient) GetSpecifiedBlock(num uint64) (*cb.Block, error) { 121 return m.readBlock() 122 } 123 124 func (m *mockDeliverClient) GetOldestBlock() (*cb.Block, error) { 125 return m.readBlock() 126 } 127 128 func (m *mockDeliverClient) GetNewestBlock() (*cb.Block, error) { 129 return m.readBlock() 130 } 131 132 func (m *mockDeliverClient) Close() error { 133 return nil 134 } 135 136 // InitMSP init MSP 137 func InitMSP() { 138 once.Do(initMSP) 139 } 140 141 func initMSP() { 142 err := msptesttools.LoadMSPSetupForTesting() 143 if err != nil { 144 panic(fmt.Errorf("Fatal error when reading MSP config: err %s", err)) 145 } 146 } 147 148 func mockBroadcastClientFactory() (common.BroadcastClient, error) { 149 return common.GetMockBroadcastClient(nil), nil 150 } 151 152 func TestCreateChain(t *testing.T) { 153 defer resetFlags() 154 155 InitMSP() 156 cleanup := configtest.SetDevFabricConfigPath(t) 157 defer cleanup() 158 159 mockchain := "mockchain" 160 161 defer os.Remove(mockchain + ".block") 162 163 signer, err := common.GetDefaultSigner() 164 if err != nil { 165 t.Fatalf("Get default signer error: %v", err) 166 } 167 168 mockCF := &ChannelCmdFactory{ 169 BroadcastFactory: mockBroadcastClientFactory, 170 Signer: signer, 171 DeliverClient: &mockDeliverClient{}, 172 } 173 174 cmd := createCmd(mockCF) 175 176 AddFlags(cmd) 177 178 args := []string{"-c", mockchain, "-o", "localhost:7050"} 179 cmd.SetArgs(args) 180 181 if err := cmd.Execute(); err != nil { 182 t.Fail() 183 t.Errorf("expected create command to succeed") 184 } 185 186 filename := mockchain + ".block" 187 if _, err := os.Stat(filename); err != nil { 188 t.Fail() 189 t.Errorf("expected %s to exist", filename) 190 } 191 } 192 193 func TestCreateChainWithOutputBlock(t *testing.T) { 194 defer resetFlags() 195 196 InitMSP() 197 cleanup := configtest.SetDevFabricConfigPath(t) 198 defer cleanup() 199 200 mockchain := "mockchain" 201 202 signer, err := common.GetDefaultSigner() 203 if err != nil { 204 t.Fatalf("Get default signer error: %v", err) 205 } 206 207 mockCF := &ChannelCmdFactory{ 208 BroadcastFactory: mockBroadcastClientFactory, 209 Signer: signer, 210 DeliverClient: &mockDeliverClient{}, 211 } 212 213 cmd := createCmd(mockCF) 214 AddFlags(cmd) 215 216 tempDir, err := ioutil.TempDir("", "create-output") 217 if err != nil { 218 t.Fatalf("failed to create temporary directory") 219 } 220 defer os.RemoveAll(tempDir) 221 222 outputBlockPath := filepath.Join(tempDir, "output.block") 223 args := []string{"-c", mockchain, "-o", "localhost:7050", "--outputBlock", outputBlockPath} 224 cmd.SetArgs(args) 225 defer func() { outputBlock = "" }() 226 227 err = cmd.Execute() 228 require.NoError(t, err, "execute should succeed") 229 230 _, err = os.Stat(outputBlockPath) 231 require.NoErrorf(t, err, "expected %s to exist", outputBlockPath) 232 } 233 234 func TestCreateChainWithDefaultAnchorPeers(t *testing.T) { 235 defer resetFlags() 236 237 InitMSP() 238 cleanup := configtest.SetDevFabricConfigPath(t) 239 defer cleanup() 240 241 mockchain := "mockchain" 242 243 defer os.Remove(mockchain + ".block") 244 245 signer, err := common.GetDefaultSigner() 246 if err != nil { 247 t.Fatalf("Get default signer error: %v", err) 248 } 249 250 mockCF := &ChannelCmdFactory{ 251 BroadcastFactory: mockBroadcastClientFactory, 252 Signer: signer, 253 DeliverClient: &mockDeliverClient{}, 254 } 255 256 cmd := createCmd(mockCF) 257 AddFlags(cmd) 258 args := []string{"-c", mockchain, "-o", "localhost:7050"} 259 cmd.SetArgs(args) 260 261 if err := cmd.Execute(); err != nil { 262 t.Fail() 263 t.Errorf("expected create command to succeed") 264 } 265 } 266 267 func TestCreateChainWithWaitSuccess(t *testing.T) { 268 defer resetFlags() 269 270 InitMSP() 271 cleanup := configtest.SetDevFabricConfigPath(t) 272 defer cleanup() 273 274 mockchain := "mockchain" 275 276 signer, err := common.GetDefaultSigner() 277 if err != nil { 278 t.Fatalf("Get default signer error: %v", err) 279 } 280 281 mockCF := &ChannelCmdFactory{ 282 BroadcastFactory: mockBroadcastClientFactory, 283 Signer: signer, 284 DeliverClient: &mockDeliverClient{err: nil}, 285 } 286 fakeOrderer := newOrderer(8101, t) 287 defer fakeOrderer.Shutdown() 288 289 cmd := createCmd(mockCF) 290 AddFlags(cmd) 291 args := []string{"-c", mockchain, "-o", "localhost:8101", "-t", "10s"} 292 cmd.SetArgs(args) 293 294 if err := cmd.Execute(); err != nil { 295 t.Fail() 296 t.Errorf("expected create command to succeed") 297 } 298 } 299 300 func TestCreateChainWithTimeoutErr(t *testing.T) { 301 defer viper.Reset() 302 defer resetFlags() 303 304 InitMSP() 305 cleanup := configtest.SetDevFabricConfigPath(t) 306 defer cleanup() 307 308 mockchain := "mockchain" 309 310 signer, err := common.GetDefaultSigner() 311 if err != nil { 312 t.Fatalf("Get default signer error: %v", err) 313 } 314 315 mockCF := &ChannelCmdFactory{ 316 BroadcastFactory: mockBroadcastClientFactory, 317 Signer: signer, 318 DeliverClient: &mockDeliverClient{err: errors.New("bobsled")}, 319 } 320 fakeOrderer := newOrderer(8102, t) 321 defer fakeOrderer.Shutdown() 322 323 // failure - connects to orderer but times out waiting for channel to 324 // be created 325 cmd := createCmd(mockCF) 326 AddFlags(cmd) 327 channelCmd.AddCommand(cmd) 328 args := []string{"create", "-c", mockchain, "-o", "localhost:8102", "-t", "10ms", "--connTimeout", "1s"} 329 channelCmd.SetArgs(args) 330 331 if err := channelCmd.Execute(); err == nil { 332 t.Error("expected create chain to fail with deliver error") 333 } else { 334 require.Contains(t, err.Error(), "timeout waiting for channel creation") 335 } 336 337 // failure - point to bad port and time out connecting to orderer 338 args = []string{"create", "-c", mockchain, "-o", "localhost:0", "-t", "1s", "--connTimeout", "10ms"} 339 channelCmd.SetArgs(args) 340 341 if err := channelCmd.Execute(); err == nil { 342 t.Error("expected create chain to fail with deliver error") 343 } else { 344 require.Contains(t, err.Error(), "failed connecting") 345 } 346 } 347 348 func TestCreateChainBCFail(t *testing.T) { 349 defer resetFlags() 350 351 InitMSP() 352 cleanup := configtest.SetDevFabricConfigPath(t) 353 defer cleanup() 354 355 mockchain := "mockchain" 356 357 defer os.Remove(mockchain + ".block") 358 359 signer, err := common.GetDefaultSigner() 360 if err != nil { 361 t.Fatalf("Get default signer error: %v", err) 362 } 363 364 sendErr := errors.New("luge") 365 mockCF := &ChannelCmdFactory{ 366 BroadcastFactory: func() (common.BroadcastClient, error) { 367 return common.GetMockBroadcastClient(sendErr), nil 368 }, 369 Signer: signer, 370 DeliverClient: &mockDeliverClient{}, 371 } 372 373 cmd := createCmd(mockCF) 374 AddFlags(cmd) 375 args := []string{"-c", mockchain, "-o", "localhost:7050"} 376 cmd.SetArgs(args) 377 378 expectedErrMsg := sendErr.Error() 379 if err := cmd.Execute(); err == nil { 380 t.Error("expected create chain to fail with broadcast error") 381 } else { 382 if err.Error() != expectedErrMsg { 383 t.Errorf("Run create chain get unexpected error: %s(expected %s)", err.Error(), expectedErrMsg) 384 } 385 } 386 } 387 388 func TestCreateChainDeliverFail(t *testing.T) { 389 defer resetFlags() 390 391 InitMSP() 392 cleanup := configtest.SetDevFabricConfigPath(t) 393 defer cleanup() 394 395 mockchain := "mockchain" 396 397 defer os.Remove(mockchain + ".block") 398 399 signer, err := common.GetDefaultSigner() 400 if err != nil { 401 t.Fatalf("Get default signer error: %v", err) 402 } 403 404 sendErr := fmt.Errorf("skeleton") 405 mockCF := &ChannelCmdFactory{ 406 BroadcastFactory: func() (common.BroadcastClient, error) { 407 return common.GetMockBroadcastClient(sendErr), nil 408 }, 409 Signer: signer, 410 DeliverClient: &mockDeliverClient{err: sendErr}, 411 } 412 cmd := createCmd(mockCF) 413 AddFlags(cmd) 414 args := []string{"-c", mockchain, "-o", "localhost:7050"} 415 cmd.SetArgs(args) 416 417 expectedErrMsg := sendErr.Error() 418 if err := cmd.Execute(); err == nil { 419 t.Errorf("expected create chain to fail with deliver error") 420 } else { 421 if err.Error() != expectedErrMsg { 422 t.Errorf("Run create chain get unexpected error: %s(expected %s)", err.Error(), expectedErrMsg) 423 } 424 } 425 } 426 427 func createTxFile(filename string, typ cb.HeaderType, channelID string) (*cb.Envelope, error) { 428 ch := &cb.ChannelHeader{Type: int32(typ), ChannelId: channelID} 429 data, err := proto.Marshal(ch) 430 if err != nil { 431 return nil, err 432 } 433 434 p := &cb.Payload{Header: &cb.Header{ChannelHeader: data}} 435 data, err = proto.Marshal(p) 436 if err != nil { 437 return nil, err 438 } 439 440 env := &cb.Envelope{Payload: data} 441 data, err = proto.Marshal(env) 442 if err != nil { 443 return nil, err 444 } 445 446 if err = ioutil.WriteFile(filename, data, 0o644); err != nil { 447 return nil, err 448 } 449 450 return env, nil 451 } 452 453 func TestCreateChainFromTx(t *testing.T) { 454 defer resetFlags() 455 InitMSP() 456 cleanup := configtest.SetDevFabricConfigPath(t) 457 defer cleanup() 458 459 mockchannel := "mockchannel" 460 dir, err := ioutil.TempDir("", "createtestfromtx-") 461 if err != nil { 462 t.Fatalf("couldn't create temp dir") 463 } 464 defer os.RemoveAll(dir) // clean up 465 466 // this could be created by the create command 467 defer os.Remove(mockchannel + ".block") 468 469 file := filepath.Join(dir, mockchannel) 470 471 signer, err := common.GetDefaultSigner() 472 if err != nil { 473 t.Fatalf("Get default signer error: %v", err) 474 } 475 mockCF := &ChannelCmdFactory{ 476 BroadcastFactory: mockBroadcastClientFactory, 477 Signer: signer, 478 DeliverClient: &mockDeliverClient{}, 479 } 480 481 cmd := createCmd(mockCF) 482 AddFlags(cmd) 483 484 // Error case 0 485 args := []string{"-c", "", "-f", file, "-o", "localhost:7050"} 486 cmd.SetArgs(args) 487 err = cmd.Execute() 488 require.Error(t, err, "Create command should have failed because channel ID is not specified") 489 require.Contains(t, err.Error(), "must supply channel ID") 490 491 // Error case 1 492 args = []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 493 cmd.SetArgs(args) 494 err = cmd.Execute() 495 require.Error(t, err, "Create command should have failed because tx file does not exist") 496 msgExpr := regexp.MustCompile(`channel create configuration tx file not found.*no such file or directory`) 497 require.True(t, msgExpr.MatchString(err.Error())) 498 499 // Success case: -f option is empty 500 args = []string{"-c", mockchannel, "-f", "", "-o", "localhost:7050"} 501 cmd.SetArgs(args) 502 err = cmd.Execute() 503 require.NoError(t, err) 504 505 // Success case 506 args = []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 507 cmd.SetArgs(args) 508 _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, mockchannel) 509 require.NoError(t, err, "Couldn't create tx file") 510 err = cmd.Execute() 511 require.NoError(t, err) 512 } 513 514 func TestCreateChainInvalidTx(t *testing.T) { 515 defer resetFlags() 516 517 InitMSP() 518 cleanup := configtest.SetDevFabricConfigPath(t) 519 defer cleanup() 520 521 mockchannel := "mockchannel" 522 523 dir, err := ioutil.TempDir("", "createinvaltest-") 524 if err != nil { 525 t.Fatalf("couldn't create temp dir") 526 } 527 528 defer os.RemoveAll(dir) // clean up 529 530 // this is created by create command 531 defer os.Remove(mockchannel + ".block") 532 533 file := filepath.Join(dir, mockchannel) 534 535 signer, err := common.GetDefaultSigner() 536 if err != nil { 537 t.Fatalf("Get default signer error: %v", err) 538 } 539 540 mockCF := &ChannelCmdFactory{ 541 BroadcastFactory: mockBroadcastClientFactory, 542 Signer: signer, 543 DeliverClient: &mockDeliverClient{}, 544 } 545 546 cmd := createCmd(mockCF) 547 548 AddFlags(cmd) 549 550 args := []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 551 cmd.SetArgs(args) 552 553 // bad type CONFIG 554 if _, err = createTxFile(file, cb.HeaderType_CONFIG, mockchannel); err != nil { 555 t.Fatalf("couldn't create tx file") 556 } 557 558 defer os.Remove(file) 559 560 if err = cmd.Execute(); err == nil { 561 t.Errorf("expected error") 562 } else if _, ok := err.(InvalidCreateTx); !ok { 563 t.Errorf("invalid error") 564 } 565 566 // bad channel name - does not match one specified in command 567 if _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, "different_channel"); err != nil { 568 t.Fatalf("couldn't create tx file") 569 } 570 571 if err = cmd.Execute(); err == nil { 572 t.Errorf("expected error") 573 } else if _, ok := err.(InvalidCreateTx); !ok { 574 t.Errorf("invalid error") 575 } 576 577 // empty channel 578 if _, err = createTxFile(file, cb.HeaderType_CONFIG_UPDATE, ""); err != nil { 579 t.Fatalf("couldn't create tx file") 580 } 581 582 if err := cmd.Execute(); err == nil { 583 t.Errorf("expected error") 584 } else if _, ok := err.(InvalidCreateTx); !ok { 585 t.Errorf("invalid error") 586 } 587 } 588 589 func TestCreateChainNilCF(t *testing.T) { 590 defer viper.Reset() 591 defer resetFlags() 592 593 InitMSP() 594 cleanup := configtest.SetDevFabricConfigPath(t) 595 defer cleanup() 596 597 mockchannel := "mockchannel" 598 dir, err := ioutil.TempDir("", "createinvaltest-") 599 require.NoError(t, err, "Couldn't create temp dir") 600 defer os.RemoveAll(dir) // clean up 601 602 // this is created by create command 603 defer os.Remove(mockchannel + ".block") 604 file := filepath.Join(dir, mockchannel) 605 606 // Error case: grpc error 607 viper.Set("orderer.client.connTimeout", 10*time.Millisecond) 608 cmd := createCmd(nil) 609 AddFlags(cmd) 610 args := []string{"-c", mockchannel, "-f", file, "-o", "localhost:7050"} 611 cmd.SetArgs(args) 612 err = cmd.Execute() 613 require.Error(t, err) 614 require.Contains(t, err.Error(), "failed to create deliver client") 615 616 // Error case: invalid ordering service endpoint 617 args = []string{"-c", mockchannel, "-f", file, "-o", "localhost"} 618 cmd.SetArgs(args) 619 err = cmd.Execute() 620 require.Error(t, err) 621 require.Contains(t, err.Error(), "ordering service endpoint localhost is not valid or missing") 622 623 // Error case: invalid ca file 624 defer os.RemoveAll(dir) // clean up 625 channelCmd.AddCommand(cmd) 626 args = []string{"create", "-c", mockchannel, "-f", file, "-o", "localhost:7050", "--tls", "true", "--cafile", dir + "/ca.pem"} 627 channelCmd.SetArgs(args) 628 err = channelCmd.Execute() 629 require.Error(t, err) 630 t.Log(err) 631 require.Contains(t, err.Error(), "no such file or directory") 632 } 633 634 func TestSanityCheckAndSignChannelCreateTx(t *testing.T) { 635 defer resetFlags() 636 637 signer := &mock.SignerSerializer{} 638 env := &cb.Envelope{} 639 env.Payload = make([]byte, 10) 640 var err error 641 642 // Error case 1 643 _, err = sanityCheckAndSignConfigTx(env, signer) 644 require.Error(t, err, "Error expected for nil payload") 645 require.Contains(t, err.Error(), "bad payload") 646 647 // Error case 2 648 p := &cb.Payload{Header: nil} 649 data, err1 := proto.Marshal(p) 650 require.NoError(t, err1) 651 env = &cb.Envelope{Payload: data} 652 _, err = sanityCheckAndSignConfigTx(env, signer) 653 require.Error(t, err, "Error expected for bad payload header") 654 require.Contains(t, err.Error(), "bad header") 655 656 // Error case 3 657 bites := bytes.NewBufferString("foo").Bytes() 658 p = &cb.Payload{Header: &cb.Header{ChannelHeader: bites}} 659 data, err = proto.Marshal(p) 660 require.NoError(t, err) 661 env = &cb.Envelope{Payload: data} 662 _, err = sanityCheckAndSignConfigTx(env, signer) 663 require.Error(t, err, "Error expected for bad channel header") 664 require.Contains(t, err.Error(), "could not unmarshall channel header") 665 666 // Error case 4 667 mockchannel := "mockchannel" 668 cid := channelID 669 channelID = mockchannel 670 defer func() { 671 channelID = cid 672 }() 673 ch := &cb.ChannelHeader{Type: int32(cb.HeaderType_CONFIG_UPDATE), ChannelId: mockchannel} 674 data, err = proto.Marshal(ch) 675 require.NoError(t, err) 676 p = &cb.Payload{Header: &cb.Header{ChannelHeader: data}, Data: bytes.NewBufferString("foo").Bytes()} 677 data, err = proto.Marshal(p) 678 require.NoError(t, err) 679 env = &cb.Envelope{Payload: data} 680 _, err = sanityCheckAndSignConfigTx(env, signer) 681 require.Error(t, err, "Error expected for bad payload data") 682 require.Contains(t, err.Error(), "Bad config update env") 683 684 // Error case 5 685 signer = &mock.SignerSerializer{} 686 signer.SerializeReturns(nil, errors.New("bad signer header")) 687 env, err = protoutil.CreateSignedEnvelope( 688 cb.HeaderType_CONFIG_UPDATE, 689 "mockchannel", 690 nil, 691 &cb.ConfigEnvelope{}, 692 0, 693 0) 694 require.NoError(t, err) 695 _, err = sanityCheckAndSignConfigTx(env, signer) 696 require.EqualError(t, err, "bad signer header") 697 698 // Error case 6 699 signer = &mock.SignerSerializer{} 700 signer.SignReturns(nil, errors.New("signer failed to sign")) 701 env, err = protoutil.CreateSignedEnvelope( 702 cb.HeaderType_CONFIG_UPDATE, 703 "mockchannel", 704 nil, 705 &cb.ConfigEnvelope{}, 706 0, 707 0) 708 require.NoError(t, err) 709 _, err = sanityCheckAndSignConfigTx(env, signer) 710 require.EqualError(t, err, "signer failed to sign") 711 }