王森涛
发布于 2026-08-03 / 0 阅读
0
0

《东京物语》与数字遗产:家族记忆的链上永续存储

《东京物语》与数字遗产:家族记忆的链上永续存储

1953年,小津安二郎的《东京物语》(Tokyo Story)讲述了一个关于"家庭"、"记忆"和"遗忘"的永恒故事。年迈的夫妇周吉和富子从尾道来到东京看望他们的子女,但子女们各自忙于自己的生活,无暇顾及父母。只有已故次子的妻子纪子,以"儿媳"的身份善待了他们。电影的结尾,富子去世,周吉独自返回尾道,面对空荡荡的家——"人生真是寂寞啊"。2026年,当我们思考"数字遗产"时,《东京物语》的"寂寞"感变得更加深刻:我们的数字记忆——照片、视频、日记、社交媒体的帖子——存储在各种中心化平台上,但这些平台可能关闭、可能删除数据、可能改变政策。区块链技术提供了一个"永续存储"的解决方案:将家族记忆存储在去中心化的链上网络中,让它们"永不消失"。

第一幕:数字记忆的"不可靠"存储

第一场:中心化存储的脆弱性

2026年,一个普通人的"数字记忆"分布在大约20-30个不同的平台上:

  • 照片存储在Google Photos、iCloud、Flickr上。
  • 视频存储在YouTube、Vimeo、TikTok上。
  • 日记存储在博客平台、Notion、Evernote上。
  • 社交媒体帖子存储在Facebook、Instagram、Twitter上。

这些平台的问题是:它们不是"永久的"。Google Photos可能会改变免费政策、iCloud可能会被黑客攻击、YouTube可能会删除你的频道、Facebook可能会关闭你的账户。你的"数字记忆"实际上并不属于你——它们属于平台。

第二场:数字遗产的法律困境

当一个人去世时,他的"数字遗产"面临复杂的法律问题:

  1. 平台账户:平台账户通常不可转让,去世后账户可能被删除。
  2. 数据所有权:存储在平台上的数据属于谁?用户还是平台?
  3. 访问权限:家人是否有权访问去世亲人的数字记忆?
  4. 隐私保护:去世亲人的隐私如何保护?

第三场:从"租赁"到"拥有"——链上存储的范式转变

区块链技术提供了一个根本性的解决方案:将数字记忆存储在去中心化的网络上,用户真正"拥有"自己的数据,而不是从平台"租赁"存储空间。

  • IPFS(InterPlanetary File System):分布式文件系统,文件被分割成小块,存储在全球多个节点上。
  • Filecoin:基于IPFS的去中心化存储市场,用户支付FIL代币来存储文件,矿工通过提供存储空间获得FIL。
  • Arweave:永久存储网络,用户一次性支付费用,文件永久存储在Arweave的"永续网络"上。
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/access/AccessControl.sol";
import "@openzeppelin/contracts/token/ERC721/ERC721.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";

