Skip to content

Commit

Permalink
Merge pull request #1 from 3130585774/master
Browse files Browse the repository at this point in the history
init Commit
  • Loading branch information
3130585774 authored Oct 28, 2024
2 parents 1bb02f4 + 74b2f2a commit 9444f47
Show file tree
Hide file tree
Showing 7 changed files with 859 additions and 2 deletions.
290 changes: 288 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,288 @@
# blockchainlite
BlockchainLite 是一个轻量级的区块链实现。
### 描述

**BlockchainLite** 是一个轻量级的区块链实现,旨在简化和教育目的。该系统允许用户创建一个安全且防篡改的区块链,使用 SQLite 数据库存储数据。

---

### 主要特性
- **区块结构**:每个区块包含索引、时间戳、数据负载、哈希值和前一个区块的哈希值,以确保区块链的完整性和不可变性。
- **数据库存储**:区块以 SQLite 数据库的形式存储,便于访问和操作。
- **数据序列化**:用户可以以 JSON 格式添加数据到区块链,灵活适应多种应用场景。
- **并发支持**:实现通过互斥锁确保线程安全,允许多个 `goroutine` 在不风险数据损坏的情况下添加区块。
- **历史记录检索**:用户可以轻松检索区块历史,以访问以前的条目及其相关数据。

### 快速开始

```go
package main

import (
"github.com/3130585774/blockchainlite"
"log"
)

func main() {
bcName := "myBlockchain"
server, err := blockchainlite.NewServer(bcName)
if err != nil {
log.Fatalf("Error creating server: %v", err)
}

addr := ":8080"
if err := server.Start(addr); err != nil {
log.Fatalf("Error starting server: %v", err)
}

defer func() {
if err := server.Stop(); err != nil {
log.Printf("Error stopping server: %v", err)
}
}()

select {}
}
```

#### API 端点

1. **添加区块**
- **请求方法**`POST`
- **路径**`/blocks`
- **请求体**
```json
{
"data": "Your block data here"
}
```
- **响应**:
- 成功时返回:
```json
{
"code": 201,
"data": "Block added successfully"
}
```
- 失败时返回:
```json
{
"code": 400,
"error": "Error message"
}
```

2. **获取最新区块**
- **请求方法**:`GET`
- **路径**:`/blocks/latest`
- **响应**:
- 成功时返回:
```json
{
"code": 200,
"data": {
"index": 1,
"timestamp": "2024-01-01T00:00:00Z",
"data": "Your block data",
"hash": "abc123",
"previous_hash": "xyz789"
}
}
```
- 失败时返回:
```json
{
"code": 404,
"error": "No blocks found"
}
```

3. **获取区块历史**
- **请求方法**:`GET`
- **路径**:`/blocks/history`
- **响应**:
- 成功时返回:
```json
{
"code": 200,
"data": [
{
"index": 1,
"timestamp": "2024-01-01T00:00:00Z",
"data": "Your block data",
"hash": "abc123",
"previous_hash": "xyz789"
},
{
"index": 2,
"timestamp": "2024-01-02T00:00:00Z",
"data": "Another block data",
"hash": "def456",
"previous_hash": "abc123"
}
]
}
```

---

### 示例用法
以下是使用 Python、Java、JavaScript 和 Go 访问 **BlockchainLite** API 的示例代码。

### 1. Python 示例

```python
import requests
import json

# 添加区块
url = 'http://localhost:8080/blocks'
data = {'data': 'This is my first block data'}
response = requests.post(url, json=data)
print(response.json())

# 获取最新区块
response = requests.get('http://localhost:8080/blocks/latest')
print(response.json())

# 获取区块历史
response = requests.get('http://localhost:8080/blocks/history')
print(response.json())
```

### 2. Java 示例

```java
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;

public class BlockchainLiteExample {

public static void main(String[] args) throws Exception {
// 添加区块
String url = "http://localhost:8080/blocks";
String jsonInputString = "{\"data\": \"This is my first block data\"}";

HttpURLConnection conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setDoOutput(true);

try(OutputStream os = conn.getOutputStream()) {
byte[] input = jsonInputString.getBytes("utf-8");
os.write(input, 0, input.length);
}

System.out.println("Response Code: " + conn.getResponseCode());
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
StringBuilder response = new StringBuilder();
String responseLine;

while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println(response.toString());

// 获取最新区块
conn = (HttpURLConnection) new URL("http://localhost:8080/blocks/latest").openConnection();
conn.setRequestMethod("GET");
System.out.println("Response Code: " + conn.getResponseCode());
br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
response = new StringBuilder();

while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println(response.toString());

// 获取区块历史
conn = (HttpURLConnection) new URL("http://localhost:8080/blocks/history").openConnection();
conn.setRequestMethod("GET");
System.out.println("Response Code: " + conn.getResponseCode());
br = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
response = new StringBuilder();

while ((responseLine = br.readLine()) != null) {
response.append(responseLine.trim());
}
System.out.println(response.toString());
}
}
```

