diff --git a/internal/osnadmin/fetch.go b/internal/osnadmin/fetch.go new file mode 100644 index 0000000..b43fcba --- /dev/null +++ b/internal/osnadmin/fetch.go @@ -0,0 +1,42 @@ +package osnadmin + +import ( + "context" + "crypto/tls" + "crypto/x509" + "fmt" + "io" + "net/http" + + "github.com/hyperledger/fabric-protos-go-apiv2/common" + "google.golang.org/protobuf/proto" +) + +func Fetch(ctx context.Context, osnURL, channelID string, blockID string, caCertPool *x509.CertPool, tlsClientCert tls.Certificate) (*common.Block, error) { + url := fmt.Sprintf("%s/participation/v1/channels/%s/blocks/%s", osnURL, channelID, blockID) + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return nil, fmt.Errorf("create request: %w", err) + } + + resp, err := httpDo(req, caCertPool, tlsClientCert) + if err != nil { + return nil, fmt.Errorf("process request: %w", err) + } + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("unexpected status code: %d", resp.StatusCode) + } + + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("read response body: %w", err) + } + + var block common.Block + if err := proto.Unmarshal(body, &block); err != nil { + return nil, fmt.Errorf("unmarshal response body: %w", err) + } + return &block, nil +} diff --git a/internal/osnadmin/update.go b/internal/osnadmin/update.go new file mode 100644 index 0000000..df8e987 --- /dev/null +++ b/internal/osnadmin/update.go @@ -0,0 +1,48 @@ +package osnadmin + +import ( + "bytes" + "context" + "crypto/tls" + "crypto/x509" + "fmt" + "mime/multipart" + "net/http" +) + +// Update channel configuration using presented config envelope. +func Update(ctx context.Context, osnURL, channelID string, caCertPool *x509.CertPool, tlsClientCert tls.Certificate, configEnvelope []byte) (*http.Response, error) { + url := osnURL + "/participation/v1/channels" + + req, err := createUpdateRequest(ctx, url, configEnvelope) + if err != nil { + return nil, fmt.Errorf("create update request: %w", err) + } + + return httpDo(req, caCertPool, tlsClientCert) +} + +func createUpdateRequest(ctx context.Context, url string, configEnvelope []byte) (*http.Request, error) { + joinBody := new(bytes.Buffer) + writer := multipart.NewWriter(joinBody) + part, err := writer.CreateFormFile("config-update-envelope", "config_update.pb") + if err != nil { + return nil, err + } + _, err = part.Write(configEnvelope) + if err != nil { + return nil, err + } + err = writer.Close() + if err != nil { + return nil, err + } + + req, err := http.NewRequestWithContext(ctx, http.MethodPut, url, joinBody) + if err != nil { + return nil, err + } + req.Header.Set("Content-Type", writer.FormDataContentType()) + + return req, nil +} diff --git a/pkg/channel/block.go b/pkg/channel/block.go index aac92ca..e4b6678 100644 --- a/pkg/channel/block.go +++ b/pkg/channel/block.go @@ -2,8 +2,11 @@ package channel import ( "context" + "crypto/tls" + "crypto/x509" "fmt" + "github.com/hyperledger/fabric-admin-sdk/internal/osnadmin" "github.com/hyperledger/fabric-admin-sdk/pkg/identity" "github.com/hyperledger/fabric-admin-sdk/pkg/internal/proposal" @@ -61,3 +64,7 @@ func getSignedProposal(ctx context.Context, connection grpc.ClientConnInterface, return proposalResp, nil } + +func GetBlock(ctx context.Context, osnURL, channelID, blockID string, caCertPool *x509.CertPool, tlsClientCert tls.Certificate) (*cb.Block, error) { + return osnadmin.Fetch(ctx, osnURL, channelID, blockID, caCertPool, tlsClientCert) +} diff --git a/pkg/channel/channel.go b/pkg/channel/channel.go index db1bdf8..0c47fac 100644 --- a/pkg/channel/channel.go +++ b/pkg/channel/channel.go @@ -13,9 +13,9 @@ import ( "github.com/hyperledger/fabric-admin-sdk/internal/protoutil" "github.com/hyperledger/fabric-admin-sdk/pkg/identity" "github.com/hyperledger/fabric-admin-sdk/pkg/internal/proposal" - "github.com/hyperledger/fabric-protos-go-apiv2/peer" cb "github.com/hyperledger/fabric-protos-go-apiv2/common" + "github.com/hyperledger/fabric-protos-go-apiv2/peer" "google.golang.org/grpc" "google.golang.org/protobuf/proto" ) @@ -110,3 +110,8 @@ func ListChannelOnPeer(ctx context.Context, connection grpc.ClientConnInterface, } return channelQueryResponse.GetChannels(), nil } + +func UpdateChannel(ctx context.Context, osnURL string, caCertPool *x509.CertPool, tlsClientCert tls.Certificate, channelName string, env *cb.Envelope) (*http.Response, error) { + envelopeBytes := protoutil.MarshalOrPanic(env) + return osnadmin.Update(ctx, osnURL, channelName, caCertPool, tlsClientCert, envelopeBytes) +}