contract FamilyMemoryVault is ERC721, AccessControl, ReentrancyGuard {
    bytes32 public constant FAMILY_HEAD_ROLE = keccak256("FAMILY_HEAD_ROLE");
    bytes32 public constant MEMBER_ROLE = keccak256("MEMBER_ROLE");

    enum MemoryType {
        PHOTO, VIDEO, AUDIO, DOCUMENT, LETTER, DIARY, FAMILY_TREE, OTHER
    }

    enum AccessLevel {
        PUBLIC,         // 公开
        FAMILY_ONLY,    // 仅限家族
        PRIVATE         // 仅限本人
    }

    struct Memory {
        uint256 memoryId;
        string title;
        string description;
        MemoryType mType;
        string ipfsCID;
        string thumbnailCID;
        uint256 createdAt;
        uint256 capturedAt;
        address creator;
        string[] tags;
        AccessLevel accessLevel;
        uint256 viewCount;
        bool isEncrypted;
    }

    struct FamilyMember {
        address memberAddress;
        string name;
        string relationship;
        string bio;
        string ipfsAvatarCID;
        uint256 joinedAt;
        uint256 memoryCount;
        bool isActive;
    }

    struct Family {
        uint256 familyId;
        string name;
        string motto;
        address founder;
        uint256 memberCount;
        uint256 totalMemories;
        uint256 createdAt;
        bool isActive;
    }

    uint256 private _familyCounter;
    uint256 private _memoryCounter;
    uint256 private _memberCounter;

    mapping(uint256 => Family) public families;
    mapping(uint256 => Memory) public memories;
    mapping(address => FamilyMember) public familyMembers;
    mapping(uint256 => uint256[]) public familyMemories;
    mapping(uint256 => address[]) public familyMemberList;
    mapping(address => uint256) public memberFamily;
    mapping(uint256 => mapping(address => bool)) public memoryAccess;

    uint256 public constant STORAGE_FEE = 0.01 ether;

    event FamilyCreated(uint256 indexed familyId, string name, address indexed founder);
    event MemberAdded(uint256 indexed familyId, address indexed member, string relationship);
    event MemoryAdded(uint256 indexed memoryId, uint256 indexed familyId, address indexed creator, string title);
    event MemoryAccessed(uint256 indexed memoryId, address indexed viewer);
    event FamilyMottoUpdated(uint256 indexed familyId, string newMotto);

    constructor() ERC721("FamilyMemoryVault", "FMV") {
        _grantRole(DEFAULT_ADMIN_ROLE, msg.sender);
    }

    function createFamily(string memory _name, string memory _motto) external returns (uint256) {
        require(memberFamily[msg.sender] == 0, "Already in a family");
        uint256 familyId = _familyCounter++;
        families[familyId] = Family({
            familyId: familyId,
            name: _name,
            motto: _motto,
            founder: msg.sender,
            memberCount: 1,
            totalMemories: 0,
            createdAt: block.timestamp,
            isActive: true
        });
        familyMemberList[familyId].push(msg.sender);
        memberFamily[msg.sender] = familyId;
        familyMembers[msg.sender] = FamilyMember({
            memberAddress: msg.sender,
            name: _name,
            relationship: "founder",
            bio: "",
            ipfsAvatarCID: "",
            joinedAt: block.timestamp,
            memoryCount: 0,
            isActive: true
        });
        _grantRole(FAMILY_HEAD_ROLE, msg.sender);
        _grantRole(MEMBER_ROLE, msg.sender);
        emit FamilyCreated(familyId, _name, msg.sender);
        return familyId;
    }

    function addMember(uint256 _familyId, address _member, string memory _name, string memory _relationship) external onlyRole(FAMILY_HEAD_ROLE) {
        require(families[_familyId].isActive, "Family not active");
        require(memberFamily[_member] == 0, "Already in a family");
        familyMemberList[_familyId].push(_member);
        families[_familyId].memberCount++;
        memberFamily[_member] = _familyId;
        familyMembers[_member] = FamilyMember({
            memberAddress: _member,
            name: _name,
            relationship: _relationship,
            bio: "",
            ipfsAvatarCID: "",
            joinedAt: block.timestamp,
            memoryCount: 0,
            isActive: true
        });
        _grantRole(MEMBER_ROLE, _member);
        emit MemberAdded(_familyId, _member, _relationship);
    }

    function addMemory(
        uint256 _familyId,
        string memory _title,
        string memory _description,
        MemoryType _mType,
        string memory _ipfsCID,
        string memory _thumbnailCID,
        uint256 _capturedAt,
        string[] memory _tags,
        AccessLevel _accessLevel,
        bool _isEncrypted
    ) external payable nonReentrant {
        require(memberFamily[msg.sender] == _familyId, "Not a family member");
        require(msg.value >= STORAGE_FEE, "Insufficient storage fee");
        uint256 memoryId = _memoryCounter++;
        memories[memoryId] = Memory({
            memoryId: memoryId,
            title: _title,
            description: _description,
            mType: _mType,
            ipfsCID: _ipfsCID,
            thumbnailCID: _thumbnailCID,
            createdAt: block.timestamp,
            capturedAt: _capturedAt,
            creator: msg.sender,
            tags: _tags,
            accessLevel: _accessLevel,
            viewCount: 0,
            isEncrypted: _isEncrypted
        });
        familyMemories[_familyId].push(memoryId);
        families[_familyId].totalMemories++;
        familyMembers[msg.sender].memoryCount++;
        if (_accessLevel == AccessLevel.FAMILY_ONLY) {
            for (uint256 i = 0; i < familyMemberList[_familyId].length; i++) {
                memoryAccess[memoryId][familyMemberList[_familyId][i]] = true;
            }
        } else if (_accessLevel == AccessLevel.PUBLIC) {
            memoryAccess[memoryId][address(0)] = true;
        } else {
            memoryAccess[memoryId][msg.sender] = true;
        }
        emit MemoryAdded(memoryId, _familyId, msg.sender, _title);
    }

    function viewMemory(uint256 _memoryId) external returns (string memory) {
        Memory storage memoryItem = memories[_memoryId];
        require(memoryAccess[_memoryId][msg.sender] || memoryAccess[_memoryId][address(0)], "Access denied");
        memoryItem.viewCount++;
        emit MemoryAccessed(_memoryId, msg.sender);
        return memoryItem.ipfsCID;
    }

    function grantAccess(uint256 _memoryId, address _viewer) external {
        require(memories[_memoryId].creator == msg.sender, "Not the creator");
        memoryAccess[_memoryId][_viewer] = true;
    }

    function getFamilyMemories(uint256 _familyId) external view returns (uint256[] memory) {
        return familyMemories[_familyId];
    }

    function getMemory(uint256 _memoryId) external view returns (Memory memory) {
        return memories[_memoryId];
    }
}