### 3. JavaScript 示例(使用 Fetch API)

```javascript
// 添加区块
fetch('http://localhost:8080/blocks', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ data: 'This is my first block data' }),
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

// 获取最新区块
fetch('http://localhost:8080/blocks/latest')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));

// 获取区块历史
fetch('http://localhost:8080/blocks/history')
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```

### 4. Go 示例

```go
package main

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
)

func main() {
// 添加区块
url := "http://localhost:8080/blocks"
data := map[string]string{"data": "This is my first block data"}
jsonData, _ := json.Marshal(data)

resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
body, _ := ioutil.ReadAll(resp.Body)
fmt.Println(string(body))

// 获取最新区块
resp, err = http.Get("http://localhost:8080/blocks/latest")
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
body, _ = ioutil.ReadAll(resp.Body)
fmt.Println(string(body))

// 获取区块历史
resp, err = http.Get("http://localhost:8080/blocks/history")
if err != nil {
fmt.Println("Error:", err)
return
}
defer resp.Body.Close()
body, _ = ioutil.ReadAll(resp.Body)
fmt.Println(string(body))
}
```
107 changes: 107 additions & 0 deletions api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package blockchainlite

import (
"context"
"encoding/json"
"errors"
"github.com/gorilla/mux"
"log"
"net/http"
"time"
)

type Server struct {
blockchain *Blockchain
httpServer *http.Server
}
type Response struct {
Code int `json:"code"`
Data interface{} `json:"data,omitempty"`
Error string `json:"error,omitempty"`
}

func NewServer(bcName string) (*Server, error) {
bc, err := NewBlockchain(bcName)
if err != nil {
return nil, err
}
return &Server{
blockchain: bc,
httpServer: &http.Server{},
}, nil
}

func (s *Server) writeResponse(w http.ResponseWriter, code int, data interface{}, errMsg string) {
response := Response{
Code: code,
Data: data,
Error: errMsg,
}
w.WriteHeader(code)
json.NewEncoder(w).Encode(response)
}

func (s *Server) AddBlockHandler(w http.ResponseWriter, r *http.Request) {
var data interface{}
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
s.writeResponse(w, http.StatusBadRequest, nil, err.Error())
return
}

if err := s.blockchain.AddBlock(data); err != nil {
s.writeResponse(w, http.StatusInternalServerError, nil, err.Error())
return
}

s.writeResponse(w, http.StatusCreated, "Block added successfully", "")
}

func (s *Server) GetLatestBlockHandler(w http.ResponseWriter, r *http.Request) {
block, err := s.blockchain.GetLatestBlock()
if err != nil {
s.writeResponse(w, http.StatusInternalServerError, nil, err.Error())
return
}
if block == nil {
s.writeResponse(w, http.StatusNotFound, nil, "No blocks found")
return
}
s.writeResponse(w, http.StatusOK, block, "")
}

func (s *Server) GetBlockHistoryHandler(w http.ResponseWriter, r *http.Request) {
blocks, err := s.blockchain.GetBlockHistory()
if err != nil {
s.writeResponse(w, http.StatusInternalServerError, nil, err.Error())
return
}
s.writeResponse(w, http.StatusOK, blocks, "")
}

func (s *Server) Start(addr string) error {
r := mux.NewRouter()

r.HandleFunc("/blocks", s.AddBlockHandler).Methods("POST")
r.HandleFunc("/blocks/latest", s.GetLatestBlockHandler).Methods("GET")
r.HandleFunc("/blocks/history", s.GetBlockHistoryHandler).Methods("GET")

s.httpServer.Addr = addr
log.Printf("Starting server on %s\n", addr)

go func() {
if err := s.httpServer.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
log.Fatalf("ListenAndServe(): %v", err)
}
}()

return nil
}

func (s *Server) Stop() error {
log.Println("Stopping server...")
s.blockchain.Close()
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()

return s.httpServer.Shutdown(ctx)
}
Loading

0 comments on commit 9444f47

Please sign in to comment.