第二幕:家族记忆的链上永续

第一场:从"胶片"到"链上"——记忆存储的进化

小津安二郎的《东京物语》是用胶片拍摄的。胶片是"物理"的存储介质——它需要恒温恒湿的存储环境、需要防潮防霉、需要定期检查。2026年,数字存储也是"物理"的——它需要硬盘、服务器、数据中心、电力。

但区块链技术提供了一种"逻辑"的存储方式——数据不是存储在"物理"介质上,而是存储在"分布式网络"的"逻辑"空间中。只要互联网存在,数据就存在。

第二场:IPFS与Filecoin——去中心化存储

IPFS(InterPlanetary File System)是一个点对点的分布式文件系统,设计目标是"永久网络"(Permanent Web)。在IPFS中,每个文件都有一个唯一的"内容标识符"(CID),基于文件内容的哈希值。当你"访问"一个文件时,IPFS网络从最近的节点获取文件——如果某个节点下线,其他节点仍然可以提供文件。

Filecoin在IPFS的基础上增加了"存储市场"——用户支付FIL代币来存储文件,矿工通过提供存储空间获得FIL。这种经济激励确保了存储的"持久性"。

第三场:Arweave——永久存储

Arweave是另一个"永久存储"网络。与Filecoin不同,Arweave采用"永久存储"模型——用户一次性支付费用,文件永久存储在Arweave的"永续网络"上。

Arweave的"经济模型"基于"存储捐赠"(Storage Endowment)——用户支付的费用被投入一个"捐赠基金",基金的收益用于支付矿工的存储成本。理论上,只要基金不被耗尽,文件就永远存在。

# Family Memory Vault - Decentralized Memory Storage
# Stores family memories on IPFS/Filecoin with blockchain timestamps

import hashlib
import json
import time
import os
from typing import List, Dict, Optional
from dataclasses import dataclass
from enum import Enum
from datetime import datetime

class MemoryType(Enum):
    PHOTO = "photo"
    VIDEO = "video"
    AUDIO = "audio"
    DOCUMENT = "document"
    LETTER = "letter"
    DIARY = "diary"
    FAMILY_TREE = "family_tree"
    OTHER = "other"

class AccessLevel(Enum):
    PUBLIC = "public"
    FAMILY_ONLY = "family_only"
    PRIVATE = "private"

@dataclass
class Memory:
    memory_id: str
    title: str
    description: str
    memory_type: MemoryType
    ipfs_cid: str
    thumbnail_cid: str
    created_at: float
    captured_at: float
    creator: str
    tags: List[str]
    access_level: AccessLevel
    is_encrypted: bool
    file_size: int
    file_hash: str

@dataclass
class FamilyMember:
    address: str
    name: str
    relationship: str
    bio: str
    avatar_cid: str
    joined_at: float
    memory_count: int
    is_active: bool

@dataclass
class Family:
    family_id: str
    name: str
    motto: str
    founder: str
    members: List[FamilyMember]
    total_memories: int
    created_at: float
    is_active: bool

class FamilyMemoryVault:
    def __init__(self):
        self.families: Dict[str, Family] = {}
        self.memories: Dict[str, Memory] = {}
        self.family_memories: Dict[str, List[str]] = {}
        self.member_family: Dict[str, str] = {}
        self.access_control: Dict[str, Dict[str, bool]] = {}
        self.family_counter = 0

    def create_family(self, name: str, motto: str, founder: str) -> Family:
        if founder in self.member_family:
            raise ValueError(f"{founder} already in a family")
        family_id = f"family_{self.family_counter}"
        self.family_counter += 1
        member = FamilyMember(address=founder, name=founder, relationship="founder",
                            bio="", avatar_cid="", joined_at=time.time(),
                            memory_count=0, is_active=True)
        family = Family(family_id=family_id, name=name, motto=motto, founder=founder,
                       members=[member], total_memories=0, created_at=time.time(),
                       is_active=True)
        self.families[family_id] = family
        self.family_memories[family_id] = []
        self.member_family[founder] = family_id
        self.access_control[founder] = {}
        print(f"[FAMILY] Created: {name} by {founder}")
        return family

    def add_member(self, family_id: str, member_address: str, name: str, relationship: str):
        if family_id not in self.families:
            raise ValueError(f"Family {family_id} not found")
        if member_address in self.member_family:
            raise ValueError(f"{member_address} already in a family")
        family = self.families[family_id]
        member = FamilyMember(address=member_address, name=name, relationship=relationship,
                            bio="", avatar_cid="", joined_at=time.time(),
                            memory_count=0, is_active=True)
        family.members.append(member)
        self.member_family[member_address] = family_id
        self.access_control[member_address] = {}
        print(f"[MEMBER] Added {name} ({relationship}) to {family.name}")

    def add_memory(self, family_id: str, creator: str, title: str, description: str,
                  memory_type: MemoryType, file_data: bytes, captured_at: float,
                  tags: List[str], access_level: AccessLevel, is_encrypted: bool = False) -> Memory:
        if family_id not in self.families:
            raise ValueError(f"Family {family_id} not found")
        if creator not in self.member_family or self.member_family[creator] != family_id:
            raise ValueError(f"{creator} is not a member of this family")

        # Simulate IPFS upload
        file_hash = hashlib.sha256(file_data).hexdigest()
        ipfs_cid = self._simulate_ipfs_upload(file_data, title)
        thumbnail_cid = self._generate_thumbnail_cid(file_data)

        memory_id = hashlib.sha256(f"{family_id}{title}{time.time()}".encode()).hexdigest()[:16]
        memory = Memory(memory_id=memory_id, title=title, description=description,
                       memory_type=memory_type, ipfs_cid=ipfs_cid,
                       thumbnail_cid=thumbnail_cid, created_at=time.time(),
                       captured_at=captured_at, creator=creator, tags=tags,
                       access_level=access_level, is_encrypted=is_encrypted,
                       file_size=len(file_data), file_hash=file_hash)

        self.memories[memory_id] = memory
        self.family_memories[family_id].append(memory_id)
        self.families[family_id].total_memories += 1

        # Grant access
        if access_level == AccessLevel.FAMILY_ONLY:
            for member in self.families[family_id].members:
                if member.is_active:
                    if memory_id not in self.access_control:
                        self.access_control[memory_id] = {}
                    self.access_control[memory_id][member.address] = True
        elif access_level == AccessLevel.PUBLIC:
            if memory_id not in self.access_control:
                self.access_control[memory_id] = {}
            self.access_control[memory_id]["public"] = True
        else:
            if memory_id not in self.access_control:
                self.access_control[memory_id] = {}
            self.access_control[memory_id][creator] = True

        print(f"[MEMORY] Added: {title} ({memory_type.value}) by {creator}")
        return memory

    def _simulate_ipfs_upload(self, data: bytes, filename: str) -> str:
        # Simulate IPFS upload and return a CID
        hash_input = f"{filename}{time.time()}{len(data)}"
        return f"Qm{hashlib.sha256(hash_input.encode()).hexdigest()[:44]}"

    def _generate_thumbnail_cid(self, data: bytes) -> str:
        hash_input = f"thumb_{time.time()}_{len(data)}"
        return f"Qm{hashlib.sha256(hash_input.encode()).hexdigest()[:44]}"

    def view_memory(self, memory_id: str, viewer: str) -> Optional[Memory]:
        if memory_id not in self.memories:
            raise ValueError(f"Memory {memory_id} not found")
        memory = self.memories[memory_id]
        if memory_id in self.access_control:
            ac = self.access_control[memory_id]
            if ac.get("public", False) or ac.get(viewer, False):
                return memory
        raise PermissionError("Access denied")

    def create_time_capsule(self, family_id: str, creator: str, title: str,
                           unlock_date: float, memories: List[str]) -> Dict:
        # Create a time capsule - a collection of memories that unlocks on a future date
        capsule_id = hashlib.sha256(f"capsule_{family_id}{title}{time.time()}".encode()).hexdigest()[:16]
        capsule = {
            "capsule_id": capsule_id,
            "family_id": family_id,
            "creator": creator,
            "title": title,
            "unlock_date": unlock_date,
            "memories": memories,
            "created_at": time.time(),
            "is_unlocked": time.time() >= unlock_date
        }
        print(f"[CAPSULE] Created: {title} (unlocks {datetime.fromtimestamp(unlock_date)})")
        return capsule

    def get_family_timeline(self, family_id: str) -> List[Dict]:
        # Get a chronological timeline of family memories
        if family_id not in self.family_memories:
            return []
        timeline = []
        for memory_id in self.family_memories[family_id]:
            memory = self.memories[memory_id]
            timeline.append({
                "date": datetime.fromtimestamp(memory.captured_at).isoformat(),
                "title": memory.title,
                "type": memory.memory_type.value,
                "creator": memory.creator,
                "tags": memory.tags
            })
        timeline.sort(key=lambda x: x["date"])
        return timeline

    def get_family_tree(self, family_id: str) -> Dict:
        # Generate a family tree from member relationships
        if family_id not in self.families:
            return {}
        family = self.families[family_id]
        tree = {"family_name": family.name, "motto": family.motto, "members": []}
        for member in family.members:
            tree["members"].append({
                "name": member.name,
                "relationship": member.relationship,
                "memory_count": member.memory_count,
                "joined_at": datetime.fromtimestamp(member.joined_at).isoformat()
            })
        return tree

# Example
vault = FamilyMemoryVault()
family = vault.create_family("The Tanaka Family", "Always Remember", "0xGRANDPA")
vault.add_member(family.family_id, "0xDAD", "Taro Tanaka", "son")
vault.add_member(family.family_id, "0xMOM", "Hanako Tanaka", "daughter-in-law")
vault.add_member(family.family_id, "0xSON", "Kenji Tanaka", "grandson")

# Add memories
with open("family_photo.jpg", "rb") as f:
    photo_data = f.read() if os.path.exists("family_photo.jpg") else b"simulated_photo_data"

memory = vault.add_memory(family.family_id, "0xGRANDPA", "Wedding Day 1950",
                         "Our wedding photo in Tokyo", MemoryType.PHOTO,
                         photo_data, time.time() - 2374099200,
                         ["wedding", "tokyo", "1950"], AccessLevel.FAMILY_ONLY)

# Create time capsule
capsule = vault.create_time_capsule(family.family_id, "0xGRANDPA", "Letters to Future Generations",
                                   time.time() + 10*365*86400, [memory.memory_id])

# Get timeline
timeline = vault.get_family_timeline(family.family_id)
print(f"Timeline: {json.dumps(timeline, indent=2, ensure_ascii=False)}")

# Get family tree
tree = vault.get_family_tree(family.family_id)
print(f"Family tree: {json.dumps(tree, indent=2, ensure_ascii=False)}")

Family memories and blockchain

第三幕:数字遗产的伦理与设计

第一场:从"拥有"到"传承"——数字遗产的伦理

数字遗产不仅仅是"技术问题",更是"伦理问题":

  1. 谁有权访问去世亲人的数字记忆?配偶、子女、父母、兄弟姐妹?
  2. 去世亲人的隐私如何保护?他们可能不希望某些记忆被公开。
  3. 数字记忆的"删除权"——去世亲人是否可以在生前"删除"某些记忆?
  4. 数字记忆的"传承权"——去世亲人是否可以指定"继承人"来管理自己的数字记忆?

第二场:从"私密"到"共享"——记忆的访问控制

区块链技术提供了"精细"的访问控制机制:

  1. 时间锁定:某些记忆只有在"特定时间"之后才能被访问(如"18岁生日")。
  2. 条件解锁:某些记忆只有在"特定条件"满足时才能被访问(如"结婚"、"生子")。
  3. 多签访问:某些记忆需要"多个继承人"的"共同签名"才能访问。
  4. 渐进披露:某些记忆"分期"披露——"每年"披露"一部分"。

第三场:从"东京物语"到"数字物语"

《东京物语》的"核心"是"家庭的变迁"——子女离开父母、父母老去、家庭记忆被遗忘。2026年,区块链技术为"家庭记忆"提供了一个"永续"的"存储"方案——即使"子女"不在身边、"父母"已经老去,家庭记忆"永远"存在于链上。

// Family Memory Vault API
// Decentralized family memory storage with time capsules

const crypto = require('crypto');

class FamilyMemoryVault {
    constructor() {
        this.families = new Map();
        this.memories = new Map();
        this.familyMemories = new Map();
        this.memberFamily = new Map();
        this.accessControl = new Map();
        this.timeCapsules = new Map();
        this.familyCounter = 0;
    }

    createFamily(name, motto, founder) {
        if (this.memberFamily.has(founder)) throw new Error('Already in a family');
        const familyId = `family_${this.familyCounter++}`;
        const family = {
            familyId, name, motto, founder, members: [{
                address: founder, name: founder, relationship: 'founder',
                bio: '', avatarCid: '', joinedAt: Date.now(),
                memoryCount: 0, isActive: true
            }],
            totalMemories: 0, createdAt: Date.now(), isActive: true
        };
        this.families.set(familyId, family);
        this.familyMemories.set(familyId, []);
        this.memberFamily.set(founder, familyId);
        console.log(`[FAMILY] Created: ${name} by ${founder}`);
        return family;
    }

    addMember(familyId, memberAddress, name, relationship) {
        const family = this.families.get(familyId);
        if (!family) throw new Error('Family not found');
        if (this.memberFamily.has(memberAddress)) throw new Error('Already in a family');
        family.members.push({
            address: memberAddress, name, relationship,
            bio: '', avatarCid: '', joinedAt: Date.now(),
            memoryCount: 0, isActive: true
        });
        this.memberFamily.set(memberAddress, familyId);
        console.log(`[MEMBER] Added ${name} (${relationship})`);
    }

    addMemory(familyId, creator, title, description, memoryType, fileData, capturedAt, tags, accessLevel, isEncrypted = false) {
        const family = this.families.get(familyId);
        if (!family) throw new Error('Family not found');
        if (this.memberFamily.get(creator) !== familyId) throw new Error('Not a member');

        const fileHash = crypto.createHash('sha256').update(fileData).digest('hex');
        const ipfsCid = `Qm${crypto.createHash('sha256').update(`${title}${Date.now()}${fileData.length}`).digest('hex').substring(0, 44)}`;
        const memoryId = crypto.createHash('sha256').update(`${familyId}${title}${Date.now()}`).digest('hex').substring(0, 16);

        const memory = {
            memoryId, title, description, memoryType, ipfsCid,
            thumbnailCid: `Qm${crypto.createHash('sha256').update(`thumb_${Date.now()}`).digest('hex').substring(0, 44)}`,
            createdAt: Date.now(), capturedAt, creator, tags, accessLevel,
            isEncrypted, fileSize: fileData.length, fileHash
        };

        this.memories.set(memoryId, memory);
        this.familyMemories.get(familyId).push(memoryId);
        family.totalMemories++;

        // Set access control
        const ac = {};
        if (accessLevel === 'family_only') {
            family.members.forEach(m => { if (m.isActive) ac[m.address] = true; });
        } else if (accessLevel === 'public') {
            ac['public'] = true;
        } else {
            ac[creator] = true;
        }
        this.accessControl.set(memoryId, ac);

        console.log(`[MEMORY] Added: ${title} (${memoryType})`);
        return memory;
    }

    viewMemory(memoryId, viewer) {
        const memory = this.memories.get(memoryId);
        if (!memory) throw new Error('Memory not found');
        const ac = this.accessControl.get(memoryId) || {};
        if (ac['public'] || ac[viewer]) return memory;
        throw new Error('Access denied');
    }

    createTimeCapsule(familyId, creator, title, unlockDate, memoryIds) {
        const capsuleId = crypto.createHash('sha256').update(`capsule_${familyId}${title}${Date.now()}`).digest('hex').substring(0, 16);
        const capsule = {
            capsuleId, familyId, creator, title, unlockDate,
            memoryIds, createdAt: Date.now(), isUnlocked: Date.now() >= unlockDate
        };
        this.timeCapsules.set(capsuleId, capsule);
        console.log(`[CAPSULE] Created: ${title} (unlocks ${new Date(unlockDate).toISOString()})`);
        return capsule;
    }

    getFamilyTimeline(familyId) {
        const memoryIds = this.familyMemories.get(familyId) || [];
        return memoryIds.map(id => {
            const m = this.memories.get(id);
            return { date: new Date(m.capturedAt).toISOString(), title: m.title, type: m.memoryType, creator: m.creator, tags: m.tags };
        }).sort((a, b) => a.date.localeCompare(b.date));
    }

    getFamilyTree(familyId) {
        const family = this.families.get(familyId);
        if (!family) return null;
        return {
            familyName: family.name, motto: family.motto,
            members: family.members.map(m => ({
                name: m.name, relationship: m.relationship, memoryCount: m.memoryCount
            }))
        };
    }
}

// Example
const vault = new FamilyMemoryVault();
const family = vault.createFamily('The Tanaka Family', 'Always Remember', '0xGRANDPA');
vault.addMember(family.familyId, '0xDAD', 'Taro Tanaka', 'son');
vault.addMember(family.familyId, '0xMOM', 'Hanako Tanaka', 'daughter-in-law');

const memory = vault.addMemory(family.familyId, '0xGRANDPA', 'Wedding Day 1950',
    'Wedding photo in Tokyo', 'photo', Buffer.from('simulated_photo'),
    Date.now() - 2374099200000, ['wedding', 'tokyo', '1950'], 'family_only');

vault.createTimeCapsule(family.familyId, '0xGRANDPA', 'Letters to Future',
    Date.now() + 10*365*86400000, [memory.memoryId]);

console.log('Timeline:', vault.getFamilyTimeline(family.familyId));
console.log('Family tree:', vault.getFamilyTree(family.familyId));

Digital legacy and family

第四场:结语——从"寂寞"到"永恒"

《东京物语》的"寂寞"在于"记忆的消逝"——父母去世后,子女对父母的记忆逐渐模糊、褪色、最终消失。但区块链技术提供了一种"永恒"的可能性:家族记忆被存储在去中心化的网络中,永远不会被删除、永远不会被篡改、永远不会被遗忘。即使百年之后,你的曾孙也可以看到你今天的照片、听到你今天的声音、读到你今天写的日记。

在这个万物皆可Token化的时代,技术的迭代往往比镜头切换更快。作为北京城市学院2021级广播电视编导的毕业生,我始终在影像与区块链的交汇处寻找共鸣。感谢阅读,我是王森涛,让我们在视听与去中心化的世界里,继续探索。


评论